11、Vue3

Vue3

相比vue2的提升

创建vue3工程

1、使用vue/cli,确保版本大于4.5.0

2、使用vite,vue团队打造

Vue3的变化

main.js

// 不再是引入Vue构造函数,而是引入createApp工厂函数
import { createApp } from 'vue'
import App from './App.vue'

//创建应用实例对象,类似于Vue实例对象,但是比Vue实例对象更轻
createApp(App).mount('#app')

App.vue

<!-- vue3中的组件模板可以没有根标签 -->
<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <HelloWorld msg="Welcome to Your Vue.js App"/>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>
<style>
</style>

Composition API

setup

vue3中的一个新的组件配置项,值是一个函数,setup是所有Composition API表演的舞台

组件中用到的所有数据、方法、计算属性,全部要配置在setup中

<template>
  <h1>name:{{name}}</h1>
  <h1>age:{{age}}</h1>
  <button @click="show">show</button>
</template>

<script>
export default {
  name: 'App',
  setup(){
    //数据
    let name = "lucy";
    let age = 18;
    //方法
    function show(){
      alert("姓名:" + name + ",年龄:" + age);
    }
    return {name,age,show}
  }
}
</script>

注意:尽量不要和vue2配置混用(vue2配置可以读取setup的属性和方法,但是setup不能访问vue2配置的);setup不能使用async修饰

setup函数的执行时机

在beforeCreate之前执行一次,this是undefined,也就是说,setup中不要写this

ref函数

对于在setup函数中返回的属性,虽然组件可以直接使用,但是不是响应式(页面随着数据进行改变)的,如果需要该属性是响应式的,也就是需要vue监测该属性,那么需要使用vue提供的ref函数

ref函数,接受的数据可以是基本类型也可以是对象类型

对于基本类型:底层依靠的是defineProperty()get()set()实现

对于对象类型:底层利用vue3的一个新函数reactive()实现

<template>
  <h1>name:{{name}}</h1>
  <h1>age:{{age}}</h1>
  <button @click="ageAdd10">ageAdd10</button>
</template>

<script>
//引入ref函数
import {ref} from 'vue';
export default {
  name: 'App',
  setup(){
    let name = "lucy";
    //需要响应式的属性使用ref函数,生成引用实现对象
    let age = ref(18);
    //方法
    function ageAdd10(){
      //修改值的时候需要修改引用实现对象的value属性
      age.value += 10;
    }
    return {name,age,ageAdd10}
  }
}
</script>

reactive函数

和ref作用、用法都一样,定义响应式数据,通常用来定义对象类型数据,虽然ref也可以定义对象数据类型,但是底层调用的还是reactive

computed函数

用于在setup中定义计算属性

<template>
  <input type="text" v-model="name">
  <h1>{{sayHello}}</h1>
</template>

<script>
import {ref,computed} from 'vue';
export default {
  name: 'App',
  setup(){
    let name = ref("lucy");
    let sayHello = computed(() => {
      return "Hello " + name.value;
    });
    return {name,sayHello}
  }
}
</script>

watch函数

用于在setup中定义监视属性

注意:可以同时监视多个变量,只需要多个变量放到一个数组,传到第一个参数即可

<template>
  <input type="text" v-model="name">
</template>

<script>
import {ref,watch} from 'vue';
export default {
  name: 'App',
  setup(){
    let name = ref("lucy");
    watch(name,(after,before)=>{
      console.log(before,after);
    })
    watch(name,(after,before)=>{
      console.log(before,after);
    },{immediate: true}) //如果使用immediate:true,那么回调会在组件创建时调用一次
    return {name}
  }
}
</script>

watchEffect函数

这个函数的参数是一个回调函数(无参),可以智能的监视这个回调函数里面使用的数据,如果数据发生变化,就会调用该回调,并且在组件创建时调用一次

<template>
  <input type="text" v-model="name">
</template>

<script>
import {ref,watchEffect} from 'vue';
export default {
  name: 'App',
  setup(){
    let name = ref("lucy");
    watchEffect(()=>{
      console.log(before,after);
    })
    return {name}
  }
}
</script>

toRef函数

创建一个ref对象,其value值指向另一个响应式对象中的某个属性,这个value也是响应式的

setup(){
    let student = reactive({
        name: 'lucy',
        age: 18,
        clazz: {
            level: 9
        }
    })
    let name = toRef(student,'name');
    let level = toRef(student.clazz,'level');
    return {name}
}

toRefs函数

可以将一个响应式对象中的所有属性(第一层属性)都变成响应式对象,也就是不会将下面level变成响应式

setup(){
    let student = reactive({
        name: 'lucy',
        age: 18,
        clazz: {
            level: 9
        }
    })
    let stu = toRefs(student);
    return {name}
}

toRaw函数

可以将一个响应式对象转换为一个普通对象并返回

vue3没有this

1、由于vue3中setup函数的执行时机要比beforeCreate早,所以在setup中无法拿到this

2、由于vue3不是使用Vue构造进行构建,而是使用App,所以如果要挂载一些属性到Vue原型对象上,方法和vue2不同

例如挂载axios

// 引入axios
import axios from 'axios';
const app = createApp(App);
//挂载全局属性
app.config.globalProperties.$axios = axios;
app.use(router).mount("#app");

在组件中使用

setup(){
    const{proxy} = getCurrentInstance();
    proxy.$axios.get();
}

vue3声明周期

Hook

Hook的本质就是一个函数,是对setup函数里面的组合式API进行封装,类似于Vue2中的mixin

选项式 API Hook inside setup
beforeCreate setup
created setup
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
renderTracked onRenderTracked
renderTriggered onRenderTriggered
activated onActivated
deactivated onDeactivated
import {onMounted} from 'vue'
<script>
    export default {
      name: 'Demo',
      setup() {
          // 可以在setup中直接写
          onMounted(() => {
              
          })
      }
    }
</script>

自定义hook

src/hooks/中新建一个js文件,将多组件复用的组合式API抽离,并将组件需要的属性返回即可

import {ref} from 'vue';
export default () => {
    //此处写组合式API的逻辑
    let name = ref('lucy');
    
    return name;
}

在需要该组合API的组件中引入并调用,一般函数名以use开头

import useName from '@/hooks/name.js';
<script>
    export default {
      name: 'Demo',
      setup() {
          // 在setup中调用,并接收参数
          let name = useName();
          return {name}
      }
    }
</script>

新增组件

Fragment

在vue2中,所有组件必须有跟标签

在vue3中,组件可以没有跟标签,所有元素在Fragment虚拟元素中

Teleport

可以将指定的html结构移动到指定位置

<template>
    <!-- 传送到body标签中 -->
    <teleport to="body">
        <input/>
    </teleport>
</template>

全局API变化

vue2 vue3
Vue.config.productionTip 移除
Vue.config.ignoredElements app.config.isCustomElement()
Vue.component app.component
Vue.directive app.directive
Vue.mixin app.mixin
Vue.use app.use()
Vue.filter 移除
Vue.prototype app.config.globalProperties

其他变化

1、移除v-on.native

2、由于vue3中setup没有this,所以获取ref的方法有所改变

<template>
  <input type="text" ref="inputRef">
</template>
<script>
import { onMounted, ref } from 'vue'
/*
    ref获取元素: 利用ref函数获取组件中的标签元素
    功能需求: 让输入框自动获取焦点
*/
export default {
  setup() {
    const inputRef = ref(null)
    onMounted(() => {
      inputRef.value.focus()
    })
    return {
      inputRef
    }
  },
}
</script>