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
等。由于笔者在工作中未频繁使用到这些特性,在此就不记录了,等之后使用到了或是学习了在回来更新 🥱