| 对比 | vue2 | vue3 |
|---|---|---|
| 脚手架 | 命令式 | 可视化脚手架 |
| 组件通信 | 见下文 | 见下文 |
| 数据监听 | watch, computed | watch, watchEffer, computed |
| 双向绑定 | Object.defineProperty | ProxAPI |
| 生命周期 | ||
| api | 选项式 | 组合式 |
一、双向绑定更新
vue2的双向绑定是利用 ES5 的一个API, Object.defineProperty()对数据进行劫持,结合发布订阅模式来实现
vue3中使用了 ES6 的ProxyAPI对数据代理,通过reactive()函数给每一个对象都包一层 Proxy 监听属性的变化,从而实现对数据的监控
使用 proxy的优势
1. defineProper只能监听某个属性,不能对全对象监听,
可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
2.可以监听数组,不用再去单独的对数组进行异步操作,
通过 Proxy 可以直接拦截所有对象类型数据的操作,完美支持对数组的监听
二、实例化
Vue2.X中new出的实例对象,所有的东西都在这个vue对象上,这样无论用到还是没用到,都会跑一遍,不仅消耗性能,也增加了用户加载时间
vue3.0中可以用ES module imports按需引入,如:keep-alive内置组件、v-model指令,等等,不仅开发起来更加的便捷,减少了内存消耗,同时减少了用户加载时间,优化用户体验
三、 生命周期
| vue2 | vue3 | 描述 |
|---|---|---|
| beforeCreate | setup | 实例创建前 |
| created | setup | 实例创建前 |
| beforeMount | onBeforeMount | DOM挂载前调用 |
| mounted | onMounted | DOM挂载完成调用 |
| beforeUpdate | onBeforeUpdate | 数据更新前调用 |
| updated | onUpdate | 数据更新后调用 |
| beforeDestory | onBeforeUnmount | 组件销毁前调用 |
| destoryed | onUnmounted | 组件销毁完调用 |
四、获取props vue2在script代码块可以直接获取props,vue3通过setup指令传递
vue2: console.log('props', this.xxx)
vue3: setup(props, context){ console.log('props', props) }
五、数据的方法的定义
Vue2使用的是选项API (Options API),Vue3使用的合成型API(Composition API)
vue2:
data() { return {} }, methods: {}
vue3
数据和方法都定义在 setup 中,并统一进行 return{}
六、给父组件传值emit
vue2: this.$emint()
vue3: setup(props, context) { context.emit() }
七、watchEffect
Vue3中除了watch,还引入副作用监听函数watchEffect,它和 React 中的 useEffect 很像,只不过 watchEffect 不需要传入依赖
watchEffect会立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数
computed和watch所依赖的数据必须是响应式的。Vue3引入了 watchEffect,相当于 watch 的依赖源和回调函数合并,当任何你有用到的响应式依赖跟新时,该回调函数就会立刻执行,不同于 watch 的是 watchEffect 的回调函数会被立即执行,既({ immediate: true })
八、组件通信
| 方式 | Vue2 | Vue3 |
|---|---|---|
| 父传子 | props | props |
| 子传父 | $emits | emits |
| 父传子 | $attrs | attrs |
| 子传父 | $listeners | 无(合并到attrs方式) |
| 父传子 | provide | provide |
| 子传父 | inject | inject |
| 子组件访问父组件 | $parent | 无 |
| 父组件访问子组件 | $children | 无 |
| 父组件访问子组件 | $ref | expose&ref |
| 兄弟传值 | EventBus | mitt |
注意
props中数据是单项的,既子组件不可改变父组件传来的值
在组合API中,如果想在子组件中用其他变量接收props的值时,需要使用toRef将props中的属性转为响应式
attrs和insteners
子组件使用 $attrs 可以获得父组件除了 props 专递的属性和特性绑定属性(class 和 style)之外的所有属性
子组件使用 $listeners 可以获得父组件(不含 .native修饰器的)所有v-on事件监听器,在Vue3中的attrs不仅可以获得父组件传来的属性,也可以获得父组件v-on事件监听器
九、路由
vue2和vue3路由常见功能只是在写法上有些区别:
vue3的 beforeRouteEnter 作为路由守卫的示例是因为他在 setup语法糖中是无法使用的;
setup中组件实例已经创建,时能够获得到组件实例的。而 beforeRouteEnter是再进入路由前触发的,此时组件还未创建,所以无法用在setup中的;
如果想在setup语法糖中使用则需要再写一个 script 如下
<script>
export default {
beforeRouteEnter(to, from, next) {
// 在渲染组件的对应路由被 confirm 前调用
next()
}
}
</script>
vue3路由写法
<script>
import { defineComponent } from 'vue'
import { useRoute, useRouter } from 'vue-router'
export default defineComponent({
beforeRouteLeave((to, from, next)=>{
// 离开当前组件 触发
next()
}),
beforeRouteLeave((to, from, next)=>{
// 离开当前组件 触发
next()
}),
setup() {
const router = useRouter()
const route = useRoute()
const toPage = () => {
router.push(xxx)
}
// 获取params
route.params
// 获取query
route.query
return {
toPage
}
}
})
</script>
vue2路由写法
<script>
export default {
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由 confirm 前调用
netx()
},
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由 confirm 前调用
netx()
},
beforeRouteLeave((to, from, next) => {
// 离开当前组件 触发
netx()
}),
beforeRouteLeave((to, from, next) => {
// 离开当前组件 触发
netx()
}),
methods: {
toPage() {
this.$router.push(xxx)
}
},
created() {
// 获取params
this.$route.params
// 获取query
this.$route.query
}
}
</script>
十、总结
vue2和vue3比较还有很多不一样的地方,比如setup语法糖的形式最为便捷且更加符合开发者习惯
其他总结
1.因为改成组合式api所以没有this
2.生命周期没有creat,setup等同于create,卸载改成unmount
3.vue3中v-if的优先级高于v-for
4.根实例的创建从new app变成createApp方法
5.一些全局注册,比如minxin,注册全局组件,use改成了用app实例调用,而不是vue类调用
6.新增了传送门teleport组件
7.template模版可以不包在一个根div里