Vue3.0 新特性学习(一)
setup
内部也可以调用生命周期钩子,但是 Vue3 并没有提供 beforeCreate
和 created
对应的钩子,由上篇文章可知,setup
是早于这两个钩子执行的,因此 setup
本身就可以胜任这两个钩子的工作,并且官方也是这么说的:
因为 setup
是围绕 beforeCreate
和 created
生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在 setup
函数中编写。
其他的钩子名称有所改变,beforeMount
变成了 onBeforeMount
,其他钩子的命名规则都与这个相同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Vue.createApp({ setup(props) { Vue.onBeforeMount(() => { console.log(1) }) Vue.onMounted(() => { console.log(2) }) }, beforeMount() { console.log(3) }, mounted() { console.log(4) }, }) app.mount('#app')
|
运行结果:

同样的钩子,setup
内部的钩子调用早于外部的钩子。
computed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const app = Vue.createApp({ setup(props) { const a = Vue.ref(1) const b = Vue.computed(() => a.value * 2) const c = Vue.computed({ get: () => a.value * 3, set:val => a.value = val + 3 }) console.log(a.value) // 1 console.log(+ b.value) // 2 console.log(c.value) // 3 c.value = 2 console.log(c.value) // 15 console.log(a.value) // 5 console.log(b.value) // 10 console.log(c.value) // 15 return { a, b, c } }, }) app.mount('#app')
|
computed 用法与之前没什么差别。
watch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| const app = Vue.createApp({ setup(props) { const a = Vue.ref(1) Vue.watch(a, (val, prevVal) => { console.log(`a 被改变了:新值为${val},旧值为${prevVal}`) }) a.value = 2
const b = Vue.reactive({ x: 1, y: 2 }) Vue.watch(() => b.x, (val, prevVal) => { console.log(`b.x 被改变了:新值为${val},旧值为${prevVal}`) }) b.x = 2
const { c, d } = Vue.toRefs(Vue.reactive({ c: 3, d: 4 })) Vue.watch([c, d], (newValArr, preValArr) => { console.log(newValArr, preValArr) }) c.value = 7 d.value = 7 return { a, b } }, }) app.mount('#app')
|
运行结果:

watchEffect
watchEffect
接受一个回调函数,在这个回调函数中用到的任意一个响应式数据更新时,这个回调函数都会被执行,也就是说它可以监听多个响应式数据。它与 watch
很相似,但也有需要注意的地方:
watchEffect
无需指定要监听的属性,它自动会收集依赖,而 watch
必须指定。
watchEffect
因为需要收集依赖。所以它在组件初始化的时候就会运行一遍,而 watch
默认不会运行,除非手动配置 immediate: true
。
watchEffect
无法知道是哪个值被更新,因此获取不到变化的新值与旧值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const app = Vue.createApp({ setup(props, context) { const a = Vue.ref(0) let b = 1 Vue.watchEffect(() => { console.log(`有值更新了!a:${a.value};b:${b}。`) }) setTimeout(() => { b = 5 }, 1000) setTimeout(() => { a.value ++ }, 2000) return { listLoading, toggleLoading } }, }) app.mount('#app')
|
运行结果:

watch
与 watchEffect
都返回了一个 unwatch 方法用于取消侦听
1 2 3 4 5 6 7 8 9 10 11 12
| const app = Vue.createApp({ setup(props, context) { const unWatch = Vue.watch(() => {}) unWatch() const unWatchEffect = Vue.watchEffect(() => {}) unWatchEffect() return {} }, }) app.mount('#app')
|
组合式函数
以前我们需要在组件之间共享代码时,一般使用 mixins
或作用域插槽。但它们都有一些硬伤:
mixins
多了之后变量会十分混乱,在引用文件中根本无法区分哪个变量或方法来自哪个 mixins
。
- 作用域插槽没有变量混乱的问题,因为它的数据只能在模板中访问,但这恰好也是它的缺点。
在 Vue3 中,我们配合组合式 API可以编写组合式函数,可以清楚地知道该变量来自哪个组合式函数。
下面是两个简单的例子:
1 2 3 4 5 6 7 8 9 10
| <div id="app" v-cloak> <div> {{listLoading}} <button @click="toggleLoading">改变状态</button> </div> <div> {{count}} <button @click="addCount">+1</button> </div> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| function useToggleLoading(user) { const listLoading = Vue.ref(false) const toggleLoading = () => { listLoading.value = !listLoading.value } return { listLoading, toggleLoading } }
function useAddCount(user) { const count = Vue.ref(0) const addCount = () => { count.value++ } return { count, addCount } }
const app = Vue.createApp({ setup(props, context) { const { listLoading, toggleLoading } = useToggleLoading() const { count, addCount } = useAddCount() return { listLoading, toggleLoading, count, addCount } }, }) app.mount('#app')
|

Vue2 与 Vue3 的主要区别就写到这里,还有其他很多我觉得用得相对较少的 API 文章中就不多介绍。