浅析vue3.0

181 阅读8分钟

vue3.0与2.0的不同

Vue3.0 和 Vue2.0 相比,优势主要体现在:更快、更小、更易维护、更易于原生、让开发者更爽;

更快

  1. virtual DOM 完全重写,mounting & patching 提速 100%;
  2. 更多编译时 (compile-time)提醒以减少 runtime 开销;
  3. 基于 Proxy 观察者机制以满足全语言覆盖以及更好的性能;
  4. 放弃 Object.defineProperty ,使用更快的原生 Proxy
  5. 组件实例初始化速度提高 100%;(速度翻倍)
  6. 提速一倍/内存使用降低一半;(内存减半)

更易维护

  1. 3.0 新加入了 TypeScript 以及 PWA 的支持和部分命令发生了变化:
  2. 下载安装 npm install -g vue@cli
  3. 删除了vue list
  4. 创建项目 vue create
  5. 启动项目 npm run serve
  6. 默认项目目录结构也发生了变化:
  7. 移除了配置文件目录,config 和 build 文件夹
  8. 移除了 static 文件夹,新增 public 文件夹,并且 index.html 移动到 public 中
  9. 在 src 文件夹中新增了 views 文件夹,用于分类 视图组件 和 公共组件

更小

  1. Tree-shaking 更友好;
  2. 新的 core runtime:~ 10kb gzipped;

更易于原声

PWA全称Progressive Web App,即渐进式WEB应用。一个 PWA 应用首先是一个网页, 可以通过 Web 技术编写出一个网页应用. 随后添加上 App Manifest 和 Service Worker 来实现 PWA 的安装和离线等功能,PWA可以将app的快捷方式放置到桌面上,全屏运行,与原生app无异

3.0的新增方法和新的写法

setup的作用

对比vue2.0的使用方式,你需要把data, method, computed, watch以及生命周期都放到setup函数中来使用

1、setup中的data如何使用?
import { ref, toRefs, reactive }  from 'vue'
export default {
  name: 'Test',
  setup(){
    // 在setup中定义template模板使用的响应式变量,你得用ref或者reactive来定义
    // 这里的ref你可以理解成一个工厂类,传入的参数就是初始化的变量的值,跟组件的ref概念不能混淆
    // 定义单个变量,为了让大家明白意义,我跟vue2.0都进行下对比 
    // vue2.0,不管定义单个或者多个我们都是定义 在data里,如:
    /*
       data(){
          return {
            name: 'zhangmin'
          }
       }
    */
    
    // 在vue3.0中,如果你只需要定义一个响应式变量,那么你可以用以下ref
    // 可能你会疑惑既然是定义变量为什么不用let,var,而用const定义常量的,这里是因为你定义的是一个引用,name指向的永远是一个固定不变的指针地址
    const name = ref('zhangmin')
    // 注意点,这里要获取name的值怎么获取,通过定义的变量的 .value
    
    console.log('拿到name的值:', name.value)
    
    // 检测某个值是不是响应式的可以用isRef
    // 每次都用.value去拿值的写法,是不是有点不适应,而且定义的变量多了我们也不可能定义一堆ref,看起来都丑
   // reactive 可以创建一个响应式数据,参数是一个对象
    const data = reactive({
       name: '我叫张敏君'sex: '性别很重要'arr: []
    })
    // 但是以上还是有个缺点,如果你在return里直接放上data,
    //那你使用的时候每次都要data.name,data.sex也麻烦,<div>{{data.sex}}</div>
    // 你说你可以解构在return {...data} 如果你这样的,里面的数据都会变成非响应式的,
    //vue3.0提供了一个满足你幻想的方法toRefs,使用了这个包装下,你就可以在return里使用解构了
    // 包装上面的data
     const  refData = toRefs(data)
    // 在data中都有个return ,这里当然也必须要有的,但是这里是所有方法计算属性都要通过这个返回
    // 有人疑惑,那我可以直接在这个return上定义变量吗,答案是可以,但是定义的变量不是响应式的,不可变化
    return {
      ...refData, // 你也可以直接在这里用...toRefs(data) 这样会简单点
      name,
      rules: [] //如果你有什么不会变化的数据,如规则啊,配置啊,可以直接在这定义而不需要通过ref和reactive
    }
    
  }
}

2.setup中的method如何使用?

import { ref } from 'vue'
export default {
  name: 'Test',
  setup(){
    // 定义一个响应式数据
    const baby = ref('1岁boby')
   // 定义method,把方法名字在return里返回
   // 注意:这里用调用响应式的数据也就是您定义的vue2.0的data,
   //不可以用this,这个setup函数在01里已经说明过了,这个时候相当于vue2.0的beforeCreate和created,
   //这里一开始就会运行,还没有this的指向,是个undefined,访问所有你定义的响应式的变量都要.value去访问
    const wantToKnowBabysName = () => {
      console.log("oh,he is a " + baby.value)
    }
    const getData = () => {}
   // 对比vue2.0
   /*
   method: {
      wantToKnowBabysName(){
        console.log("oh,he is a " + baby.value)
      },
      getData() {
      }
    }
  */
   
    return {
      baby,
      wantToKnowBabysName,
      getData
    }
    
  }
}

3、setup中的computed如何使用?

// 注意使用的时候引入computed
import { ref, computed} from 'vue'
export default {
  name: 'Test',
  setup(){
    // 定义一个响应式数据
    const baby = ref('嘎嘎嘎')
    // 定义翠花年龄
    const age = ref(28)
    // computed计算属性传入一个回调函数
    const areYouSureYouAreABaby = computed(() => {
      return `I'm sure,I'm a 300 month baby, ${baby.value}`
    })
    // set和get方式
    const setAge= computed({
      get() {
        return age.value + 10
      },
      set(v) {
        age.value = v - 10
      }
    })
   // 对比vue2.0
   /*
   computed: {
      areYouSureYouAreABaby (){
        return `I'm sure,I'm a 300 month baby, ${baby.value}`
      },
      setAge:{
        get(){
          return age + 10
        },
        set(v) {
          age = v - 10
        }
      }
    }
  */
   
    return {
      baby,
      age,
      areYouSureYouAreABaby 
    }
    
  }
}

4、setup中的watch如何使用?

// 注意使用的时候引入watch
import { ref, watch, watchEffect } from 'vue'
export default {
  name: 'Test',
  setup(){
    // 定义一个响应式数据
    const baby = ref('嘎嘎嘎')
    const arr = ref(['翠花', '小红'])
    // 监听一个值的情况,有两种方式
    // watch 有三个参数:第一个是个getter(所谓getter写法就是你要写个getter函数),第二个是个回调函数,第三个是个options(这个参数是放vue2.0的deep或者immediate等可选项)
    // 第一种:直接放ref
    watch(baby, () => {
      return `I'm sure,I'm a 300 month baby, ${baby.value}`
    })
   // 第二种:放ref的value值
   watch(() => baby.value, () => {
      return `I'm sure,I'm a 300 month baby, ${baby.value}`
    })
  
   // 监听多个值的时候 ,第一个参数是个数组,里面放监听的元素
   watch([baby,arr], (v, o) => { 
     // 这里的v,o也是数组,所以你取值的时候v[0],v[1]拿到第几个元素的变化
     ...
   }, {
    deep: true,
    immediate: true
   })
 // 或者写成
 watch([baby,arr], ([baby, arr], [prebaby,prearr]) => {
    ...
  })
   // 对比vue2.0
   /*
   watch: {
      baby(v, o) {
        
      },
      arr: {
        handle(v,o) {},
        deep: true,
        immediate: true,
        flush: 'pre' // 这个默认有三个参数,'pre'| 'post' | 'sync',默认‘pre’组件更新前运行,'post'组件渲染完毕后执行,一般用于你需要去访问$ref的时候可以用这个,'sync'是一旦你的值改变你需要同步执行回调的时候用这个
      }
    }
  */
   // watch的写法跟vue2的$watch写法一样,可以参考
  // vue3.0 watchEffect 用法
  //  watchEffect 有两个参数,一个是副作用函数(就是外部的数据对这个函数产生影响的,通俗点说就是在这个函数内部使用了外面的变量等),一个是options()
//  在vue2.0中,我们一般在created里添加一些监听事件,比如你的$bus的一些事件监听,在setup中就可以在这个里面写
watchEffect((onInvalidate) => {
   // 这里的变化就相当于依赖了age.value,如果age变化了就会触发这个监听
   // 刚刚创建组件的时候会立即执行这个 
   const _age= `her age is ${age.value}`
   console.log(_age)
   //有时候你需要在这里挂载一些监听事件
   const handerClick = ()=>{}
   document.addEventlistener('click', handerClick)
   // 在vue2.0我们需要在destroy的时候remove它,这里提供了一个方法onInvalidate回调解决remove的问题
   onInvalidate(()=>{
       /*
        执行时机:  在副作用即将重新执行时,就是在每次执行这个watchEffect回调的时候会先执行这个,如果在setup()或生命周期钩子函数中使用watchEffect, 则在卸载组件时执行此函数。
       */
       document.removeEventListener('click',handerClick )
    })  
})
// 这个也是支持async,await的
const data = ref(null)
watchEffect(async onInvalidate => {
 // 假设个接口获取数据的
  data.value = await fetchData()
  onInvalidate(() => {...})
})
// 再来理解options:这里有三个参数flush,onTrigger,onTrack
watchEffect(onInvalidate => {
  onInvalidate(() => {...})
}, {
  flush: 'pre' // 跟watch一样,默认pre,组件更新前去调用
  onTrigger(e) {
    // 依赖项变化时候触发这个即依赖项的set触发的时候
  },
  onTrack(e) {
    // 依赖项被调用的时候触发这个即依赖项的get触发的时候
  }
})
    return {
      baby,
      areYouSureYouAreABaby,
      data 
    }
    
  }
}

5、setup中的生命周期如何使用?

image.png

//这里注意引入组件,用什么引入什么

import {onBeforeMount
       ,onMounted
       ,onBeforeUpdate
       ,onUpdated
       ,onBeforeUnmount
       ,onUnmounted} from 'vue';
export default {
  setup: function () {
    //组件挂载之前
    onBeforeMount(() =>{
      console.log("onBeforeMount");
    });
    //组件挂载完成
    onMounted (() => {
      console.log("onMounted");
    });
    //数据更新,虚拟 DOM 打补丁之前
    onBeforeUpdate (() => {
      //注意,onBeforeUpdate 和 onUpdated 里面不要修改值,会死循环的哦!
      console.log("onBeforeUpdate");
    });
    //数据更新,虚拟 DOM 渲染完成
    onUpdated (() => {
      console.log("onUpdated");
    });
    //组件销毁之前
    onBeforeUnmount (() => {
      console.log("onBeforeUnmount");
    });
    //组件销毁后
    onUnmounted (() => {
      console.log("onUnmounted");
    });
  }
}

vue3.0各个属性的介绍

reactive 与 ref

reactive用于为对象添加响应式状态。接收一个js对象作为参数,返回一个具有响应式状态的副本。

ref 用于为数据添加响应式状态。由于reactive只能传入对象类型的参数,而对于基本数据类型要添加响应式状态就只能用ref了,同样返回一个具有响应式状态的副本,获取数据值的时候需要加.value。可以理解为ref是通过reactive包装了一层具有value属性的对象实现的 参数可以传递任意数据类型,传递对象类型时也能保持深度响应式,所以适用性更广。 vue 3.0 setup里定义数据时推荐优先使用ref,方便逻辑拆分和业务解耦

代码如下:

<template>
       <div> Count is: {{ state.count }}</div>   
       <div> name is: {{ name }}</div>   
       <div> num is: {{ num.count }}</div>   
</template>

<script>
import { reactive,ref} from "vue"
export default {
    setup() {
     const state = reactive({
          count: 0,
        });
         // 为基本数据类型添加响应式状态
        const name = ref("Neo");

        // 为复杂数据类型添加响应式状态
        const num = ref({
          count: 0,
        });
        return {
         state,name,num
        }
    }
}
</script>

这时我们也可以实现一个简单的增加,再次引入一个vue的计算属性 computed,computed一定要import引入,如果不引入的话 他会报错,computed不存在

代码如下

<template>
       <div> Count is: {{ state.count }} double:{{state.double}}</div>   
</template>

<script>
import { reactive,computed} from "vue"
export default {
    setup(){
     const state = reactive({
          count: 0,
          double: computed(() => state.count * 2),
        });
        return {
         state
        }
    }
}
</script>