阅读 1923

一篇关于Vue3的个人学习笔记

这是我参与更文挑战的第30天,活动详情查看: 更文挑战

前言

今天是更文挑战的最后一天,想了许久,最后决定梳理一篇关于Vue3的个人小结,一来作为完美收官6月份,二来为7月份做个铺垫!

内容目录预览如下:

关于Vue3的个人学习笔记.png

Vue2和Vue3的区别

  1. 重构响应式系统,使用Proxy替换Object.definePropertyProxy优势:
  • 可直接监听数组类型的数据变化
  • 监听的目标为对象本身,不需要像Object.defineProperty一样遍历每个属性,有一定的性能提升
  • 可拦截的东西更多,提供了applyownKeyshas等13种拦截器方法
  1. 新增Composition API,更好的逻辑复用和代码组织
  2. 重构 Virtual DOM
  • 模板编译时的优化,将一些静态节点编译成常量
  • slot优化,将slot编译为lazy函数,将slot的渲染的决定权交给子组件
  • 模板中内联事件的提取并重用(原本每次渲染都重新生成内联函数)
  1. 代码结构调整,更便于Tree shaking,使得体积更小
  2. 使用Typescript替换Flow

Vue3为什么引入composition API

首先我们使用Vue2.x的形式来实现一个简单功能

需求:

1.当点击商品列表项时删除该项

2.当点击添加按钮时,会根据表单中数据添加一行到商品列表中

代码如下:

<template>
  <div class="wrap">
    <section>
      <h6>商品列表</h6>
      <table>
        <thead>
          <td>序号</td>
          <td>名称</td>
          <td>单价</td>
          <td>折扣</td>
          <td>折后价</td>
        </thead>
        <tbody>
          <tr
            v-for="(fruit, index) in fruits"
            :key="fruit.id"
            @click="remove_item(index)"
          >
            <td>{{ fruit.id }}</td>
            <td>{{ fruit.fruit_name }}</td>
            <td>{{ fruit.price }}</td>
            <td>{{ fruit.discount }}</td>
            <td>{{ (fruit.price * fruit.discount).toFixed(2) }}元/斤</td>
          </tr>
        </tbody>
      </table>
      <br />
    </section>
    <section>
      <h6>如果想添加一个商品,请输入:</h6>
      <form>
        商品序号:<input type="text" v-model="f.id" /><br />
        商品名称:<input type="text" v-model="f.fruit_name" /><br />
        单价价格:<input type="text" v-model="f.price" /><br />
        打折折扣:<input type="text" v-model="f.discount" /><br />
        <button @click="add_item">添加</button>
      </form>
    </section>
  </div>
</template>

<script>
export default {
  name: "App",
  data: function () {
    return {
      fruits: [
        { id: 1, fruit_name: "apple", price: 10, discount: 0.8 },
        { id: 2, fruit_name: "banana", price: 3, discount: 0.7 },
        { id: 3, fruit_name: "orange", price: 5, discount: 0.5 },
        { id: 4, fruit_name: "durain", price: 50, discount: 0.8 },
      ],
      f: {
        id: 5,
        fruit_name: "",
        price: "",
        discount: "",
      },
    };
  },
  methods: {
    remove_item(index) {
      this.fruits = this.fruits.filter((item, key) => index !== key);
    },
    add_item(e) {
      e.preventDefault();
      let temp = Object.assign({}, this.f);
      this.fruits.push(temp);
      this.f.id = this.fruits.length + 1;
      this.f.fruit_name = "";
      this.f.price = "";
      this.f.discount = "";
    },
  },
};
</script>
复制代码

简单加点样式

.wrap{
  width: 600px;
  margin: 10px auto;
  display: flex;
  justify-content:space-around;
  background-color:rgb(253, 247, 247);
  border-radius:4px;
}
.wrap table thead{
  background-color: deepskyblue;
  font-weight: bold;
  font-size: 0.9em;
}
.wrap table tr:nth-of-type(2n+1){
  background-color:pink;
}
.wrap form{
  font-size: 0.9em;
}
.wrap button{
  margin-top: 10px;
  width: 100%;
  color: rgb(224, 43, 31);
  font-weight: 700;
}
复制代码

显示结果如下

上述例子中,我们可以看到,使用2.xoption API,每当实现一个功能,都会在data中添加一些数据,同时在methods中添加业务逻辑。这里还好只有两个简单的功能,但实际工作中,当添加很多很多功能时,要找到某个功能对应数据和业务逻辑就变得非常困难,并且业务逻辑不一定就在methods中,还可能分散在computedwatch等选配项中。所以vue3.0中引入了composition API,专门用于解决功能、数据和业务逻辑分散的问题,使项目更益于模块化开发以及后期维护

Vue3更优雅的使用v-model

我们知道,在Vue2.0中如何实现双向数据绑定一种是v-model,另一种是.sync。通常一个组件只能用于一个v-model,但是有的组件需要有多个可以双向响应的数据,所以就出现了.sync

Vue3.0中为了实现统一,实现了让一个组件可以拥有多个v-model,同时删除掉了.sync。在vue3.0中,v-model后面需要跟一个modelValue,即要双向绑定的属性名,Vue3.0就是通过给不同的v-model指定不同的modelValue来实现多个v-model

Composition API和React Hook的区别

React Hook的实现角度看,React Hook是根据useState调用的顺序来确定下一次重渲染时的state是来源于哪个useState,所以出现了以下限制

  1. 不能在循环、条件、嵌套函数中调用Hook
  2. 必须确保总是在你的React函数的顶层调用Hook
  3. useEffectuseMemo等函数必须手动确定依赖关系

Composition API是基于Vue的响应式系统实现的,与React Hook的相比

  1. Composition API声明在setup函数内,一次组件实例化只调用一次setup,而React Hook每次重渲染都需要调用Hook,使得ReactGCVue更有压力,性能也相对于Vue来说也较慢
  2. Compositon API的调用不需要顾虑调用顺序,也可以在循环、条件、嵌套函数中使用
  3. 响应式系统自动实现了依赖收集,进而组件的部分的性能优化由Vue内部自己完成,而React Hook需要手动传入依赖,而且必须必须保证依赖的顺序,让useEffectuseMemo等函数正确的捕获依赖变量,否则会由于依赖不正确使得组件性能下降

虽然Compositon API看起来比React Hook好用,但是其设计思想也是借鉴了React Hook

ref函数

我们知道,在vue3.0引入了composition API,setup函数是其核心函数

setup函数中,可以使用ref函数,用于创建一个响应式数据,当数据发生改变时,Vue会自动更新UI 例如:使用ref函数定义一个变量count

import { ref } from 'vue';

function useChangeCount() {
    let count = ref(0);
    function change_count() {
        count.value += 1;
    }
    return { count, change_count }
}
export default useChangeCount;
复制代码

然后在组件中引入该模块:import useChangeCount from "./composition_tiny_js/count" 并且在组件的setup中使用,并通过return的形式将外界需要用到的变量和函数暴露出去

setup() {
  let { count, change_count } = useChangeCount();
  return { count, change_count };
}
复制代码

这样上面暴露的count变量,change_count方法就可以在外界使用了

<template>
    <div>
      <h1>{{ count }}</h1>
      <button @click="change_count">点我</button>
    </div>
</template>
复制代码

需要注意的是:

  1. setup中定义的变量或方法,都必须通过return {xxx,xxx}暴露出去,外界才能使用
  2. ref函数仅能监听基本类型的变化,不能监听复杂类型的变化(比如对象、数组)

reactive函数

reactive的用法与ref的用法相似,也是将数据变成响应式数据,当数据发生变化时UI也会自动更新。不同的是ref用于基本数据类型,而reactive是用于复杂数据类型,比如对象和数组 例如:定义一个对象类型的变量user

<template>
  <div>
    <p>{{ user }}</p>
    <button @click="increase">click me! one year later</button>
  </div>
</template>

<script>
import { reactive } from "vue";
export default {
  name: "reactive",
  setup() {
    const user = reactive({ name: "Alice", age: 12 });
    function increase() {
      ++user.age
    }
    return { user, increase };
  },
};
</script>
复制代码

如上,当点击按钮时,让数据user.age加1,当Vue发现数据发生变化,UI会自动更新 那我们验证了,确实reactive函数可以将一个复杂数据类型变成响应式数据。我们不妨将reactive函数执行的结果打印出来看下,看看它返回值是什么 reactive将传递的对象包装成了proxy对象 我们发现,reactive执行结果是将传递的对象包装成了proxy对象

接下来我们测试一下,如果传递基本数据类型呢?

<template>
  <div>
    <p>{{ userAge }}</p>
    <button @click="increase">click me! one year later</button>
  </div>
</template>

<script>
import { reactive } from "vue";
export default {
  name: "reactive",
  setup() {
    let userAge = reactive(12);
    function increase() {
      console.log(userAge);
      ++userAge;
    }
    return { userAge, increase };
  },
};
</script>
复制代码

运行发现,基本数据传递给reactivereactive并不会将它包装成porxy对象,并且当数据变化时,界面也不会变化

需要注意的是,reactive中传递的参数必须是json对象或者数组,如果传递了其他对象(比如new Date()),在默认情况下修改对象,界面不会自动更新,如果也需要具有响应式,可以通过重新赋值的方式实现

setup函数的注意点

我们知道setup函数是组合API的核心入口函数,使用时需要注意几点:

  1. setup函数的执行时机是在beforeCreatecreated之间
  2. 由于setup执行时机是在created之间,所以组件才刚刚被创建,而datamethods还没初始化好,所以无法在setup中使用datamethods
  3. setupthis指向undefined
  4. setup只能是同步的,不能是异步的

递归监听和非递归监听

我们知道ref函数和reactive函数用于将一个普通数据变成一个响应式的数据。当数据发生改变时,界面也会立即更新。 其实还有一个规律,就是是深度监听数据的每一层,我们称之为递归监听

import { reactive } from "vue";
export default {
  setup() {
   const alice =  { 
      name: "Alice", 
      age: 80,
      sex: 'female',
      child:{
        name:'Tom',
        sex: 'male',
        age:59,
        child:{
          name:'Frank',
          sex: 'male',
          age:30,
          child:{
            name:'Blue',
            sex: 'male',
            age:3
          }
        }
    }}
    const AliceFamily = reactive(alice );
    return { AliceFamily };
  },
};
复制代码

如上例子,vue会通过reactive函数将我们传递的对象alice的每一层打包成一个proxy对象,深度监听对象的每一层的每一个数据,当任意一层的任意一个数据发生改变,vue都会检测到,并更新对应的UI ref也是类似,因为ref的本质也是reactive

ref(12)  相当于  reactive({value:12})
复制代码

递归监听的好处显而易见,可以监听到每一个数据的变化,但正因为要监听每一个数据,当数据非常复杂时,vue要讲每个数据都通过Proxy包装一次,数据量大的话这个过程是非常消耗性能的。所以为了解决这个问题,vue3提供了两个函数用于创建浅度监听数据,即非递归监听。这两个函数是:

  1. shallowRef
  2. shallowReactive

使用过程中需要注意:

  • 如果是通过shallowRef创建数据,那么vue监听的是.value的变化,而不是第一层的变化
  • 另外vue3还提供了triggerRef函数,用于手动更新界面UI。但是没有提供triggerReactive,所以如果是reactive的数据,那是无法手动触发界面更新的。

那有人会想:在什么情况下用递归监听,什么情况下用非递归监听呢? 其实只要记住,非递归监听是为了解决监听数据量大的问题而出现的,所以只有当数据量非常大时,我们才考虑用shallowRefshallowReactive,一般情况下都使用refreactive

toRaw函数和markRaw函数

setup函数中,我们通过refreactive函数创建响应式数据,其特点是,每次修改数据都会更新UI界面,这样的问题是非常消耗性能

所以,如果我们有些时候,有些操作可以不需要每次修改数据都去更新UI界面,那么我们可以通过vue3提供的toRaw方法来获取该数据被Proxy包装前的原始数据,然后通过对原始数据进行修改,进而可以修改对应的代理对象内部数据。这是通过原始数据修改改变的,并不会触发 UI界面更新

<script>
import { reactive, toRaw } from "vue";
export default {
  setup() {
    const obj1= {name:'alice'};
    const user = reactive(obj1);
    const obj2 = toRaw(user);
    console.log(obj1 === obj2);//true
    function change() {
      obj2.name = 'Frank';
    }
    return { user, change};
  },
};
</script>
复制代码

上面例子中,通过包装后的响应式对象user来修改,界面会立即更新。但是如果通过修改原始数据obj2 来修改数据,界面是不会跟新的。另外我们可以看见obj2===obj1,由此证明: toRow就是用于获取一个Proxy对象的原始数据

以上是获取reactive的原始数据(创建时响应式数据时传入的原始数据),我们再来看下如何获取ref的原始数据

我们知道ref的本质是reactive,即ref(obj)相当于reactive({value : obj}) 所以如果想通过toRaw方法获取ref类型的原始数据,就必须明确告诉toRaw,需要获取的是.value的值。因为.value中保存的才是当初创建时传入的原始数据

import { ref, toRaw } from "vue";
export default {
  setup() {
    const obj1= {name:'alice'};
    const user = ref(obj1);
    const obj2 = toRaw(user.value);
    console.log(obj1,user,obj2);
    return { user };
  },
};
复制代码

有的情况下,我们希望某个数据在以后的操作中永远都不会被追踪,vue3提供了一个方法:markRaw

setup() {
   const obj= {name:'alice',age:18};
   obj= markRaw(obj);
   const user= reactive(obj);
   function change(){
    user.age=19
   }
   return { user , change};
}
复制代码

上述代码中,obj被markRaw标记后,当后面将obj变成proxy对象时,发现调用change方法改变数据时,界面并不会再跟新了!

toRef函数和toRefs函数

我们知道ref可以用于创建一个响应式数据,而toRef也可以创建一个响应式数据,那他们之间有什么区别呢?

事实上,如果利用ref函数将某个对象中的属性变成响应式数据,修改响应式数据是不会影响到原始数据。

import {ref} from 'vue';
export default {
  name:'App'
  setup(){
    let obj = {name : 'alice', age : 12};
    let newObj= ref(obj.name);
    function change(){
      newObj.value = 'Tom';
      console.log(obj,newObj)
    }
    return {newObj,change}
  }
}
复制代码

上述代码,当change执行的时候,响应式数据发生改变,而原始数据obj并不会改变。

原因在于,ref的本质是拷贝,与原始数据没有引用关系

需要注意ref(obj.name)相当于ref('alice')相当于reactive({value:'alice'}) 所以在修改数据时,是修改newObj.value=xxx

而如果使用toRef将某个对象中的属性变成响应式数据,修改响应式数据是会影响到原始数据的。但是需要注意,如果修改通过toRef创建的响应式数据,并不会触发UI界面的更新。

所以,toRef的本质是引用,与原始数据有关联

import {toRef} from 'vue';
export default {
  name:'App'
  setup(){
    let obj = {name : 'alice', age : 12};
    let newObj= toRef(obj, 'name');
    function change(){
      newObj.value = 'Tom';
      console.log(obj,newObj)
    }
    return {newObj,change}
  }
}
复制代码

上述代码,当change执行的时候,响应式数据发生改变,原始数据obj并不会改变,但是UI界面不会更新

小结:

ref和toRef的区别

(1). ref本质是拷贝,修改响应式数据不会影响原始数据;toRef的本质是引用关系,修改响应式数据会影响原始数据

(2). ref数据发生改变,界面会自动更新;toRef当数据发生改变是,界面不会自动更新

(3). toRef传参与ref不同;toRef接收两个参数,第一个参数是哪个对象,第二个参数是对象的哪个属性

所以如果想让响应式数据和以前的数据关联起来,并且想在更新响应式数据的时候不更新UI,那么就使用toRef

有的时候,我们希望将对象的多个属性都变成响应式数据,并且要求响应式数据和原始数据关联,并且更新响应式数据的时候不更新界面,就可以使用toRefs,用于批量设置多个数据为响应式数据。(toRef一次仅能设置一个数据)

toRefs接收一个对象作为参数,它会遍历对象身上的所有属性,然后挨个调用toRef执行

例如

import {toRefs} from 'vue';
export default {
  name:'App'
  setup(){
    let obj = {name : 'alice', age : 12};
    let newObj= toRefs(obj);
    function change(){
      newObj.name.value = 'Tom';
      newObj.age.value = 18;
      console.log(obj,newObj)
    }
    return {newObj,change}
  }
}
复制代码

使用customRef函数自定义一个ref

我们知道,ref函数可以创建一个响应式数据,在数据更新时同时更新UI界面

有的时候,我们希望可以显示的控制依赖追踪和触发响应,那就可以使用customRef函数自定义一个ref

自定义ref本质其实就是return customRef()

需要注意:

customRef函数接受一个工厂函数,该工厂函数有两个参数,分别是用于追踪的track与用于触发响应的trigger,并且返回一个的对象,该对象需要有getset方法

官方例子:使用自定义 ref 实现带防抖功能的 v-model :

<input v-model="text" />
复制代码
function useDebouncedRef(value, delay = 200) {
  let timeout
  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return value
      },
      set(newValue) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          value = newValue
          trigger()
        }, delay)
      },
    }
  })
}

export default {
  setup() {
    return {
      text: useDebouncedRef('hello'),
    }
  },
}
复制代码

如上代码,在get中显示调用track()表示该数据需要被追踪,在set中显示的调用trigger()表示当数据被修改时,需要更新UI界面。

使用customRef函数自定义一个ref函数的步骤:

1.函数返回customRef()

2.customRef接受两个参数track和trigger

3.customRef返回一个对象

4.customRef返回的对象必须实现set和get方法

5.在get中显示调用track()表示该数据需要被追踪,在set中显示的调用trigger()表示当数据被修改时,需要更新UI界面

如何通过ref属性获取元素

vue2.x中,可以通过给元素添加ref='xxx'属性,然后在代码中通过this.$refs.xxx获取到对应的元素

然而在vue3中时没有$refs这个东西的,因此vue3中通过ref属性获取元素就不能按照vue2的方式来获取

vue3需要借助生命周期方法,原因很简单,在setup执行时,template中的元素还没挂载到页面上,所以必须在mounted之后才能获取到元素。

<template>
  <div ref='box'>I am DIV</div>
</template>
<script>
import {ref,onMounted}
export default{
  setup(){
    let box = ref(null);
    onMounted(()=>{
      console.log(box.value)
    });
    return {box}
  }
}
</script>
复制代码

如上代码,vue3中,所有生命周期方法都抽离出去了,需要用时直接import 。这里导入了一个onMounted

当界面挂载出来的时候,就会自动执行onMounted的回调函数,里头就可以获取到dom元素

小结

1.在compositionAPI中如何使用生命周期函数?

需要用到哪个生命周期函数,就将对应函数的import进来,接着在setup中调用即可

2.vue3如何通过ref属性获取界面上的元素?

在template中的写法跟vue2一样,给元素添加个ref='xxx'

在setup中,先创建一个响应式数据,并且要把响应式数据暴露出去

当元素被创建出来的适合,就会给对应的响应数据赋值

当响应式数据被赋值之后,就可以利用生命周期方法,在生命周期方法中获取对应的响应式数据,即DOM元素

readonly和shallowReadonly函数

vue3中提供了只读相关的函数:readonlyshallowReadonlyisReadonly

三者用途和区别显而易见:

readonly:用于创建一个只读数据,并且是深度只读或者叫递归只读

shallowReadonly:也是用于创建一个只读数据,但是这个只读只是第一层只读,非深度只读

isReadonly:判断一个数据是不是只读数据

我们知道const定义的变量也是不能改的,那readonly和const有什么区别?

  1. const是赋值保护,使用const定义的变量,该变量不能重新赋值。但如果const赋值的是对象,那么对象里面的东西是可以改的。原因是const定义的变量不能改说的是,对象对应的那个地址不能改变

  2. 而readonly是属性保护,不能给属性重新赋值

Teleport组件

Teleport,被称为传送门组件,用于提供一种简洁的方式,指定其里面内容的父元素

例如,定义一个模态框,该模态框原本是在一个组件中的,但我希望当弹出的时候,它的结构是body下,与#app平级。如下代码

<template>
  <button @click="modalsOpen = true">弹出框按钮</button>
  <teleport to='body'>
    <div v-if="modalsOpen" class="modals">
      <div>
          <p>这是一个弹出框,并且是被传送到body上</p>
          <button @click="modalsOpen = false">关闭</button>
      </div>      
    </div>
  </teleport>
</template>

<script>
import { ref } from "vue";
export default {
  name: "Modals",
  setup() {
    let modalsOpen = ref(false);
    return { modalsOpen };
  },
};
</script>

<style scoped>
.modals{
    background-color: rgba(0, 0, 0, .5);
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}
.modals div{
    border-radius: 4px;
    width: 300px;
    height: 100px;
    background-color:#fff;
    padding: 20px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    font-size: .9em;
    color:  rgba(0, 0, 0, .9);
}
button{
    padding: 5px;
}
</style>
复制代码

显示结果如下:

image.png

我们发现,teleport组件使用也比较简单,就是通过to属性能将其里面的内容被传送到指定的哪个元素下,属性值为元素选择器

Fragments和emits选项

Vue3中组件可以拥有多根

我们知道,在vue2.x中,每个组件只能有一个根,这意味着我们写每个组件模板时都要套一个父元素。vue3为了更方便的书写组件模板,引入Fragments,说白了就是vue3中组件可以拥有多个根了

例如:创建一个Fragments.vue,组件模板可以写多个根

<template>
    <div>
        <h1>Fragments</h1>
    </div>
    <div>
        <p>vue3引入Fragments,本意是碎片</p>
        <p>说白了就是vue3的组件可以拥有多个根了</p>
    </div>
    <!--还可以拥有其他更多根-->
</template>
复制代码

如上,由以前的单根变成多根的情况,是不是有点零零碎碎的感觉,这就是Fragmens意思的来源----碎片

vue3针对自定义事件,添加了emits选项

vue3新增emits选项,需要将组件发送的自定义事件定义在emits选项中。一来可以避免当自定义事件与原生事件重名时,事件会触发多次的情况,比如:click事件;二来可以更好的指示组件的工作方式

例如:创建一个Emits.vue,我们自定义了一个click事件

<template>
  <button @click="$emit('click')">点我</button>
</template>
<script>
export default {
    //emits:['click']
};
</script>
复制代码

如果自定义事件没有写入到emits选项中,当自定义事件名与原生事件名冲突时,事件会被多次触发

<template>
  <Emits @click="onClick"></Emits>
</template>

<script>
import Emits from './components/Emits.vue'
export default {
  name: 'App',
  components: {
    Emits
  },
  methods:{
    onClick(){console.log('clicked!!!!!')}
  }
}
</script>
复制代码

因此,在vue3书写自定义事件的时候,都建议将自定义事件书写到emits选项中

Vue3中全局API改为应用程序实例调用

vue3中存在一些具有破坏性的变更,比如Global API改为应用程序实例调用

Vue2中很多全局API会改变vue的行为,全局的API会导致一些问题:

  1. Vue2没有app的概念,new Vue()得到的根实例作为app,这样所有创建的根实例app都是共享相同的全局配置,这在测试时会污染其他测试用例,导致测试困难
  2. 全局配置也导致没有办法在单页面创建不同全局配置的多个app实例

所以,Vue3使用createApp函数返回应用程序实例app,并由这个app实例暴露一系列的全局API

比如,Vue2Vue.component变更为如下形式

import { createApp, h } from 'vue'
import App from './App.vue'
import './index.css'

const app = createApp(App)
    .component('comp', { render: () => h('div', 'i am comp!!!') })
    .mount('#app')
复制代码

可以看到,Vue2中通过Vue的构造函数调用component创建全局组件,现在变成有应用实例app调用的形式

类似的变更(Vue.component变更为app.component)还有:

1. Vue.directive变更为app.directive

2. Vue.mixin变更为app.mixin

3. Vue.use变更为app.use

4. Vue.config变更为app.config

5. Vue.config.ignoredElements变更为app.config.ignoredElements

注意:Vue.config.productionTipVue.filterVue3中被移除

关于Tree-shaking

我们知道,Vue3中提到一个叫Tree-shaking的东西,其实也并不是一个新的东西,有人称之为"摇树优化",什么意思?

按照尤大的原话解释,Tree-shaking其实就是:把无用的模块进行“剪枝”,很多没有用到的API就不会打包到最后的包里

其实说白了,Tree-shaking本质并不是Vue3的东西,而是那些打包工具的功能。只是Vue3代码结构调整,当用webpack等打包工具打包项目时,webpack会将那些没用用到的代码不打包到最后的项目中,这样使得项目体积更小

主要原理:依赖es6的模块化的语法,将无用的代码(dead-code)进行剔除!

Vue3中生命周期函数的变化

我们知道,在每个组件在被创建时,要经过一系列的初始化过程,比如,需要设置数据监听、编译模板、实例挂载并在数据变化时触发DOM更新等。

Vue2中提供了生命周期钩子函数,如 beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedbeforeDestorydestoryed等,用于在组件不同阶段执行一些我们想要的执行的操作

到了Vue3,有所变化

  1. beforeCreate ---->setup
  2. created ---->setup
  3. beforeMount ---->onBeforeMount
  4. mounted ---->onMounted
  5. beforeUpdate ---->onBeforeUpdate
  6. updated ---->onUpdated
  7. beforeDestory ---->onBeforeUnmount
  8. destoryed ---->onUnmounted

可以看到,setup 函数代替了 beforeCreate created 两个生命周期函数,因此我们认为setup的执行时间在beforeCreate created 之间

为了更好的Tree-shakingVue3的生命周期函数都是从 vue 中导入,再进行直接调用

//从 vue 中引入 多个生命周期函数
import {onBeforeMount, onMounted, onBeforeUpdate, onUpdated, 
  onBeforeUnmount, unMounted} from 'vue'
export default {
  name: 'App',
  setup() {
    onBeforeMount(() => {
      // 在挂载前执行
    })
    onMounted(() => {
      // 在挂载后执行
    })
    onBeforeUpdate(() => {
      // 在更新前前执行
    })
    onUpdated(() => {
      // 在更新后执行
    })
    onBeforeUnmount(() => {
      // 在组件销毁前执行
    })
    unMounted(() => {
      // 在组件销毁后执行
    })
    return {}
  }
  
}
复制代码

END~

以上就个人的一些学习笔记,不一定都正确!希望下个月好好学好Vue吧~

6月,完美收官!!撒花~

文章分类
前端
文章标签