Vue3 的发布已经差不多快一年了,笔者也是在中途跟了波热潮,学习了一下 Vue3 的新特性,但一直没有用于工作开发。好在这家公司比较鼓励新技术的使用
,笔者也是在不久前将 Vue3 投入到工作中,发现还是很丝滑的 😎 在此记录一下笔者的所学所用,持续更新吧...
Vue3 与 Vue2
Vue2 结构如下:
components: {},
mixins: {},
props: {},
data() {
return {};
},
computed: {},
watch: {},
created: {},
mounted: {},
methods: {},
熟悉Vue2的读者应该知道,我们一般会在data中定义数据,在methods中声明方法,通过this调用需要的数据和方法。
想必大家和笔者一样也感受到了,当.vue文件中功能复杂、代码过长时,我们需要在template、data、methods之间来回切换,甚是烦躁 😤
当然,还不止于此!不知大家是否在工作中用过 mixins。不可否认,mixins有它的优点和好处,但不足也很明显:
- 命名易冲突
- 未知的数据来源,调试起来很酸爽 😵
......
大概是基于以上的问题,Vue3 诞生了 👏 推出了 Composition API
Vue3 诞生
Vue3 推出的Composition API,不仅可以把零散的逻辑组合在一起,还能将独立的功能逻辑拆分成单独的文件。下面,我就来隆重的介绍它
setup
这是 Vue3 新增的一个特性,是作为Composition API的入口。结构如下:
export default {
setup() {},
};
setup执行的时机,网上说法不一。不过通过笔者的测试发现,setup执行的时机在beforeCreate生命周期之前,读者也可通过下方代码进行自测:🤔
setup(props, context) {
console.log('setup');
},
beforeCreate() {
console.log('beforeCreate');
},
created() {
console.log('created');
},
setup可以接收两个参数props和context,如上方代码。我们简单来说说这两个属性:
props:父子组件之间通过prop所传的值。直接上代码:
// 这是接收到的props
props: {
num: {
type: Number,
default: 0,
},
obj: {
type: Object,
default: () => {},
},
},
那么,通过setup中的props参数就可以拿到上面传入的num和obj属性,从而进行相关的逻辑操作
tips:props不能使用 ES6 解构,这样解构出的数据会失去响应式。如果我们既想要解构,又想要其保持响应式,怎么办?别怕,Vue3 提出
了toRefs函数,我们会在后面学习它
context:可替代Vue2中的this
我们在 Vue2 中,会频繁使用到 this。但是,在 Vue3 中,不能使用 this。所以,context 中提供了最常用的几个属性:emit、slot,使用如下:
setup(props, {emit}) {
emit('alert', type);
},
ref、reactive、toRefs
在 Vue2 中,我们通常把数据定义在data中,而且我们知道,定义在data中的数据通常是响应式的。那么,我们在 Vue3 中该怎么定义数据呢?ref、reactive由此而生。一般来说,ref定义js基础类型的双向绑定;而reactive则定义对象类型的双向绑定。用法如下:
<template>
<p>{{ name }}</p>
<p>{{ data.age }}</p>
<p>{{ data.sex }}</p>
</template>
<script>
import {ref, reactive, toRefs} from "vue";
export default {
setup(props, {root}) {
// ref 通常用于定义基础类型
const name = ref('');
// reactive 通常用于定义对象类型
const data = reactive({
age: 11,
sex: '其它',
phone: 0,
address: '',
});
return {
name,
data
}
}
}
</script>
相信读者们也发现了,当我们用reactive定义了对象类型,同时需要在模版中使用时,都需要data.某个属性,数据量大的时候还是蛮繁琐的。同上文提到的props一样,我们不能直接解构,不然会失去响应式。因此,Vue3 提出了toRefs函数。通过toRefs将reactive定义的对象类型里的属性全部转为ref定义的基础类型。上述代码可做如下修改:
<template>
<p>{{name}}</p>
<p>{{age}}</p>
<p>{{sex}}</p>
</template>
<script>
import {ref, reactive, toRefs} from "vue";
export default {
setup(props, {root}) {
// ref 通常用于定义基础类型
const name = ref('');
// reactive 通常用于定义对象类型
const data = reactive({
age: 11,
sex: '其它',
phone: 0,
address: '',
});
return {
name,
...toRefs(data)
}
}
}
</script>
computed
直接上代码,感受一下 Vue3 中的computed
<template>
<p>{{double}}</p>
</template>
<script>
import {ref, computed} from "vue";
export default {
setup(props, {root}) {
const num = ref(12);
const double = computed(() => {
return num.value * 2;
});
return {
double,
}
}
}
</script>
watch
- 监听
ref定义的数据
<script>
import {ref, watch} from "vue";
export default {
setup(props, {root}) {
const num = ref(12);
watch(
num,
(newValue, oldValue) => {
console.log(newValue, oldValue);
}
);
}
}
</script>
- 监听
reactive定义的数据
<script>
import {reactive, watch} from "vue";
export default {
setup(props, {root}) {
const data = reactive({
age: 100,
address: 'test'
});
watch(
() => data.age,
(newValue, oldValue) => {
console.log(newValue, oldValue);
}
);
}
}
</script>
Vue3 中依旧保留了deep、immediate关键字,如下代码
<script>
import {reactive, watch} from "vue";
export default {
setup(props, {root}) {
const data = reactive({
age: 100,
address: 'test'
});
watch(
() => data.age,
(newValue, oldValue) => {
console.log(newValue, oldValue);
},
{
deep: true,
immediate: true
}
);
}
}
</script>
生命周期
Vue2和Vue3的生命周期还是有点区别的,直接将官网的说明拿过来 🤲
后续
Vue3中的特性就先介绍到这边。除了上述介绍的特性外,Vue3中还有很多的新特性,如watchEffect、自定义Hooks、Teleport等。由于笔者在工作中未频繁使用到这些特性,在此就不记录了,等之后使用到了或是学习了在回来更新 🥱