Vue3自学笔记

目录

    • 创建项目
    • setup
    • ref函数
    • reactive函数
    • Vue3的响应式原理
    • reactive对比ref
    • setup注意点
    • computed:计算属性
    • watch:监视属性
    • watchEffect函数
    • Vue3的生命周期
    • toRef和toRefs
      • toRef
      • toRefs
    • shallowReactive
    • shallowRef
    • shallowReactive和shallowRef使用情况
    • readonly
    • shallowReadonly
    • toRaw
    • markRaw
    • 响应式数据的判断
    • 新组件
      • Fragment
      • Suspense组件(实验性api)
    • 全局api转译
    • 其它改变
    • Vue3.2语法糖
      • script setup
        • defineProps 和 defineEmits
        • defineExpose
    • Vue Router

创建项目

vue-cli:需要版本在4.5.0以上。

npm init vite@latest

setup

setup是所有组合API的“表演舞台”。
组件中用到的数据、方法等等,都要配置在setup中。也就是说不在需要单写datamethods声明周期等等。

setup函数的两种返回值:
  1、若返回一个对象,则对象中的属性、方法,在模板中均可以直接使用。(重点)

<template>
  <h1>App组件h1>
  <p>姓名:{{name}}p>
  <p>年龄:{{age}}p>
  <button @click="sayHello">按钮button>
template>

<script>

export default {
  name: 'App',
  setup() {
    let name = "Tom";
    let age = 23;

    const sayHello = function() {
      alert(`我叫${name},今年${age}岁。`);
    };
    
	// 返回一个对象(常用)
    return {
      name,
      age,
      sayHello
    };
  }
}
script>

  2、若返回一个渲染函数。(了解)
    h需要两个参数,第一个是元素类型,第二个是内容。
    如果返回一个渲染函数,无论模板中是什么,都只渲染渲染函数中的内容。

import { h } from '@vue/runtime-core';

export default {
  name: 'App',
  setup() {
    let name = "Tom";
    let age = 23;

    const sayHello = function() {
      alert(`我叫${name},今年${age}岁。`);
    };

    // 返回一个渲染函数
    return () => h('h1','哈哈哈哈')
  }
}

注意:

  1. vue3尽量不要与vue2配置混用。
    vue2.x的配置(data、methods、computed…)中可以访问到setup的属性、方法。
    但是在setup中不能访问到vue2.x的配置(data、methods、computed…)
    如果有重名,setup优先。
  2. setup不能是一个async函数。因为加入了async,返回值就不再是对象,而是promise,模板看不到return对象中的属性。

ref函数

我们写一个按钮,给按钮绑定一个点击事件,想要实现点击更新页面显示信息。

<template>
  <h1>App组件h1>
  <p>姓名:{{name}}p>
  <p>年龄:{{age}}p>
  <button @click="changeInfo">修改信息button>
template>

<script>
export default {
  name: 'App',
  setup() {
    let name = "Tom";
    let age = 23;

  function changeInfo() {
    name = "李四";
    age = 48;
  }

    return {
      name,
      age,
      changeInfo,
    };
  }
}
script>

点击以后发现页面并没有发生改变,但是我们在changeInfo()中打印,会发现输出的name和age已经改变,但是由于vue没有检测到数据改变,所以没有渲染到页面上。
vue3有了一个新的re函数:

import {ref} from 'vue';
export default {
  name: 'App',
  setup() {
    let name = ref("Tom");
    let age = ref(23);

这时候我们发现点击按钮页面还是没有变化,先不在changeInfo()里面修改数据,打印一下name,age:console.log(name.age);
在这里插入图片描述
发现被ref 绑定为响应式数据的name和age变成了对象。
需要加.value触发原型对象上的getter方法改变数据。

import {ref} from 'vue';
export default {
  name: 'App',
  setup() {
    let name = ref("Tom");
    let age = ref(23);

  function changeInfo() {
    name.value = "李四";
    age.value = 48;
    console.log(name, age);
  }

    return {
      name,
      age,
      changeInfo,
    };
  }
}

vue3的模板字符串不需要写.value,当模板解析到ref的时候,会自动加上.value,所以我们写的

年龄:{{age}}

被vue解析成了

年龄:{{age。value}}

语法:cosnt xxx = ref(initValue)

  • 创建一个包含响应式数据的引用对象(ref对象)
  • js中操作数据:xxx.value
  • 模板中读取数据:不需要.value,直接

    {{xxxx}}

备注:

  • 接受的数据可以是基本数据类型,也可以是对象类型。
  • 基本数据类型:响应式数据依然是靠Object.defineProperty()getset完成的。
  • 对象类型的数据:内部使用了Vue3.0的一个新函数——reactive函数。

reactive函数

作用: 定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)

  • 语法:const 代理对象= reactive(源对象)接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)
  • reactive定义的响应式数据是“深层次的”。
  • 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。

给上面用ref写的job对象,换成reactive,打印:

import {ref, reactive} from 'vue';
export default {
  name: 'App',
  setup() {
    let name = ref("Tom");
    let age = ref(23);
    let job = reactive({
      type: "门卫",
      salary: "0k",
    });

  function changeInfo() {
    name.value = "李四";
    age.value = 48;
    console.log(job);
  }

    return {
      name,
      age,
      job,
      changeInfo,
    };
  }
}

Vue3自学笔记_第1张图片
我们想要更改对象内的值,无需在.value:

  function changeInfo() {
  	=======================
    job.type = "保安";
    job.salary = "1k";
  }

Vue3自学笔记_第2张图片
上面的所有属性我们可以直接放在一个对象中,创建一个person变量来接收这个对象,使用reactive来使对象变为响应式。

import {reactive} from 'vue';
export default {
  name: 'App',
  setup() {
    // let name = ref("Tom");
    // let age = ref(23);
    // let job = reactive({
    //   type: "门卫",
    //   salary: "0k",
    //   a:{
    //     b:{
    //       c: 300
    //     }
    //   }
    // });
    // let hobby = ["1", "2", "3"];
    let person = reactive({
      name: "Tom",
      age: 18,
      job: {
        type: "门卫",
        salary: "0k",
        a: {
          b: {
            c: 300
          }
        },
        hobby: ["吃饭", "睡觉", "打豆豆"],
      }
    })

  function changeInfo() {
    // name.value = "李四";
    // age.value = 48;
    // job.type = "保安";
    // job.salary = "1k";
    // job.a.b.c = 10101010;
    // hobby[0] = 100;
    person.name = "李四";
    person.age = 22;
    person.job.type = "保安";
    person.job.salary = "1k";
    person.job.a.b.c = 1008711;
    person.job.hobby[2] = "烫头";
  }

    return {
      person,
      changeInfo,
    };
  }
}

Vue3的响应式原理

Vue2的响应式存在一些问题:
  1、新增属性、删除属性,页面不会更新。
  2、直接修改数组下标,页面不会更新。

模拟响应式:
Vue2的响应式是通过Object.defineProperty()来实现的:

  let person = {
    name: "张三",
    age: "30"
  }

  // 模拟Vue2实现响应式
  let p = {}
  Object.defineProperty(p, "name",{
    get(){
      return person.name
    },
    set(Newvalue) {
      console.log("模拟响应式修改name属性")
      return person.name = Newvalue
    }
  })

Vue3自学笔记_第3张图片
Vue3采用es6的Proxy代理对象和Reflect反射对象来实现响应式。

  let person = {
    name: "张三",
    age: "30"
  } 
  
    const p = new Proxy(person, {
    // 查
    get(target, propName){
      console.log(`读取了${propName}属性`)
      return Reflect.get(target, propName)
    },
    // 改和增
    set(target, propName, value){
      console.log(`修改了${propName}${value}`);
      Reflect.set(target, propName, value)
    },
    // 删
    deleteProperty(target, propName){
      console.log(`删除了${propName}属性`)
      return Reflect.defineProperty(target, propName)
    }
  })

Vue3自学笔记_第4张图片
以上只是模拟,实际Vue的底层原理不是这么low。

reactive对比ref

  • 从定义数据角度对比:
    • ref用来定义:基本类型数据
    • reactive用来定义:对象(或数组)类型数据
    • 备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过reactive转为代理对象
  • 从原理角度对比:
    • ref通过Object.defineProperty()getset来实现响应式(数据劫持)。
    • reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。
  • 从使用角度对比:
    • ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value
    • reactive定义的数据:操作数据与读取数据:均不需要.value

setup注意点

  • setup的执行时机
    • beforeCreate之前执行一次,this是undefined
    beforeCreate() {
    	console.log("----start beforeCreate-----");
    },
    setup() {
        console.log("-----start setup------");
        console.log(this);
    },
    
    Vue3自学笔记_第5张图片
  • setup接受的参数
    • props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。如果不在setup顶部使用props接受外部给的数据,会报警告。
    props:['age'],
    setup(props) {
    	console.log(props);
    	},
    
  • context:上下文对象
    • attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于 this.$attrs
    • slots: 收到的插槽内容, 相当于 this.$slots。 vue3舍弃了slot="xxxx"的用法,只有v-solt:xxxx一种用法。
    • emit: 分发自定义事件的函数, 相当于 this.$emit

computed:计算属性

  • 与Vue2.x中computed配置功能一致
    • 简写形式:可以写成函数,没有考虑计算结果被修改的情况。只使用了set
    • 复杂形式:只能写成对象,考虑了计算结果被修改的情况。
<template>
  <h1>个人信息h1>
  姓:<input type="text" v-model="person.firstName">
  名:<input type="text" v-model="person.lastName">
  <br>
  <p>姓名:{{person.fullName}}p>
  <br>
  全名:<input type="text" v-model="person.fullName">
template>

<script setup>
  import {reactive,computed} from "vue";
  const person = reactive({
    firstName:"",
    lastName:"",
  });

  // 计算属性简写:没有考虑计算属性被修改
  person.fullName = computed(() => {
    return person.firstName +" " + person.lastName
  });

  // 计算属性完整写法,考虑计算属性被修改。是一个对象
  person.fullName = computed({
    get(){
      return person.firstName + " " + person.lastName;
    },
    set(value){
      const nameArr = value.split(" ")
      person.firstName = nameArr[0]
      person.lastName = nameArr[2]
    }
  })
script>

watch:监视属性

Vue3中watch成了一个组合api,所以需要引入。Vue3中的watch可以监视一个或者多个属性。
watch可以接收三个参数:第一个是被监视的属性名字,第二是监视的回调函数,第二个是监视的配置:immediate等等。

监视一个

<template>
  <h1>当前求和为:{{ sum }}h1>
  <button @click="sum++">点击+1button>
template>

<script>
import { ref, watch } from "vue";
export default {
  setup() {
    let sum = ref(0);

    // 情况1:监视ref定义的单个响应式数据
    watch(sum, (newValue, oldValue)=>{
      console.log("sum值变化", newValue, oldValue);
    })

    return {
      sum,
    };
  }, 
};
script>

watch监听的必须是响应式数据,如果是通过refs解构出来的,则需要写成() => 形式:

import { ref, reactive, toRefs, watch } from 'vue'

let obj = {
  num: 30
}
let objRet = reactive(obj)
let { num } = toRefs(objRet)
watch(() => obj.num, () => {

})

监视多个:把被监视的属性写在一个数组里面。

 // 情况2:监视ref定义的多个响应式数据
 watch([sum, msg], (newValue, oldValue)=>{
   console.log("sum或者msg值变化", newValue, oldValue);
 })

监视的第三个参数:监视的配置

 watch(sum, (newValue, oldValue)=>{
 	console.log("sum值变化", newValue, oldValue);
 },{immediate:true})

Vue3监视属性的坑:
监视reactive的对象响应式数据,但是Vue3中存在一些bug:无法获取oldValue

let person = reactive({
	name: "张三",
	age: 23,
})
watch(person,(newValue, oldValue)=>{
	console.log("变化了", newValue, oldValue);
})

执行代码会发现打印出的oldValue是错误的:
Vue3自学笔记_第6张图片
Vue3强制开启了深度监视(deep配置无效)

<template>
  <h1>薪资:{{person.job.work.salary}}h1>
  <button @click="person.job.work.salary++">点击涨薪button>
template>

<script>
import { ref, reactive, watch } from "vue";
export default {
  setup() {
    let person = reactive({
      job:{
        work:{
          salary: 2
        }
      }
    })
    // 默认开启深度监视,无法关闭
    watch(person,(newValue, oldValue)=>{
      console.log("变化了", newValue, oldValue);
    },{deep: false})

    return {
      sum,
      msg,
      person,
    }
  }
}
script>

以上代码中,我们配置了deep: false所以person.job.work.salary按理说应该监视不到,但是实际却是可以监听到:
在这里插入图片描述
监视reactive定义的一个响应式数据中的某一个属性
需要把想检测的那个属性写成方法:(该方法可以正确的监测oldValue

<template>
  <h1>名字:{{person.name}}h1>
  <h1>年龄:{{person.age}}h1>
  <h1>薪资:{{person.job.work.salary}}h1>
  <button @click="person.name+='e'">点击修改namebutton>
  <button @click="person.age++">点击修改年龄button>
  <button @click="person.job.work.salary++">点击涨薪button>
template>

<script>
import { reactive, watch } from "vue";
export default {
  setup() {
    let person = reactive({
      name: "张三",
      age: 23,
      job:{
        work:{
          salary: 2
        }
      }
    })

    // 情况4:监视reactive所定义的一个响应式数据中的某个属性
    watch(()=>person.age,(oldValue, newValue)=>{
      console.log("age改变了", oldValue, newValue);
    })

    return {
      
      person,
    }
  }
}
script>

上面代码想要监视person中的name属性,所以写了()=>person.name来监视person中的name属性。
Vue3自学笔记_第7张图片
监视reactive中的某一个响应式数据的某些属性:(和监视ref一样,写成数组)

 // 情况5:监视reactive所定义的一个响应式数据中的某些属性
 watch([()=>person.age, ()=>person.name], (oldValue, newValue)=>{
   console.log("age或者name改变了", oldValue, newValue);
 })

Vue3自学笔记_第8张图片
特殊情况: 如果我们想监视person下的job,按照正常思路我们会写成:

// 特殊情况
watch(()=>person.job,(oldValue, newValue)=>{
  console.log("person的job改变了", oldValue, newValue);
})

但是我们如果这么写的话,会发现监视不到,但是我们加上deep:true开启深度监视,就可以监视到了:

 // 特殊情况
 watch(()=>person.job,(oldValue, newValue)=>{
   console.log("person的job改变了", oldValue, newValue);
 }, {deep: true})

总结:当我们监视的reactive中的某一个属性,但是该属性依然是一个对象的时候,需要deep:true开启深度监视才能监视到。

watchEffect函数

  • watchEffect的用法是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。

  • watchEffect有点像computed:

    • 但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。
    • 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。
import { ref, reactive, watchEffect } from "vue";
export default {
  setup() {
    let sum = ref(0)
    let msg = ref("hello")
    let person = reactive({
      name: "张三",
      age: 23,
      job:{
        work:{
          salary: 2
        }
      }
    })
    
    watchEffect(()=>{
      // 使用了谁就去监听谁
      const x1 = sum.value
      const x2 = person.job.work.salary
      console.log("指定的回调执行了", x1, x2)
    })
    
    return {
      sum,
      msg,
      person,
    }
  }
}

Vue3的生命周期

Vue3依然可以使用Vue2的生命周期钩子,但是有两个被改名了:

beforeDestory被更名为beforeUnmount
destroyde被更名为unmounted

Vue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:

  • beforeCreate===>setup()
  • created=======>setup()
  • beforeMount ===>onBeforeMount
  • mounted=======>onMounted
  • beforeUpdate===>onBeforeUpdate
  • updated =======>onUpdated
  • beforeUnmount ==>onBeforeUnmount
  • unmounted =====>onUnmounted

因为变成了函数,所以需要引入import { } from "vue",语法:

import { ref, onBeforeMount } from "vue"
export default {
  setup() {
    let sum = ref(0)
    onBeforeMount(()=>{
      console.log("----------onBeforeMount----------");
    })

    return {
      sum
    }
  }
}

toRef和toRefs

toRef

可以让一个变量接收指定的一个响应式数据的某个属性。
语法toRef(哪个对象, "对象中的哪个属性")

<template>
  <h1>名字:{{name}}h1>
  <h1>年龄:{{person.age}}h1>
  <h1>薪资:{{salary}}h1>
  <button @click="name+='e'">点击修改namebutton>
  <button @click="person.age++">点击修改年龄button>
  <button @click="salary++">点击涨薪button>
template>

<script setup>
import {reactive, toRef} from "vue"

let person = reactive({
  name: "张三",
  age: 22,
  job:{
    work:{
      salary: 3
    }
  }
})
let name = toRef(person, 'name')

let salary = toRef(person.job.work, "salary")

script>

toRefs

语法:toRefs(要解析的响应式对象)
toRef功能一致,可以批量处理多个ref对象,如果ref是多层嵌套,toRefs只能解析到最外面一层:

import {reactive, toRef, toRefs} from "vue"

let person = reactive({
  name: "张三",
  age: 22,
  job:{
    work:{
      salary: 3
    }
  }
})

let salary = toRefs(person)
console.log(salary);

Vue3自学笔记_第9张图片

shallowReactive

浅响应式数据:只处理对象的最外层属性的响应式。

<template>
  <h1>名字:{{person.name}}h1>
  <h1>年龄:{{person.age}}h1>
  <h1>薪资:{{person.job.work.salary}}h1>
  <button @click="person.name+='e'">点击修改namebutton>
  <button @click="person.age++">点击修改年龄button>
  <button @click="person.job.work.salary++">点击涨薪button>
template>

<script setup>
import {shallowReactive} from "vue"

let person = shallowReactive({
  name: "张三",
  age: 22,
  job:{
    work:{
      salary: 3
    }
  }
})
script>

Vue3自学笔记_第10张图片

shallowRef

只处理基本类型的响应式,不处理对象类型的响应式。

如果只像下面让 shallowRef处理基本数据类型,那么可以处理未响应式。

<template>
  <h1>{{x}}h1>
  <button @click="x++">点击x+1button>
template>

<script setup>
import {shallowReactive, shallowRef} from "vue"

let x = shallowRef(0)
script>

shallowRef处理对象数据类型的时候,则不会变为响应式:

<template>
  <h1>{{x}}h1>
  <button @click="x++">点击x+1button>
template>

<script setup>
import {shallowReactive, shallowRef} from "vue"

let x = shallowRef({
  y:0
})
script>

Vue3自学笔记_第11张图片

shallowReactive和shallowRef使用情况

  • 如果有一个对象数据,结构比较深, 但变化时只是外层属性变化 ===> shallowReactive。
  • 如果有一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换 ===> shallowRef。

readonly

设置一个响应式对象为只读模式:

<template>
  <h1>和为:{{sum}}h1>
  <button @click="sum++">点击++button>
  <hr>
  <h1>名字:{{person.name}}h1>
  <h1>年龄:{{person.age}}h1>
  <h1>薪资:{{person.job.work.salary}}h1>
  <button @click="person.name+='e'">点击修改namebutton>
  <button @click="person.age++">点击修改年龄button>
  <button @click="person.job.work.salary++">点击涨薪button>
template>

<script setup>
import {reactive, ref, readonly} from "vue"

let person = reactive({
  name: "张三",
  age: 22,
  job:{
    work:{
      salary: 3
    }
  }
})
person = readonly(person)

let sum = ref(0)

script>

上面代码把person这个响应式数据设置为了readonly,所以不能对他进行修改,当我们尝试更改的时候,控制台会报出警告。
Vue3自学笔记_第12张图片

shallowReadonly

让一个响应式数据变为只读的(浅只读)。

<template>
  <h1>和为:{{sum}}h1>
  <button @click="sum++">点击++button>
  <hr>
  <h1>名字:{{person.name}}h1>
  <h1>年龄:{{person.age}}h1>
  <h1>薪资:{{person.job.work.salary}}h1>
  <button @click="person.name+='e'">点击修改namebutton>
  <button @click="person.age++">点击修改年龄button>
  <button @click="person.job.work.salary++">点击涨薪button>
template>

<script setup>
import {reactive, ref, shallowReadonly} from "vue"

let person = reactive({
  name: "张三",
  age: 22,
  job:{
    work:{
      salary: 3
    }
  }
})
person = shallowReadonly(person)

let sum = ref(0)

script>

上面的代码把person定义为了浅只读,所以我们在修改person最外层的name,age属性的时候,是不可以的,但是修改person,job.work.salary就可以更改,因为它是嵌套在job内部。
Vue3自学笔记_第13张图片

toRaw

将一个reactive生成的响应式对象转为普通对象

<template>
  <h1>名字:{{person.name}}h1>
  <h1>年龄:{{person.age}}h1>
  <h1>薪资:{{person.job.work.salary}}h1>
  <button @click="person.name+='e'">点击修改namebutton>
  <button @click="person.age++">点击修改年龄button>
  <button @click="person.job.work.salary++">点击涨薪button>
  <button @click="showRawPerson">输出原始的信息button>
template>


<script setup>
import {reactive} from "vue"

let person = reactive({
  name: "张三",
  age: 22,
  job:{
    work:{
      salary: 3
    }
  }
})

function showRawPerson() {
  const p = (person)
  console.log(p)
}

script>

上面定义了一个showRawPerson的点击事件来获取原始的person。如果不加toRaw获取的就是Proxy代理的数据:
Vue3自学笔记_第14张图片
而我们想要获取最原始的数据,就需要const p = toRaw(person):
Vue3自学笔记_第15张图片

markRaw

标记一个对象,使其永远不会再成为响应式对象。

<template>
  <h1>名字:{{person.name}}h1>
  <h1>年龄:{{person.age}}h1>
  <h1>薪资:{{person.job.work.salary}}h1>
  <h2 v-show="person.car">座驾:{{person.car}}h2>
  <button @click="person.name+='e'">点击修改namebutton>
  <button @click="person.age++">点击修改年龄button>
  <button @click="person.job.work.salary++">点击涨薪button>
  <button @click="showRawPerson">输出原始的信息button>
  <button @click="getCar">买一辆车button>
  <button @click="changeCarName">换车button>
template>


<script setup>
import {reactive, toRaw, markRaw} from "vue"

let person = reactive({
  name: "张三",
  age: 22,
  job:{
    work:{
      salary: 3
    }
  }
})

function showRawPerson() {
  const p = toRaw(person)
  console.log(p)
}

function getCar() {
  let car = {name: "自行车", price: 200}
  person.car = markRaw(car)
}

function changeCarName() {
  let newName = person.car.name += "!"
  console.log(newName)
  return newName
}

script>

上面我们给person.car添加了markRaw属性,使其不会再成为响应式对象,为了验证确实触发了点击事件,可以打印一下:

Vue3自学笔记_第16张图片
markRaw和readOnly的区别

markRaw是可以更改数据,但是无法成为响应式。
readOnly直接无法更改数据。

响应式数据的判断

isRef:检查一个值是否为一个ref对象
isReactive:检查一个对象是否由reactive创建的响应式数据
isReadonly:检查一个对象是否由readOnly穿件的只读代理
isProxy:检查一个对象是否由reactive或者readOnly方法创建的代理

新组件

Fragment

  • 在Vue2中: 组件必须有一个根标签
  • 在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中
  • 好处: 减少标签层级, 减小内存占用

Suspense组件(实验性api)

异步引入组件

import {defineAsyncComponent} from "vue"
const Demo = defineAsyncComponent(()=>import('./components/Demo.vue'))

使用Suspense包裹组件,并配置好defaultfallback

<template>
	<div class="app">
		<h3>我是App组件</h3>
		<Suspense>
			<template v-slot:default>
				<Child/>
			</template>
			<template v-slot:fallback>
				<h3>加载中.....</h3>
			</template>
		</Suspense>
	</div>
</template>

全局api转译

  • Vue2.x有许多全局api和配置
    • 例如:注册全局组件、注册全局指令等。
//注册全局组件
Vue.component('MyButton', {
  data: () => ({
    count: 0
  }),
  template: ''
})

//注册全局指令
Vue.directive('focus', {
  inserted: el => el.focus()
}
  • Vue3.0中对这些API做出了调整:

    • 将全局的API,即:Vue.xxx调整到应用实例(app)上

      2.x 全局 API(Vue 3.x 实例 API (app)
      Vue.config.xxxx app.config.xxxx
      Vue.config.productionTip 移除
      Vue.component app.component
      Vue.directive app.directive
      Vue.mixin app.mixin
      Vue.use app.use
      Vue.prototype app.config.globalProperties

其它改变

  • data选项应始终被声明为一个函数。

  • 过度类名的更改:

    • Vue2.x写法

      .v-enter,
      .v-leave-to {
        opacity: 0;
      }
      .v-leave,
      .v-enter-to {
        opacity: 1;
      }
      
    • Vue3.x写法

      .v-enter-from,
      .v-leave-to {
        opacity: 0;
      }
      
      .v-leave-from,
      .v-enter-to {
        opacity: 1;
      }
      
  • 移除keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes

  • 移除v-on.native修饰符

    • 父组件中绑定事件

      <my-component
        v-on:close="handleComponentEvent"
        v-on:click="handleNativeClickEvent"
      />
      
    • 子组件中声明自定义事件

      <script>
        export default {
          emits: ['close']
        }
      </script>
      
  • 移除过滤器(filter)

    过滤器虽然这看起来很方便,但它需要一个自定义语法,打破大括号内表达式是 “只是 JavaScript” 的假设,这不仅有学习成本,而且有实现成本!建议用方法调用或计算属性去替换过滤器。

Vue3.2语法糖

script setup