Vue2.x与Vue3详细对比
- 生命周期对比
使用setup代替之前的beforeCreate和created。
为啥使用setup代替之前的beforeCreate和created?
- Diff算法的提升
vue2中当数据发生变化,会新生成一个DOM树,并和之前的DOM树比较,找到不同的节点然后才更新。对每个节点都会比较,消耗时间。
vue3改进情况:
在创建虚拟DOM树时,会根据DOM中的内容会不会发生变化,添加一个静态标记。在与上次虚拟节点对比时,只会对比带有静态标记的节点。
- 打包体积的变化
vue3中实现了按需编译
- mixins更改 vue2中使用mixins实现相同逻辑的抽离,每个组件只需要引入mixins,就能实现复用 vue3中使用自定义的hook,封装可复用的功能函数
createApp
- vue2使用new的方式创建vue实例,组件中使用选项组合代码逻辑
- vue3使用createApp创建应用实例,组件中使用组合式API和选项组合代码。
props、emits
- vue2中用props、$emit进行父子组件间的通信
- vue3中用props、emits进行父子组件间的通信
setup函数
setup函数是一个新的组件选项。作为在组件内使用composition Api的入口点。
创建组件实例,然后初始化props,紧接着就调用setup函数。从生命周期看,会在beforeCreate之间执行。data、methods、watch等全部都用对应的新增的api写在setup()函数中。
<script setup>
setup(props,context) {
context.attrs //非响应式对象,等同于$attrs
context.slots // 非响应式对象,等同于$slots
context.emit // 触发事件,方法等同于$emit
context.expose // 暴露公共property
return {}
}
</script>
- props:用来接受props数据,props是响应式的,当传入新的props时,将被更新
- context:用来定义上下文,上下文对象中包含了一些有用的属性。
- this:在setup()函数中无法访问,是undefined
- return{}:返回响应式数据,值必须是一个对象,模板中需要使用的函数
组件自动注册,无需再通过components注册
<template>
<Child/>
</template>
<script setup>
import Child from './Child.vue'
</script>
CompositionAPI 创建响应式对象的方式
组合式API的好处: 逻辑可以整块使用,代码结构清晰
- vue2中实现响应式主要是使用Object.defineProperty()函数,通过getter方法进行依赖搜集,数据变化时,触发setter进行更新。
- vue3 使用以下四个方法创建响应式对象
ref
- 函数参数可以是基本数据类型,也可以接受对象类型
- 如果参数是对象类型时,底层的本质还是reactive,系统会自动根据给ref传入的值转换成:
ref(1)->reactive({value:1})
- 在template中访问,系统会自动添加.value,在js中需要手动添加.value
- ref接受的参数是基本类型,其响应式原理是依赖于Object.defineProperty()中的get()和set()方法
- 如果参数是引用类型,底层ref会借助reactive的proxy定义响应式reactive({value:'xxxx'})
<template>
<div>
<span>{{count}}</span>
</div>
</template>
<script setup>
import {ref} from 'vue'
export default {
setup(){
const count = ref(1)
setTimeout(()=>{
count.value = 2 // 通过value改变值
},3000)
return {count}
}
}
</script>
reactive
- reactive适合定义复杂的数据类型(json/arr)
- 参数必须是对象或者数组,如果是让对象的某个元素实现响应式时,需要使用toRefs
<template>
<div>
<p>{{state.name}}</p>
<p>{{state.address.city}}</p>
</div>
</template>
<script setup>
import {reactive} from 'vue'
export default {
setup(){
const state = reactive ({
name:'nihao',
address:{
city:'shenzhen'
}
})
setTimeout(()=>{
state.name = 'beijing',// 模板中的值会改变
state.address.city = 'henan'//模板中的值会改变
},2000)
return {state} // 不能使用...state方式结构,会丢失响应式
}
}
</script>
ref与reactive的区别
- ref定义基本数据类型。reactive定义复杂的数据类型,不能直接结构,需要使用toRefs()转成普通对象后解构。
toRef
- 针对一个响应式对象(reactive封装)的prop(属性)创建一个ref,且保持响应式
- 两者保持引用关系
<template>
<div>
<span>姓名:{{state.name}}</span>
<span>姓名2:{{nameRef}}</span>
</div>
</template>
<script setup>
import {reactive,toRef} form 'vue'
setup(){
const state = reactive({
name:'nihao'
})
//通过toRef创建一个ref响应式
const nameRef = toRef(state,'name')
setTimeout(()=>{
nameRef.value = 'beijing'
},2000)
return {state,nameRef}
}
</script>
toRefs
用于破坏响应式对象并将其所有属性转换为ref的实用方法
- 将响应式对象(reactive)转成普通对象
- 对象的每个属性(prop)都是对应的ref
- 两者保持引用关系
<template>
<div>
<span>姓名:{{name}}</span>
<span>姓名2:{{nameRef}}</span>
</div>
</template>
<script setup>
import {reactive,toRefs} form 'vue'
setup(){
const state = reactive({
name:'nihao'
})
//通过toRefs创建一个响应式对象属性的Ref
const toRefsValue = toRefs(state)
setTimeout(()=>{
toRefsValue.name.value = 'beijing'
},2000)
return {state,...toRefsValue}
}
</script>
ref、toRef、toRefs三者的区别
- 视图层面:ref数据进行修改时,视图会发生变化,toRef数据和toRefs数据修改时,视图不会发生变化
- 数据层面:ref数据修改时,原数据不会发生变化,toRef数据和toRefs数据修改时,原数据会发生改变
- 参数层面:toRef需要传递2个参数,第一个参数为需要转换的对象,第二个参数为该对象中的属性名,toRefs只需要传递一个参数,为需要转换的对象即可。
teleport 传送门
需求:通过点击一个按钮,实现模态框的效果。
Suspense
发送异步请求时,有时需要判断异步请求的状态,展示不同的界面。
store使用
vue2中 ,可以直接通过this.$store进行获取,vue3中,没有this概念 vue3的使用方式
import {useStore} from 'vuex'
import {defineComponent,ref,computed} from 'vue'
export default defineComponent ({
setup(){
const counter = ref(0)
const store = useStore()
const storeData = computed(()=>store) // 配合computed,获取store的值 return{counter,storeData}
}
})
Tree-shaking
- vue2版本中,很多函数是挂载在全局vue对象上,有的可能用不上,但打包时会打包进bundle中。
- vue3引入Tree-shaking,带来的bundle体积更小
- 以前在全局配置的组件(Vue.component)、指令(Vue.directive)、混入(Vue.mixin)和插件(Vue.use)等变为直接挂载在实例上的方法,通过创建的实例来调用,好处是一个应用可以有多个Vue实例,不同实例之间的配置也不会相互影响。
v-if和v-for优先级
- vue2中,v-for的优先级比v-if的高
- vue2中,v-if比v-for的优先级高
Provide/Inject
Provide/Inject可以在祖(父)组件和子(孙)组件间实现传值。
祖(父)组件中使用一个provide函数提供数据,而子(孙)组件使用inject函数来获取数据
- vue2中provide/inject不拥有响应性的 跨级组件传递数据,父组件用provide选项提供数据,子组件用inject选项接收数据 provide/inject API可以实现状态共享和依赖注入功能,可以代替vuex
- provide有两个参数:第一个参数表示字符串类型的key,第二个参数是value,可以是对象,也可以是普通数据类型
import {provide} from 'vue'
setup(){
// 第一种写法
provide('name','shenzhen')
// 第二种写法
provide('state',{
name:'nihao',
age:12
})
}
- inject有两个参数:第一个参数表示需要获取的key,第二个参数为key未取到值时填充的默认值
// setup()函数中调用inject函数获取数据
import {inject} from 'vue'
setup(){
// 第一种写法
const username = inject('name','henan')
// 第二种
const userState = inject('state')
}
- 为provide添加响应性 provide提供的数据发生变化时,inject使用数据的组件需要进行刷新界面。
// 修改后的provide
setup(){
provide('name',ref('shenzhen'))
provide ('state',reactive({
name:'test',
age:12
}))
}