vue3与vue2的区别

127 阅读5分钟

一、vue3比vue2有什么优势?

  1. 性能更好
  2. 体积更小
  3. 更好的ts支持
  4. 更好的代码组织
  5. 更好的逻辑抽离
  6. 更多新功能

二、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