1、实例化的方式
// Vue2.0 new Vue({ el: "#app", router, store, render: h => h(App) })
// Vue3.x <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- <script src="../../packages/vue/dist/vue.global.js"></script> --> <script src="../vue-next/packages/vue/dist/vue.global.js"></script> </head> <body> <div id="app"></div> <script> const { createApp, reactive, computed, } = Vue const MyComponent = { template: ` <button @click="click"> {{ state.message }} </button> `, setup() { const state = reactive({ message: 'Hello Vue 3!!' }) function click() { state.message = state.message.split('').reverse().join('') } return { state, click } } } createApp(MyComponent).mount('#app') </script> </body> </html>
2、Composition API
这个是变化最大的地方
在Vue2.x中是在data中写数据,在methods中写方法,通过this调用
在Vue3.x中,所有的逻辑代码都是在setup方法中实现,包括data,watch,computed,methods,hooks,不再有this
Vue3.x中的setup方法在组件生命周期内只执行一次,不会重复执行
(1)、reactive其实就是Vue3.0中的响应式
如以下所写
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- <script src="../../packages/vue/dist/vue.global.js"></script> --> <script src="../vue-next/packages/vue/dist/vue.global.js"></script> </head> <body> <div id="app"></div> <script> const { createApp, reactive, computed, } = Vue const MyComponent = { template: ` <button @click="click"> {{ state.message }} </button> `, setup() { // -------reactive响应式----------- const state = reactive({ message: 'Hello Vue 3!!' }) function click() { state.message = state.message.split('').reverse().join('') } return { state, click } } } createApp(MyComponent).mount('#app') </script> </body> </html>
在上面那段的click里面添加
(2) ref和toRefs
其中,ref可以用来初始化一个数,并给这个数初始值,如果你学过React,你就会发现,它其实和useState有些类似
用toRefs展开保证了state中的数据不失去响应式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- <script src="../../packages/vue/dist/vue.global.js"></script> --> <script src="../../vue-next/packages/vue/dist/vue.global.js"></script> </head> <body> <div id="app"></div> <script> const { createApp, reactive, computed, ref, toRefs } = Vue const MyComponent = { template: ` <div><button @click="addCount">点击增加, 数量{{count}} <span>{{count}}</span> </button></div> <div><button @click="addNum">点击减少</button> <span>{{num}}</span></div> `, setup() { // reactive响应式 const state = reactive({ count: 0 }) // ref的使用 const num = ref(0) function addCount() { state.count++ } function addNum() { num.value++ } return { ...toRefs(state), num, addNum, addCount } } } createApp(MyComponent).mount('#app') </script> </body> </html>
(3)、computed
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- <script src="../../packages/vue/dist/vue.global.js"></script> --> <script src="../../vue-next/packages/vue/dist/vue.global.js"></script> </head> <body> <div id="app"></div> <script> const { createApp, reactive, computed, ref, toRefs, } = Vue const MyComponent = { template: ` <div><button @click="addCount">点击增加, 数量{{count}} <span>{{count}}</span> </button></div> <div><button @click="addNum">点击减少</button> <span>{{num}}</span></div> `, setup() { // reactive响应式 const state = reactive({ count: 0, // ------ double: computed(() => { return state.count * 2 }) }) // ref的使用 const num = ref(2) function addCount() { state.count++ } function addNum() { num.value++ } // ---only getter const totalCount = computed(() => { state.count + 2 }) // getter & setter const doubleCount = computed({ get() { return state.count * 2 }, set (newVal) { state.count = newVal / 2 } }) return { ...toRefs(state), // ...state, num, addNum, addCount, totalCount, // doubleCount } } } createApp(MyComponent).mount('#app') </script> </body> </html>
(4)、watch & watchEffect
在Vue2.x中用watch来监听属性
在Vue3.x中用watch支持监听单个属性,也支持监听多个属性
在Vue3.x中watchEffect方法会返回一个方法,用于停止监听
watch跟watchEffect不同的地方在于,watchEffect注册后会立即调用,而watch默认不会,除非
显示指定immediate=true,而且watchEffect可以停止监听
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- <script src="../../packages/vue/dist/vue.global.js"></script> --> <script src="../../vue-next/packages/vue/dist/vue.global.js"></script> </head> <body> <div id="app"></div> <script> const { createApp, reactive, computed, ref, toRefs, watch, watchEffect } = Vue const MyComponent = { template: ` <div><button @click="addCount">点击增加, 数量{{count}} <span>{{count}}</span> </button></div> <div><button @click="addNum">点击减少</button> <span>{{num}}</span></div> <div>333{{totalCount}}</div> <input type="text" v-model="totalCount" /> `, setup() { // reactive响应式 const state = reactive({ count: 0, // ------ double: computed(() => { return state.count * 2 }), midObj: { innerObj: { size: 0 } } }) // ref的使用 const num = ref(2) function addCount() { state.count++ } function addNum() { num.value++ } // ---only getter const totalCount = computed(() => { return state.count + 2 }) // 监听单个属性 watch(() => totalCount.value,(newVal, oldVal) => { console.log(`count + num = ${newVal}`) }) // 监听多个属性 watch([num, () => totalCount.value], ([numVal, totalVal],[oldNumVal, OldTotalVal]) => { console.log(`num is ${numVal}, count + num = ${totalVal}`) }) // 副作用,会立即执行 let callTimes = 0 const stopEffect = watchEffect(() => { console.log('watchEffect is called!') const div = document.createElement('div') div.textContent = `totalCount is ${totalCount.value}` document.body.appendChild(div) // 调用5次后,取消fetch监听 callTimes++ if(callTimes >= 5) stopEffect() }) return { ...toRefs(state), num, addNum, addCount, totalCount, } } } createApp(MyComponent).mount('#app') </script> </body> </html>
运行上图的代码且点击按钮五次后,页面的效果如下:
3、生命周期钩子
在Vue2.x中生命周期钩子与data,methods同级
在Vue3.x中,需要先导入钩子,并且在setup方法中注册钩子回调,并且钩子命名也跟React保持一样了
Vue3.x中移除了Vue2.x中的beforeCreate和created钩子,通过setup代替,如下图:
与React Hooks相比:
基于函数的组合式 API 提供了与 React Hooks 同等级别的逻辑组合能力,
但是它们还是有很大不同:组合式 API 的setup
() 函数只会被调用一次,这意味着使用 Vue 组合式 API 的代码会是:
不会在每次渲染时重复执行,以降低垃圾回收的压力;
不存在内联处理函数导致子组件永远更新的问题,也不需要 useCallback;
不存在忘记记录依赖的问题,也不需要“useEffect”和“useMemo”并传入依赖数组以捕获过时的变量。Vue 的自动依赖跟踪可以确保侦听器和计算值总是准确无误。
我们感谢 React Hooks 的创造性,它也是本提案的主要灵感来源,然而上面提到的一些问题存在于其设计之中,且我们发现 Vue 的响应式模型恰好为解决这些问题提供了一种思路。
新增的生命周期钩子:
onRenderTracked
onRenderTriggered
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!-- <script src="../../packages/vue/dist/vue.global.js"></script>--> <script src="../../vue-next/packages/vue/dist/vue.global.js"></script> </head> <body> <div id="app"></div> <script> const { createApp, reactive, ref, toRefs, watch, watchEffect, computed, // 生命周期钩子 onBeforeMount, onMounted, } = Vue const MyComponent = { template: ` <div><button @click="addCount">点击增加, 数量{{count}} <span>{{count}}</span> </button></div> <div><button @click="addNum">点击减少</button> <span>{{num}}</span></div> <div>333{{totalCount}}</div> <input type="text" v-model="totalCount" /> `, setup() { // 生命周期钩子 onBeforeMount(() => { console.log('component is onBeforeMount') }) onMounted(() => { console.log('component is onMounted') }) // reactive响应式 const state = reactive({ count: 0, // ------ double: computed(() => { return state.count * 2 }), midObj: { innerObj: { size: 0 } } }) // ref的使用 const num = ref(2) function addCount() { state.count++ } function addNum() { num.value++ } // ---only getter const totalCount = computed(() => { return state.count + 2 }) // 监听单个属性 watch(() => totalCount.value, (newVal, oldVal) => { console.log(`count + num = ${newVal}`) }) // 监听多个属性 watch([num, () => totalCount.value], ([numVal, totalVal], [oldNumVal, OldTotalVal]) => { console.log(`num is ${numVal}, count + num = ${totalVal}`) }) // 副作用,会立即执行 let callTimes = 0 const stopEffect = watchEffect(() => { console.log('watchEffect is called!') const div = document.createElement('div') div.textContent = `totalCount is ${totalCount.value}` document.body.appendChild(div) // 调用5次后,取消fetch监听 callTimes++ if (callTimes >= 5) stopEffect() }) return { ...toRefs(state), num, addNum, addCount, totalCount, } } } createApp(MyComponent).mount('#app') </script> </body> </html>
4、Fragment
Vue2.x 的vue template只允许有一个根节点
Vue3.x的vue template支持多个节点
5、Teleport
teleport 参照React中的portal,可以将元素渲染在父节点以外的其他地方,
6、Suspense
通常在发生异步操作或者在异步的组件中使用
后面还会继续补充添加代码
参考:https://juejin.cn/post/6867123074148335624#heading-9