Vue3写一个倒计时组件

vue3 beta版本发布已有一段时间了,文档也大概看了一下,不过对于学一门技术,最好的方法还是实战,于是找了一个比较简单的组件用vue3来实现,参考的是vant的countdown组件。

Vue Composition API文档:

如果对vue3语法还不熟悉的,可以先看一下语法

目前文档还是英文的,这里简单翻译下几个比较核心的东西:

setup

setup函数是一个新的组件option选项,作为在组件内使用Composition API的入口。

1. 调用时机

setup会在组件实例创建并且初始props解析后立即调用。对于生命周期这一层面,会在beforeCreate钩子之前调用。

2. 配合template使用

如果setup返回一个对象,那么对象的属性会被合并到当前组件的render上下文。

从setup中返回的refs在template中获取值时会被自动unwrapped(猜测可能是get值时用了unref。unref也是一个新的api,val = isRef(val) ? val.value : val的语法糖),因此在模板中取值时无需加上.value。

3. 配合render函数使用

setup里不仅可以返回一个对象,也可以直接返回一个render函数。不过要注意的是,跟template会自己unwrapped不同,在render中使用refs的值时,需要加上.value。

4. 参数

setup接收两个参数,第一个是用的最多的props,第二是ctx上下文,不过是精简版,只提供了三个属性attrs,slots,emit,这三个都是写组件必不可少的。

  • emit: 同父组件通信用
  • slots: 插槽分发内容
  • attrs: 可以用于封装高阶组件, 配合v-bind进行属性透传

5. this在setup中不可用

在vue2,你可以在每一个生命周期或者方法中通过this获取当前实例,不过在setup方法中是无法获取到this的。但是,可以通过getCurrentInstance获取到当前实例。

reactive

传入一个对象并返回对目标源的响应式代理结果,等同于2版本的Vue.observable()。

ref

类似reactive,但是传入的是基本值,取值时需要加上.vaule去获取,而reactive包裹的对象可以直接像对象那样去获取值。

不过当数据结构是数组或者Map时,即使数组已经被reactive包裹了,如果数组里面的某一项是ref,依然需要通过.value去获取值。

//ref
const count = ref(0)
console.log(count.value); //reactive
const state = reactive({
count
})
console.log(state.count); //reactive with array
const arr = reactive([ref(0),3,5])
// need .value here
console.log(arr[0].value)

computed

接收一个回调函数作为getter,或者传入带有getter和setter对象 。一个computed会返回一个对象,有多个computed时就需要调用多次

const plusOne = computed(() => count.value + 1)
const plusTwo = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
})

toRef, toRefs

toRef可用于为源响应对象上的某个属性创建ref。

export default {
//由于Javascript函数参数是按值传递,所以如果传递的是基本类型,传参可以理解为复制变量值。基本类型复制后俩个变量完全独立,之后任何一方改变都不会影响另一方。如果直接传递props.numner也就是10进去,函数内部跟外部是独立的,函数里面的操作无法影响到外部变量,除非你传递的是一个对象比如整个props,才能保持引用。但是如果你只需要某个属性,传整个进去也是没必要的。此时toRef就显的很有用了。toRef返回的就是一个对象,通过这个对象.value可以获取到值。
setup(props) {
// {number:10}
useSomeFeature(toRef(props, 'number'))
}
}

toRefs可以将响应式对象转换为普通对象,其中结果对象上的每个属性都是指向原始对象中相应属性的引用。可以用于解构的时候防止丢失响应。

生命周期

生命周期大部分都改了名字,写法上也稍有不同。

  1. 需要自己import;
  2. 在setup中调用;
  • beforeCreate -> use setup()
  • created -> use setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

语法就大概介绍这些,具体的内容还是要看看官方文档。下面看一下组件的具体代码

<script>
import { h, reactive, onMounted, onBeforeUnmount, toRef } from "vue";
import { formatTime } from "./utils"; export default {
props: {
time: {
type: Number,
default: 0
},
millisecond: {
type: Boolean,
default: false
},
autoStart: {
type: Boolean,
default: true
}
},
setup(props, { emit }) {
const interval = props.millisecond ? 16 : 1000; let leftTime = toRef(props, "time").value;
let autoStart = toRef(props, "autoStart").value; let ticker = null;
let timeData = reactive(formatTime(leftTime)); const updateTime = (timeData, leftTime) => {
const data = formatTime(leftTime);
Object.keys(timeData).forEach(k => {
timeData[k] = data[k];
});
}; const start = () => {
if (!ticker && leftTime > 0) {
ticker = setInterval(() => {
leftTime -= interval;
if (leftTime <= 0) {
leftTime = 0;
clearInterval(ticker);
emit("finish");
} else {
emit("change", leftTime);
} updateTime(timeData, leftTime);
}, interval);
}
}; const stop = () => {
clearInterval(ticker);
ticker = null;
}; const restart = () => {
clearInterval(ticker);
ticker = null;
leftTime = props.time; emit("change", leftTime);
updateTime(timeData, leftTime); start();
}; onMounted(() => {
autoStart && start();
}); onBeforeUnmount(() => {
stop();
}); return {
timeData,
start,
stop,
restart
};
},
render({ $slots, timeData, millisecond }) {
const time = ["hours", "minutes", "seconds", "millisecond"]
.filter(v => v != "millisecond" || millisecond)
.map(v => timeData[v])
.join(":"); const defaultContent = h(
"span",
{
style: { fontSize: "14px", color: "#333" }
},
time
); return h(
"div",
($slots.default && $slots.default(timeData)) || defaultContent
);
}
};
</script>

主要的变化还是在setup,没有data,也没有methods了,都需在setup里面返回才可以使用。基本上绝大部门的代码都写在setup里面,包括事件,生命周期等, 当然这也很变量的作用域有关。也可以考虑把逻辑抽取出去,不过传参的时候,需要使用toRef或者toRefs,不能传基本值。

高阶组件

主要是用attrs来实现属性的绑定,但是具体是不是这样写,我还不太确定。

<template>
<div>
<p>{{ word }}</p>
<countdown v-bind="attrs"></countdown>
</div>
</template> <script>
import Countdown from "../components/countdown"; export default {
components: {
Countdown
},
props: {
word: {
type: String
}
},
setup(props, { attrs }) {
return {
attrs
};
}
};
</script>

DEMO

<template>
<div class="home">
<p>基本使用</p>
<countdown :time="66000"></countdown> <p>毫秒数</p>
<countdown :time="44444" millisecond></countdown> <p>获取组件实例以及方法</p>
<countdown :time="66000" ref="count" :auto-start="false"></countdown>
<button @click="count.start()">开始</button>
<button @click="count.stop()">关闭</button>
<button @click="count.restart()">重启</button> <p>使用插槽自定义样式</p>
<countdown :time="66000" @change="change">
<template v-slot="timeData">
<span class="block">{{ timeData.hours }}</span>
<span class="colon">:</span>
<span class="block">{{ timeData.minutes }}</span>
<span class="colon">:</span>
<span class="block">{{ timeData.seconds }}</span>
</template>
</countdown> <p>高阶组件</p>
<higher :time="8888" word="测试higher" />
</div>
</template> <script>
import Countdown from "../components/countdown";
import Higher from "../components/higher"; import { ref, onMounted } from "vue";
export default {
name: "Home",
components: {
Countdown,
Higher
},
setup() {
const change = () => {};
const count = ref(null); onMounted(() => {
console.dir(count.value);
});
return {
change,
count
};
}
};
</script>

展示效果

仓库地址

https://github.com/linrunzheng/vue3-learn

Vue3语法快速入门以及写一个倒计时组件的更多相关文章

  1. Objective-C基础语法快速入门

    Objective-C基础语法快速入门 2010-11-04 16:32 折酷吧 zheku8 字号:T | T 假如我们对面向对象的思维已经C语言都很熟悉的话,对于我们学习Objective-C将会 ...

  2. Less 语法快速入门

    Less 语法快速入门 Less 是一门 CSS 预处理语言其可以运行在 Node 或浏览器端. 它将传统的 css 样式结构单一的排版顺序进行了优化,让我们可以通过层级嵌套的方式将 css 类名与H ...

  3. 写一个vue组件

    写一个vue组件 我下面写的是以.vue结尾的单文件组件的写法,是基于webpack构建的项目.如果还不知道怎么用webpack构建一个vue的工程的,可以移步到vue-cli. 一个完整的vue组件 ...

  4. js单行写一个评级组件

    单行写一个评级组件:"★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate); -----------------------------------分隔符- ...

  5. 表单配置项写法,表单写成JSON数组套对象,一行是一个数组单位,一列是一个对象单位,然后再写一个公共组件读取这个配置,循环加载slot,外层载入slot的自定义部分,比如input select等,这种写法就是把组件嵌套改为配置方式

    表单配置项写法,表单写成JSON数组套对象,一行是一个数组单位,一列是一个对象单位,然后再写一个公共组件读取这个配置,循环加载slot,外层载入slot的自定义部分,比如input select等,这 ...

  6. JAVA WEB快速入门之通过一个简单的Spring项目了解Spring的核心(AOP、IOC)

    接上篇<JAVA WEB快速入门之从编写一个JSP WEB网站了解JSP WEB网站的基本结构.调试.部署>,通过一个简单的JSP WEB网站了解了JAVA WEB相关的知识,比如:Ser ...

  7. Scheme语言实例入门--怎样写一个“新型冠状病毒感染风险检测程序”

    小学生都能用的编程语言 2020的春季中小学受疫情影响,一直还没有开学,孩子宅在家说想做一个学校要求的研究项目,我就说你做一个怎么样通过编程来学习数学的小项目吧,用最简单的计算机语言来解决小学数学问题 ...

  8. T4语法快速入门

    1.什么是T4? T4,即4个T开头的英文字母组合:Text Template Transformation Toolkit.T4(Text Template Transformation Toolk ...

  9. 爬虫入门 手写一个Java爬虫

    本文内容 涞源于  罗刚 老师的 书籍 << 自己动手写网络爬虫一书 >> ; 本文将介绍 1: 网络爬虫的是做什么的?  2: 手动写一个简单的网络爬虫; 1: 网络爬虫是做 ...

随机推荐

  1. Windows环境下搭建Cocos2d-x3.2环境并配置android交叉编译环境

    一.软件 1)VS2012(C++11特性在VS2012以上可以使用):传送门: 2)Cocos2d-x官网源码:传送门:http://cocos2d-x.org/download 3)JDK:传送门 ...

  2. BUUOJ [CISCN2019 华北赛区 Day2 Web1]Hack World

    补一下这道题,顺便发篇博客 不知道今年国赛是什么时候,菜鸡还是来刷刷题好了 0X01 考点 SQL注入.盲注.数字型 0X02自己尝试 尝试输入1 赵师傅需要女朋友吗???随便都能有好吧 输入2 ?? ...

  3. MVC-路由解析

    MVC程序入口 Global.asax.cs 执行Application_Start 方法 *默认路由 *静态路由,访问链接只需要域名加路由url固定值就行了 *替换控制器,或方法名, *正则路由 方 ...

  4. Say goodbye

    Since September 28th 2015 Scriptogram officially closed. We considered every option before making th ...

  5. ISWC 2018概览:知识图谱与机器学习

    语义网的愿景活跃且良好,广泛应用于行业 语义网的愿景是「对计算机有意义」的数据网络(正如 Tim Berners Lee.James Hendler 和 Ora Lassila 在<科学美国人& ...

  6. Java中集合的初等案例

    我有五个学生,请把这个学生的信息储存到数组中,并遍历数组,获取得到每一个学生信息. 学生:Strdent 成员变量:name,age 构造方法:无参,带参 成员方法:getXxx()/setXxx() ...

  7. sqli lab 1-4

    less-1 爆库 id=1222' union select 1,group_concat(schema_name),database() from information_schema.schem ...

  8. php 推荐密码加密的方法

    password_hash() 函数 password_hash() 函数用于创建密码的散列(hash) PASSWORD_DEFAULT - 使用 bcrypt 算法 (PHP 5.5.0 默认). ...

  9. Spring5参考指南:基于注解的容器配置

    文章目录 @Required @Autowired @primary @Qualifier 泛型 @Resource @PostConstruct和@PreDestroy Spring的容器配置可以有 ...

  10. CF1324 --- Maximum White Subtree

    CF1324 --- Maximum White Subtree 题干 You are given a tree consisting of \(n\) vertices. A tree is a c ...