一、vue3比vue2有什么优势?
- 性能更好
- 体积更小
- 更好的ts支持
- 更好的代码组织
- 更好的逻辑抽离
- 更多新功能
二、vue3生命周期
1. options API生命周期
- beforeDestroy改为beforeUnmount
- destroyed改为unmouted
- 其他沿用vue2的生命周期
beforeCreate(){
console.log('beforeCreate')
},
created(){
console.log('created')
},
beforeMount(){
console.log('beforeMount')
},
mounted(){
console.log('mounted')
},
beforeUpdate(){
console.log('beforeUpdate')
},
updated(){
console.log('updated')
},
beforeUnmount(){
console.log('beforeUnmount')
},
unmounted(){
console.log('unmounted')
},
2. Composition API生命周期
import { onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted } form 'vue';
//等于beforeCreate()与created()
setup(){
console.log('setup');
onBeforeMount(()=>{
console.log('onBeforeMount')
})
onMounted(()=>{
console.log('onMounted')
})
onBeforeUpdate(()=>{
console.log('onBeforeUpdate')
})
onUpdated(()=>{
console.log('onUpdated')
})
onBeforeUnmount(()=>{
console.log('onBeforeOnmount')
}) onBeforeMount(()=>{
console.log('onBeforeMount')
})
onUnmounted(()=>{
console.log('onMounted')
})
},
三、Composition API对比Options API
1)Composition APII:
更好的代码组织 更好的逻辑复用 更好的类型推导
2)如何选择:
不建议共用,会引起混乱 小型项目,业务逻辑简单,用options API 中大型项目,逻辑复杂,用composition API
3)compsition API属于高阶技巧,不是基础必会,是为了解决复杂业务逻辑而设计
四、理解ref toRef 和toRefs
1. ref:
1)生长值类型的响应式数据 2)可用于模板和reactive(不需要用.value) 3)通过.value修改值 4)也能用ref获取dom元素或节点(refName.value.innerHTML,refName.value)
3. toRef:
1)针对一个响应式对象(reactive封装)的prop(属性),创建一个ref,具有响应式 2)两者保持引用关系 3)toRef 如果用于普通对象(非响应式对象),产出的结果不具备响应式 4)
6. toRefs:
1)将响应式对象(reactive封装)转换为普通对象,对象的每个prop都是对应的ref的响应式值 2)两者保持引用关系
五、ref、toRef、toRefs的最佳使用方式
1.toRefs —— 合成函数返回响应式对象
function useFeatureX(){
const state = reactive({
x:1,
y:2
})
//返回时转换为ref
return toRefs(state)
}
setup(){
//可以在不失去响应式的情况下改变结构
const { x, y } = useFeaturex()
return{
x,
y
}
}
2.用reactive做对象的响应式,用ref做值类型响应式 3.setup 中返回toRefs(state),或者toRef(state,'xxx') 4.ref 的变量命名都用xxxRef 5.合成函数返回响应式对象时,使用toRefs
一、为什么需要ref?
1、返回值类型,会丢失响应式
2、如在setup 、computed、合成函数、都有可能返回值类型
3、vue不定义,用户将自造,反而混乱
二、为何需要.value?
1、ref是一个对象,value存储值
2、通过.value属性的get和set实现响应式
3、用于模板、reactive时,不需要.value,其他情况都需要
注意:computed返回的是一个类似于ref的对象,也有.value
二、为什么需要toRef和toRefs?
1)不丢失响应式的情况下,把对象数据分散/扩散
2)针对的是响应式对象(reactive封装的)非普通对象
3)不创造响应式,而是延续响应式
六、vue3升级了哪些功能:
1、createdApp / emits属性 / 生命周期 / 多事件 / Fragment / 移除.sync
eg:
//父组件:
<HelloWorld :mag=msg @onSayHello='sayHello'/ >
//子组件:
export default{
name:'HelloWorld';
props:{
msg:String
},
emits:['onSayHello'],
setup( propos, {emit} ){
emit('onSayHello','vue3')
}
}
2、异步组件写法 / 移除filter / Teleport / Suspense / Composition API
七、composition API实现逻辑复用
1)抽离逻辑代码到一个函数
//eg:useMousePosition.js 文件
import { ref,onMounted, onUnmounted } from 'vue'
function useMousePosition(){
const x=ref(0);
const y=ref(0);
function updata(e){
x.value =e.pageX
y.value =e.pageY
}
onMounted(()=>{
console.log('useMousePosition mounted')
window.addEventListener('mousemove',updata)
})
onUnmounted(()=>{
console.log('useMousePosition unMounted')
window.remvoeEventListener('mousemove',updata)
})
return {
x,
y
}
}
export default useMousePosition
//eg:调用——index.vue
import useMousePosition from './useMousePosition'
export default{
name:'MousePosition',
setup(){
const {x,y} =useMousePosition()
return {
x,
y
}
}
}
2)函数命名预定为useXxxx格式(React Hooks也是)
八、vue3如何实现响应式:
1、vue2的object.defineProperty
sequenceDiagram
Alice->>John: Hello John, how are you?
John-->>Alice: Great!
Alice-)John: See you later!
function defineReactive(target,key,value){
//1深度监听
observer(value)
//核心API
Object.definProperth(target,key,{
//
get(){
return value
},
//
set(newValue){
if(newValue !== value){
//2深度监听 -——递归,一次性的,导致性能不是太好
observer(newValue)
//设置新值 —— 注意,value一直在闭包中,此处设置完之后,再get时也是会获取
value =newValue
//触发更新视图
updataView()
}
}
}){}
}
缺点:
- 深度监听需要一次性递归
- 无法监听新增属性/删除属性 (Vue.set Vue.delete)
- 无法原生监听数组,需要特殊处理
2、Proxy实现响应式: Proxy代理+reflect反射 实现
eg:
let data={
name:'sanqi',
age:20
}
const proxyData =new Proxy(data,{
get(target,key,receiver){
//只处理本身(非原型的)属性
const ownKeys =Reflect.ownKeys(target);
if(ownKeys.includes(key)){
console.log('get',key)
}
const result =Reflect.get(target,key,receiver)
//console.log('get',key) // get 20
return result //返回结果
},
set(target,key,receiver){
//重复数据,不处理
if(val===target[key]){
return true
}
const result =Reflect.set(target,key,receiver)
console.log('set',key,val) //set 30
console.log('set',result) // set true
return result //是否设置成功
},
deleteProperty(target,key){
const result =Reflect.set(target,key,receiver)
console.log('delete property',key) //
console.log('result',result) // result true
return result //是否删除成功
},
})
3、vue3中proxy实现响应式:
- 深度监听,性能更好
- 可监听新增/删除属性
- 可监听数组变化
//创建响应式
function reactive (target={}){
if(typ!=='object'||target ==null){
return target
}
//代理配置
const proxyConf ={
get(target,key,receiver){
//只处理本身(非原型的)属性
const ownKeys =Reflect.ownKeys(target);
if(ownKeys.includes(key)){
console.log('get',key) //监听
}
const result =Reflect.get(target,key,receiver)
//console.log('get',key) // get 20
//深度监听
return reactive(result) //重点
},
set(target,key,receiver){
//重复数据,不处理
if(val===target[key]){
return true
}
const ownKeys =Reflect.ownKeys(target);
if(ownKeys.includes(key)){
console.log('已有的key',key)
}else{
console.log('新增的key',key)
}
const result =Reflect.set(target,key,receiver)
console.log('set',key,val) //set 30
console.log('set',result) // set true
return result //是否设置成功
},
deleteProperty(target,key){
const result =Reflect.set(target,key,receiver)
console.log('delete property',key) //
console.log('result',result) // result true
return result //是否删除成功
},
}
//生成代理对象
const observed =new Proxy(target,proxyConf)
return observed
}
const data = {
name:'sanqi',
age:20,
info: {
city:'beijing'
}
}
const proxyData = reactive(data)
总结:proxy能规避Object.defineProperty的问题,但是无法兼容所有浏览器,无法polyfill
九、watch 与watchEffect 的区别
- 两者都可监听data属性变化
- watch需要明确监听哪个属性
- watchEffect会根据其中的属性,自动监听器变化
eg:
const numberRef = ref(100)
const state = reactive({
name:'sanqi',
age:20
})
watch(unberRef,(newNumder,oldNumder)=>{
console.log('ref watch',newNumder,oldNumder)
}
//,{
// immediate:true //初始化之前就监听,可选
//}
)
watch(
//第一个参数,确定要监听哪个属性
()=>state.age,
//第二个参数,回调函数
(newNumder,oldNumder)=>{
console.log('ref watch',newNumder,oldNumder)
}
//第三参数,配置项
,{
immediate:true, //初始化之前就监听,可选
deep:true, //深度监听
}
)
watchEffect(()=>{
//初始化时,一定会执行一次(收集要监听的数据)
console.log('hello watchEffect')
})
十、vue3为什么比vue2块:
- proxy响应式
- PatchFlag //编辑模板时,动态节点做标记 (diff算法)
- hoistStatic
将静态节点的定义,提升到父作用域,缓存起来
多个相邻的静态节点,会被合并起来
典型的拿空间换时间的优化策略
- cacheHandler
- SSR优化
- tree-shaking