vue3 小demo,真香~

374 阅读5分钟

为什么要写vue3

Vue代码库随着时间的推移而暴露出来的设计和体系架构问题

生命周期的变化

 vue 2                     vue3

 BeforeMount               onBeforeMount mounted                   onMounted beforeUpdate              onBeforeUpdate updated                   onUpdated beforeDestroy             onBeforeUnmount destroy                   onUnmounted errorCaptured             onErrorCaptured

vue3的亮点

性能优化

1、diff算法优化

vue2中的虚拟DOM是进行全量对比的,数据有没有更新都会进行比较

vue3新增了静态标记(PatchFlag),只会比较带有静态标记的节点,并通过静态标记可以得出要比较的具体内容,固定不变的节点不会带有静态标记

<p>{{message}}<p>      //比较的是动态文本

<p :class="{ active: isActive }">我是一只小毛驴</p>  // 比较的是动态class

2、hoistStatic(静态提升)

vue2中无论元素是否参与更新,每次都会重新创建,然后渲染

vue3中对于不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用。

3、cacheHandlers(事件侦听器缓存)

默认情况下,事件均会被动态绑定带有静态标记,所以每次都会去追踪他的变化,但函数还是那个函数,不会变,所以不需要追踪变化,直接缓存起来复用即可

composition Api

组合Api又可称为注入Api,等效于组合Api中的数据可以注入到vue2中的data函数中,组合Api中的方法注入到vue2中的methods中。vue2中数据与业务逻辑分离,不便于阅读和后期维护,组合Api允许用户像编写函数一样自由地表达、组合和重用有状态的组件逻辑

typescript支持

Typescript强类型语言,支持类型声明,可进行类型检查,编写稳定性高的代码,有利于后期维护和代码的阅读

使用proxy代替defineProperty

1、vue2版本双向数据绑定是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。(defineProperty只能绑定首次渲染时候的属性,后加的属性是不会被绑定上,也就不会触发更新渲染)
2、Vue3是用ES6的语法 Proxy对象来实现的(Proxy绑定的是整体,不关心里面有什么属性,而且Proxy的配置项有13种,可以做更细致的事情)

Proxy优势:
(1)defineProperty只能监听某个属性,不能对全对象监听
(2)可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
(3)可以监听数组,不用再去单独的对数组做特异性操作
(4) vue3.x可以检测到数组内部数据的变化

(5)defineProperty无法兼容IE8,所以vue2只能兼容到IE8,其他浏览器也会存在轻微兼容问题;proxy除了IE,其他浏览器都兼容

按需编译,打包体积小

在vue2中,随着依赖包和框架特性的增多,有时候不必要的、未使用的代码文件都被打包了进去,后期项目大了,打包文件特别大;在Vue 3中,通过将大多数全局API和内部帮助程序移动到Javascript的module.exports属性上,这允许现代模式下的module bundler能够静态地分析模块依赖关系,并删除与未使用的module.exports属性相关的代码。模板编译器还生成了对树抖动友好的代码,只有在模板中实际使用某个特性时,该代码才导入该特性的帮助程序。尽管增加了许多新特性,但Vue 3被压缩后的基线大小约为10 KB,不到Vue 2的一半。

vue3快速上手

安装

1、安装vite

vite是一个类似于webpack的打包工具,他的实现原理是利用ES6中的import会发送请求去加载文件的特性,拦截这些请求,做一些预编译,省去了webpack冗长的打包时间

npm install -g create-vite-app

2、利用vite创建vue3项目

create-vite-app projectName

3、安装依赖运行项目

cd projectName
npm install
npm run serve

vue2实现一个todolist

<template>  <div class="toDoList">    <label>id:</label><input v-model="student.id" />     <label>姓名:</label><input v-model="student.name" />     <label>年龄:</label><input v-model="student.age" />    <button @click="add">提交</button>    <p v-for="(item, index) in studentLists" :key="item.id" @click="sub(index)">      {{ item.name }}--{{ item.age }}    </p>  </div></template><script>export default {  data() {    return {      studentLists: [        { id: 1, name: "张三", age: "20" },        { id: 2, name: "李四", age: "30" },        { id: 3, name: "王五", age: "40" },      ],      student: {        id: null,        name: "",        age: "",      },    };  },  methods: {    add() {      this.studentLists.push(this.student);      this.student = {};    },    sub(index) {      this.studentLists = this.studentLists.filter((item, index2) => {        return index2 != index;      });    },  },};</script>

vue3实现一个todolist

1、小试牛刀

<template>  <div class="toDoList">    <span @click="add">{{ count }}</span>  </div></template><script>import { ref } from "vue";export default {  // setup函数是组合Api的入口函数  setup() {    //定义一个count变量,初始值为0,这个变量变化时,自动更新ui 等同于 let count = 0    // ref只能监听简单数据类型的变化,对复杂数据类型无用    const count = ref(0); // 在组合Api中,可以直接定义方法    function add() {      count.value++;      console.log(count);    }    // 在组合Api中定义的变量、方法,要想在外界使用,必须return出去    return { count, add };  },};</script>

2、实现todolist(常规版)

<template>  <div class="toDoList">    <label>id:</label><input v-model="state.student.id" />     <label>姓名:</label><input v-model="state.student.name" />     <label>年龄:</label><input v-model="state.student.age" />    <button @click="add">提交</button>    <p      v-for="(item, index) in state.studentLists"      :key="item.id"      @click="sub(index)"    >      {{ item.name }}--{{ item.age }}    </p>  </div></template><script>import { reactive } from "vue";export default {  // setup函数是组合Api的入口函数  setup() {    // reactive可以监听复杂数据类型    const state = reactive({      studentLists: [        { id: 1, name: "张三", age: "20" },        { id: 2, name: "李四", age: "30" },        { id: 3, name: "王五", age: "40" },      ],      student: {        id: null,        name: "",        age: "",      },    });    // 在组合Api中,可以直接定义方法,也可以写在setup函数外    function add() {      state.studentLists.push(state.student);      state.student = {};    }    function sub(index) {      state.studentLists = state.studentLists.filter((item, index2) => {        return index2 != index;      });    }    // 在组合Api中定义的变量、方法,要想在外界使用,必须return出去    return { state, add, sub };  },};</script>

3、实现todolist(封装版)

<template>  <div class="toDoList">    <label>id:</label><input v-model="state2.student.id" />     <label>姓名:</label><input v-model="state2.student.name" />     <label>年龄:</label><input v-model="state2.student.age" />    <button @click="add">提交</button>    <p      v-for="(item, index) in state.studentLists"      :key="item.id"      @click="sub(index)"    >      {{ item.name }}--{{ item.age }}    </p>  </div></template><script>import { reactive } from "vue";function subStudent() {  const state = reactive({    studentLists: [      { id: 1, name: "张三", age: "20" },      { id: 2, name: "李四", age: "30" },      { id: 3, name: "王五", age: "40" },    ],  });  function sub(index) {    state.studentLists = state.studentLists.filter((item, index2) => {      return index2 != index;    });  }  // 必须return  return { state, sub };}

function addStudent(state) {  const state2 = reactive({    student: {      id: null,      name: "",      age: "",    },  });  function add() {    state.studentLists.push(state2.student);    state2.student = {};  }  // 必须return  return { state2, add };}

export default {  setup() {    const { state, sub } = subStudent();    const { state2, add } = addStudent(state);    return { state, sub, state2, add };  },};</script>

4、实现todolist(引入版)

//student.js

import { reactive } from "vue";function subStudent() {  const state = reactive({    studentLists: [      { id: 1, name: "张三", age: "20" },      { id: 2, name: "李四", age: "30" },      { id: 3, name: "王五", age: "40" },    ],  });  function sub(index) {    state.studentLists = state.studentLists.filter((item, index2) => {      return index2 != index;    });  }  // 必须return  return { state, sub };}function addStudent(state) {  const state2 = reactive({    student: {      id: null,      name: "",      age: "",    },  });  function add() {    state.studentLists.push(state2.student);    state2.student = {};  }  // 必须return  return { state2, add };}export { subStudent, addStudent };

//student.html

<template>  <div class="toDoList">    <label>id:</label><input v-model="state2.student.id" />     <label>姓名:</label><input v-model="state2.student.name" />     <label>年龄:</label><input v-model="state2.student.age" />    <button @click="add">提交</button>    <p      v-for="(item, index) in state.studentLists"      :key="item.id"      @click="sub(index)"    >      {{ item.name }}--{{ item.age }}    </p>  </div></template><script>import { subStudent, addStudent } from "./student";export default {  setup() {    const { state, sub } = subStudent();    const { state2, add } = addStudent(state);    return { state, sub, state2, add };  },};</script>

注意点

setup

(1)setup函数是在beforeCreated之前执行的

(2)在setup函数中无法使用data和methods

(3)在setup函数中使用this,this是undefined

(4)setup函数只能是同步,不能是异步,如果需要异步,要在setup前加async

reactive

(1)reactive函数的参数必须是对象(json/arr)

(2)reactive函数的参数如果不是对象,数据将不具有响应式

(3)reactive函数的参数如果是其他对象(比如 new Date()),直接在原有数据的基础上进行修改,页面不会自动更新;如果想更新,可以通过直接赋值的方式

(3)reactive函数的本质就是将数据包装成一个proxy对象

//直接设置无效
setup(){
   const state = reactive({
        time = new Date()
   );
   function addTime(){
         state.time.setDate(state.time.getDate() + 1)
    }
}

//重新赋值有效
setup(){
   const state = reactive({
        time = new Date()
   );
   function addTime(){
         const newTime = new Date(state.time.getTime());
         nweTime.setDate(state.time.getDate() + 1);
         state.time = newTime;
    }
}

ref

(1)ref的本质还是reactive,系统会自动将const count = ref(0)转为 const count = reactive({ value : 0 }),只是ref实现对简单类型的监听

(2)在html中使用ref的值(count)可以直接使用count,在js中必须使用count.value才行

总结

waiting for update......