vue3基础

在这里插入图片描述

文档

尚硅谷视频:https://www.bilibili.com/video/BV1Zy4y1K7SH?p=136
官方文档:https://cn.vuejs.org/guide/introduction.html

本文每小节先总结,之后上案例。

setup

总结

  1. 理解: vue3.0中一个新的配置项,值为一个函数

  2. setup是所有composition API(组合API)“表演的舞台”。

  3. 组件中所用到的:数据、方法等等,均要配置在setup中。

  4. setup函数的两种返回值:

    1. 返回一个对象,则对象中的属性、方法,在模板中均可以直接使用。(重点关注! )
    2. 若返回一个渲染函数:则可以自定义渲染内容。(了解)
  5. 执行时机:在beforCreate之前执行一次,此时this是undefined

  6. 参数

    1. props:值为对象,组件外部传过来,且组件内部props申明接收了的属性;
    2. context:上下文对象:
      • attrs:值为对象,父组件传递过来,但没在内部props中声明接收的属性;相当于this.$attrs
      • slots:收到的插槽内容;相当于this.$slots
      • emit:分发自定义事件的函数,相当于this.$emit
  7. 注意点:

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

基本使用

基本使用如下图:(以下方式是非响应式的,响应式需借助ref、reactive等函数)
在这里插入图片描述

完整代码:

<template>
  <h2>name:{
   
   {name}}</h2>
  <h2>age:{
   
   {age}}</h2>
  <h2>sayHello:<button @click="sayHello">点击在控制台打印</button></h2>
</template>

<script>
import {
      
      ref} from "vue"
export default {
      
      
  setup(){
      
      
    //数据
    let name = "ljy";
    let age = ref(18);
    //方法
    function sayHello(){
      
      
      console.log(`你好啊,我是${ 
        name}`)
    }
    //返回一个对象
    return {
      
      
      name,
      age,
      sayHello,
    }
  }
}
</script>

setup的参数

在这里插入图片描述

完整代码如下:
父组件App.vue:

<template>
  <school msg="欢迎光临" name="张三" @myEvent="myEvent">
    <!-- 用于测试子组件接收插槽内容 -->
    <template v-slot:slot1>
      <span>插槽内容...</span>
    </template>
  </school>
</template>

<script>
import School from './components/School.vue'
export default {
      
      
  components: {
      
       School },
  beforeCreate() {
      
      
    console.log("beforeCreate");
  },
  setup() {
      
      
    //用于测试setup在beforeCreate之前,且this为undefined
    console.log("setup");

    return {
      
      
      //用于子组件触发自定义事件
      myEvent() {
      
      
        alert('触发MyEvent事件')
      }
    }
  }
}
</script>

子组件School.vue

<template>
  <button @click="onclick">点我触发myEvent事件</button>
</template>

<script>
export default {
      
      
    emits:["myEvent"],
    props:["msg"],
    setup(props,context){
      
      
        //测试setup的参数:
        console.log("props",props);//属性是props接收的
        console.log("attrs",context.attrs);//父组件传了,但props没接收的(捡漏)
        console.log("slots",context.slots);//父组件定义的插槽信息
        console.log("emit",context.emit);//父组件绑定的事件

        return{
      
      
            //点击后,触发父组件中的myEvent事件:
            onclick(){
      
      
                context.emit("myEvent")
            }
        }
    }
}
</script>

<style>

</style>

ref函数

总结:

  • 作用: 定义一个响应式的数据

  • 语法:const xxx = ref(初始值);

    • 创建一个包含响应式数据的引用对象(reference对象,简称ref对象)
    • JS中操作数据:xxx.value
    • 模板中读取数据:不需要写.value,直接{ { xxx }}即可
  • 备注:

    • 接收的数据可以是:基本类型,也可以时对象类型
    • 基本类型数据:响应式依然靠 Object.defineProperty() 的 get 与 set完成的
    • 对象类型数据:内部“求助”Vue3中的一个新函数 – reactive函数

例子:

如果想要定义一个响应式的值(例如,age),可通过如下方式:

  • 基本类型:
    在这里插入图片描述
  • 对象:(实际借助了reactive函数)
    在这里插入图片描述

完整代码:

<template>
  <h2>name:{
   
   {name}}</h2>
  <h2>age:{
   
   {age}}</h2>
  <h2>sayHello:<button @click="sayHello">点击在控制台打印</button></h2>
  <h2>incrementAge:<button @click="incrementAge">点击增加age</button></h2>
  <h2>info.hobby:{
   
   {info.hobby}}</h2>
  <h2>info.address:{
   
   {info.address}}</h2>
  <h2>updateInfo:<button @click="updateInfo">点击修改info</button></h2>
</template>

<script>
import {
      
      ref} from "vue"
export default {
      
      
  setup(){
      
      
    //数据
    let name = "ljy";
    let age = ref(18);
    let info = ref({
      
      
      hobby:"电影",
      address:"西安"
    });
    //方法
    function sayHello(){
      
      
      console.log(`你好啊,我是${ 
        name}`)
    }
    function incrementAge(){
      
      
      age.value++;
    }
    function updateInfo(){
      
      
      info.value.hobby = "vue";
      info.value.address = "上海";
    }
    //返回一个对象
    return {
      
      
      name,
      age,
      sayHello,
      incrementAge,
      info,
      updateInfo,
    }
  }
}
</script>

reactive函数

总结:

  • 作用:定义一个对象类型的响应式数据(基本数据类型不要用它,要用 ref 函数)
  • 语法:const 代理对象 = reactive(源对象) 接收一个对象(或数组),返回一个代理对象(Proxy对象)
  • reactive定义的响应式数据是“深层次的”
  • 内部基于ES6中的Proxy实现,通过代理对象操作源对象内部数据进行操作

基本使用

在这里插入图片描述

完整代码:

<template>
  <h2>info.hobby:{
   
   {info.hobby}}</h2>
  <h2>info.address:{
   
   {info.address}}</h2>
  <h2>updateInfo:<button @click="updateInfo">点击修改info</button></h2>
</template>

<script>
import {
      
      reactive} from "vue"
export default {
      
      
  setup(){
      
      
    //数据
    let info = reactive({
      
      
      hobby:["音乐","视频"],
      address:"西安"
    });
    //尝试修改数据
    function updateInfo(){
      
      
      //改数组
      info.hobby[0] = "学习",
      //改属性
      info.address = "上海"
    }

    return {
      
      
      info,
      updateInfo,
    }
  }
}
</script>

computed计算属性

总结:

  • 与|vue2中的computed配置功能一致
  • 写法:
    在这里插入图片描述

例子:

在这里插入图片描述

完整代码:

<template>
  <h2>firstName:<input type="text" v-model="firstName"></h2>
  <h2>lastName:<input type="text" v-model="lastName"></h2>
  <h2>fullName:{
   
   { fullName }}</h2>
  <h2>set fullName:<input type="text" v-model="setFullName"></h2>
</template>

<script setup>
import {
      
       ref, computed } from "vue";

const firstName = ref("张");
const lastName = ref("三")

//计算属性的简写:
const fullName = computed(() => {
      
      
  return firstName.value + "-" + lastName.value;
})

//计算属性的get、set
const setFullName = computed({
      
      
  get() {
      
      
    return firstName.value + "-" + lastName.value;
  },
  set(newVal) {
      
      
    const index = newVal.indexOf("-");
    firstName.value = newVal.substring(0, index);
    lastName.value = newVal.substring(index + 1);
  }
})
</script>

watch侦听器

总结:

  • 与vue2.x中watch配置功能一致
  • 两个小坑:
    • 监视reactive定义的响应式数据时,oldVal无法正常获取、强制开启了深度监视(deep配置失效)
    • 监视reactive定义的响应式数据中的某个属性时,deep配置有效
  • 关于监视ref定义的对象是否使用.value的问题:
    • 监视基本数据类型不用.value,因为使用.value就取出了实际值,无法监视
      在这里插入图片描述
    • 监视一个对象,需要用.value,因为此时的.value是一个由reactive生成的Proxy对象;如果此时不使用.value,则需要配置deep:true
      在这里插入图片描述

基本使用:

监视ref定义的响应式数据:

js:
在这里插入图片描述
html:
在这里插入图片描述
效果:
在这里插入图片描述


监视reactive定义的响应式数据:

js:
在这里插入图片描述
html:
在这里插入图片描述
效果:
在这里插入图片描述


监视reactive定义的响应式数据的某些属性:

js:
在这里插入图片描述
html:
在这里插入图片描述
效果:
在这里插入图片描述

完整代码:

<template>
  <h3>num1:{
   
   { num1 }}<button @click="num1++">点我num1++</button></h3>
  <h3>num2:{
   
   { num2 }}<button @click="num2++">点我num2++</button></h3>
  <h3>sum:{
   
   { num1 + num2 }}</h3>
  <hr>
  <h2>cat:</h2>
  <h3>name:{
   
   { cat.name }}<button @click="cat.name += '~'">点我修改</button></h3>
  <h3>age:{
   
   { cat.age }}<button @click="cat.age++">点我修改</button></h3>
  <h3>friend.name:{
   
   { cat.friend.name }}<button @click="cat.friend.name += '-'">点我修改</button></h3>
  <hr />
  <h2>person:</h2>
  <h3>name:{
   
   { person.name }}<button @click="person.name += '~'">点我修改</button></h3>
  <h3>pass:{
   
   { person.pass }}<button @click="person.pass += '*'">点我修改</button></h3>
  <h3>age:{
   
   { person.age }}<button @click="person.age++">点我修改</button></h3>
  <h3>car.color:{
   
   { person.car.color }}
    <!-- 切换color的颜色: -->
    <button @click="person.car.color = (person.car.color == 'red' ? 'blue' : 'red')">点我修改</button>
  </h3>
</template>

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

//---------------------
//监视ref定义的数据:
var num1 = ref(1);
var num2 = ref(1);
var sum = num1 + num2;
//监视一个:
watch(num1, (newVal, oldVal) => {
      
      
  console.log(`num1由${ 
        oldVal}变成了${ 
        newVal}`)
})
//监视多个:
watch([num1, num2], (newVal, oldVal) => {
      
      
  console.log("num1或num2发生了改变:", newVal, oldVal);
  sum = newVal[0] + newVal[1];
})
//--------------------------
//监视reactive定义的数据:
var cat = reactive({
      
      
  name: "tom",
  age: 2,
  friend: {
      
      
    name: "tom2"
  }
})
//oldVal无效,和newVal相同;deep配置无效;
watch(cat, (newVal, oldVal) => console.log("cat发生变化:", newVal, oldVal));

//---------------------
//监视reactive定义的数据中的某些属性,此时oldVal、deep均有效
var person = reactive({
      
      
  name: "张三",
  pass: "1234",
  age: 18,
  car: {
      
      
    color: "red"
  }
})
//监视一个
watch(() => person.name, (newVal, oldVal) => {
      
      
  console.log("person.name发生变化;", newVal, oldVal);
})
//监视多个:
watch([() => person.pass, () => person.age], (newVal, oldVal) => {
      
      
  console.log("person的pass或age发生变化;", newVal, oldVal);
})
//测试deep是否有效:(一会修改car的color,但监视color)
watch(() => person.car, (newVal) => {
      
      
  //如果修改person.car.color,该句话不会被打印!
  console.log("检测到person.car发生变化(未配置deep)");
})
watch(() => person.car, (newVal) => {
      
      
  console.log("检测到person.car发生变化(配置deep为true)");
}, {
      
      
  deep: true
})
</script>

watchEffect监视

总结:

  • watch的套路是:既要指明监视的属性,也要指明监视的回调
  • watchEffect的套路是:不用指明监视哪个属性,监视回调中用到哪个属性,就监视哪个属性
  • watchEffect和computed有点像:
    • computed注重计算出来的值(回调的返回值),所以必须要写返回值
    • watchEffect注重过程(回调的函数体),所以不用写返回值

例子:

在这里插入图片描述

完整代码:

<template>
  <h3>price:{
   
   { price }}<button @click="price++">点我price++</button></h3>
  <h3>count:{
   
   { count }}<button @click="count++">点我count++</button></h3>
  <h3>total:{
   
   { total }}</h3>
</template>

<script setup>
import {
      
       ref, watchEffect} from "vue";
//单价
var price = ref(10);
//数目
var count = ref(10);
//总价
var total = ref(0);

//监视:
watchEffect(() => {
      
      
  total.value = price.value * count.value;
})
</script>

hook函数

在这里插入图片描述

总结:

  • 本质是一个函数,把setup函数中使用的Composition API进行封装
  • 类似于vue2.x中的mixin
  • 自定义hook的优势:复用代码,让setup中的逻辑更清楚易懂

例子:

hooks目录下useMouse.js:
在这里插入图片描述
使用:
在这里插入图片描述

完整代码:

useMouse.js:

// mouse.js
import {
    
     ref, onMounted, onUnmounted } from 'vue'

// 按照惯例,组合式函数名以“use”开头
export function useMouse() {
    
    
  // 被组合式函数封装和管理的状态
  const x = ref(0)
  const y = ref(0)

  // 组合式函数可以随时更改其状态。
  function update(event) {
    
    
    x.value = event.pageX
    y.value = event.pageY
  }

  // 一个组合式函数也可以挂靠在所属组件的生命周期上
  // 来启动和卸载副作用
  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))

  // 通过返回值暴露所管理的状态
  return {
    
     x, y }
}

App.vue:

<template>
  <h3>Mouse position is at: {
   
   { x }}, {
   
   { y }}</h3>
</template>

<script setup>
import {
      
      useMouse} from "./hooks/useMouse"
const {
      
      x,y} = useMouse();
</script>

toRef和toRefs:

总结:

  • 作用:创建一个ref对象,其value值指向另一个对象的某个属性
  • 语法:const name = toRef(person,'name;)
  • 应用:要将响应式对象的某个属性单独供给给外部使用
  • 扩展:toRefs与toRef功能一致,但是可以批量创建多个ref对象,语法:toRefs(person),类似于对person的所有属性使用toRef()

例子:

在这里插入图片描述

完整代码:

<template>
  <h3>person:{
   
   { person }}</h3>
  <hr>
  <h3>pName:{
   
   { pName }}<button @click="pName += '~'">点击修改</button></h3>
  <h3>jobName:{
   
   { jobName }}<button @click="jobName += '~'">点击修改</button></h3>
  <hr />
  <h3>name:{
   
   { name }}<button @click="name += '~'">点击修改</button></h3>
  <h3>age:{
   
   { age }}<button @click="age += '~'">点击修改</button></h3>
  <h3>job:{
   
   { job }}</h3>
</template>

<script setup>
import {
      
       reactive, toRef, toRefs } from "vue"
var person = reactive({
      
      
  name: "张三",
  age: 18,
  job: {
      
      
    name: "开发工程师",
    address: "西安"
  }
});

//使用toRef定义一个:
var pName = toRef(person, "name");
var jobName = toRef(person.job, "name");
//使用toRefs定义多个
var {
      
       name, age, job } = toRefs(person)
</script>

其他组合式API

shallowReactive 与 shallowRef

总结:

  • shallowReactive:只处理对象最外层属性的响应式(浅响应式)
  • shallowRef:只处理基本类型的响应式,不进行对象的响应式处理
  • 什么时候用?
    • 如果有一个对象数据比较深,但变化时知识外层属性变化,则使用shallowReactive
    • 如果一个对象数据,后续功能不会修改该对象的属性,而是生成新的对象来替换,则使用shallowRef

例子:
在这里插入图片描述

完整代码:

<template>
  <h3>person:{
   
   { person }}</h3>
  <h3>pName:{
   
   { pName }}<button @click="pName += '~'">点击修改</button></h3>
  <h3>jobName:{
   
   { jobName }}<button @click="jobName += '~'">点击修改</button></h3>
  <hr>
  <h3>
    cat name:{
   
   { cat.name }}
    <button @click="cat.name += '~'">点击修改</button>
    <button @click="replaceCat">点击替换</button>
  </h3>
</template>

<script setup>
import {
      
       shallowReactive, shallowRef, toRef } from "vue"
//-------------------
//使用shallowReactive,则不会监视第二层的job.name
var person = shallowReactive({
      
      
  name: "张三",
  job: {
      
      
    name: "开发工程师",
  }
});

var pName = toRef(person, "name");
var jobName = toRef(person.job, "name");

//-------------------
//使用shallowRef,传的对象不会被reactive加工;只有当cat.value改变,才能被vue监视到
var cat = shallowRef({
      
      
  name: "tom"
})
//替换一只猫
function replaceCat() {
      
      
  cat.value = {
      
      
    name: "new tom"
  }
}
</script>

readonly 与 shallowReadonly

总结:

  • readonly:让一个响应式数据变为只读的(深只读)
  • shallowReadonly:让一个响应式数据变成只读的(浅只读)
  • 应用场景:不希望数据被修改

例子:
在这里插入图片描述

完整代码:

<template>
  <h3>person:{
   
   { person }}</h3>
  <h3>pName:{
   
   { pName }}<button @click="pName += '~'">点击修改</button></h3>
  <h3>jobName:{
   
   { jobName }}<button @click="jobName += '~'">点击修改</button></h3>
  <hr>
  <h3>person2:{
   
   { person2 }}</h3>
  <h3>pName2:{
   
   { pName2 }}<button @click="pName2 += '~'">点击修改</button></h3>
  <h3>jobName2:{
   
   { jobName2 }}<button @click="jobName2 += '~'">点击修改</button></h3>
  <hr>
</template>

<script setup>
import {
      
       reactive, readonly, shallowReadonly, toRef } from "vue"
//-------------------
//使用readonly,所有数据都不让改!
var person = reactive({
      
      
  name: "张三",
  job: {
      
      
    name: "开发工程师",
  }
});
person = readonly(person)
var pName = toRef(person, "name");
var jobName = toRef(person.job, "name");

//-----------------------
//使用shallowReadonly,只有第一层数据不让改,该例中job.name依然能改!
var person2 = reactive({
      
      
  name: "李四",
  job: {
      
      
    name: "教师",
  }
});
person2 = shallowReadonly(person2)
var pName2 = toRef(person2, "name");
var jobName2 = toRef(person2.job, "name");

</script>

toRaw 与 markRaw

总结:

  • toRaw:
    • 作用:将一个reactive生成的响应式对象转为普通对象
    • 使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面的更新
  • markRaw:
    • 作用:标记一个对象,使其永远不会再成为响应式对象
    • 应用场景:
      1. 有些值不应该设置为响应式的,例如:复杂的第三方类库等
      2. 当渲染有不可变数据源的大列表时,跳过响应式转换可以提高性能

例子:
在这里插入图片描述

完整代码:

<template>
  <h3>person: {
   
   { person }}</h3>
  <h3>person name:{
   
   { person.name }}<button @click="person.name += '~'">点击修改</button></h3>
  <hr>
  <h3>person toRaw: {
   
   { pToRaw }}</h3>
  <h3>person toRaw 的 name:{
   
   { pToRaw.name }}<button @click="updatePToRawName">点击修改</button></h3>
  <hr>
  <div v-if="person.job">
    <h3>person.job.name:{
   
   { person.job.name }}<button @click="updatePersonJobName">点击修改</button></h3>
  </div>
</template>

<script setup>
import {
      
       markRaw, reactive, toRaw } from "vue"
var person = reactive({
      
      
  name: "张三",
});

//使用toRaw,返回指定响应式对象的普通对象,此时,我们普通对象的属性值,不会造成页面的变化
var pToRaw = toRaw(person);
function updatePToRawName() {
      
      
  pToRaw.name += "-";
  console.log(`pToRaw.name 被改成了: ${ 
        pToRaw.name}`);//证明数据确实被改了,只是不是响应式的数据
}

//使用markRaw标记一个对象,使其永远不会作为响应式数据
var job = markRaw({
      
      
  name:"工程师"
});
person.job = job;//给person添加新属性,如果没使用markRaw,则添加的属性也是响应式的
function updatePersonJobName(){
      
      
  person.job.name += "-";
  console.log(`person.job.name 被改成了: ${ 
        person.job.name}`);//证明数据确实被改了,只是不是响应式的数据
}
</script>

customRef

总结:

  • 作用:创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显式控制

例子:
在这里插入图片描述

完整代码:

<template>
  <input type="text" v-model="name">
  <h3>name:{
   
   { name }}</h3>
</template>

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

function myRef(value, delay = 200) {
      
      
  let timeout;//用于清除定时器
  return customRef((track, trigger) => {
      
      
    return {
      
      
      //当获取该值时
      get() {
      
      
        track();//追踪value的变化,当value变化时重新解析模板
        return value;
      },
      //当更新该值时,延迟更新模板
      set(newValue) {
      
      
        clearTimeout(timeout);//清除定时器
        timeout = setTimeout(() => {
      
      
          value = newValue;
          trigger();//通知vue重新解析模板
        }, delay)
      }
    }
  })
}
var name = myRef("张三");
</script>

Provide 与 Inject

在这里插入图片描述
总结:

  • 作用:实现祖与后代组件间通信
  • 套路:父组件有一个provide选项用来提供数据,后代组件有一个inject用来使用这些数据

例子:

  • provide:(App.vue中)
    在这里插入图片描述

  • inject:(DeepChild.vue中)
    在这里插入图片描述

  • 效果:
    在这里插入图片描述

完整代码:

  • 祖:App.vue
<template>
  <div>
    我是App(祖)
    <h3>cat:{
   
   {  cat  }}</h3>
    <Footer></Footer>
  </div>

</template>

<script>
import {
      
       provide, reactive } from "vue"
import Footer from "./components/13/Footer.vue"
export default {
      
      
  components: {
      
       Footer },
  setup() {
      
      
    var cat = reactive({
      
      
      name: "tom",
      color: "black"
    });
    //向下层组件提供数据
    provide("cat", cat);
    return {
      
       cat };
  }
}
</script>

<style scoped>
div {
      
      
  border: 2px red solid;
}
</style>
  • 父:Footer .vue
<template>
    <div>
        我是Footer(父)
        <DeepChild></DeepChild>
    </div>
</template>

<script>
import DeepChild from "./DeepChild.vue"
export default {
      
      
    components: {
      
       DeepChild }
}
</script>

<style scoped>
div {
      
      
    border: 2px red solid;
    margin: 10px;
}
</style>
  • 孙:DeepChild.vue
<template>
    <div>
        我是DeepChild(孙)
        <h3>cat:{
   
   { cat }}</h3>
    </div>
</template>
  
<script>
import {
      
       inject } from '@vue/runtime-core'
export default {
      
      
    setup() {
      
      
        //接收上层组件传过来的值
        var cat = inject("cat");
        return {
      
       cat };
    }
}
</script>
  
<style scoped>
div {
      
      
    border: 2px red solid;
    margin: 10px;
}
</style>

isXxx

总结:

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

例子:
在这里插入图片描述

完整代码:

<template>
  <pre>
      <code>
        var num = ref(0);
        var b1 = isRef(num);
        b1:{
   
   { b1 }}

        var person = reactive({name:"张三"});
        var b2 = isReactive(person);
        b2:{
   
   { b2 }}

        var p = readonly(person);
        var b3 = isReadonly(p);
        b3:{
   
   { b3 }}

        var b4 = isProxy(person);
        var b5 = isProxy(p);
        b4:{
   
   { b4 }}
        b5:{
   
   { b5 }}
      </code>
  </pre>

</template>

<script setup>
import {
      
       isProxy, isReactive, isReadonly, isRef, reactive, readonly, ref } from 'vue';

var num = ref(0);
var b1 = isRef(num);

var person = reactive({
      
       name: "张三" });
var b2 = isReactive(person);

var p = readonly(person);
var b3 = isReadonly(p);

var b4 = isProxy(person);
var b5 = isProxy(p);
</script>

新的组件

Fragment

总结:

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

Teleport

官网:https://cn.vuejs.org/guide/built-ins/teleport.html
在这里插入图片描述

总结:

  • Teleport 是一种能将我们的组件html结构移动到指定位置的技术
  • to 的值可以是一个 CSS 选择器字符串,也可以是一个 DOM 元素对象。如: to="body"的作用就是告诉 Vue“把模板片段传送到 body 标签下”。

例子:

  • MyModal.vue中使用Teleport将组件移动到html的body中:
    在这里插入图片描述

完整代码:

  • App.vue
<template>
  <div class="outer">
    <h3>Tooltips with Vue 3 Teleport</h3>
    <div>
      <MyModal />
    </div>
  </div>
</template>

<script setup>
import MyModal from './components/15/MyModal.vue';
</script>
  • MyModal.vue
<template>
    <button @click="open = true">Open Modal</button>

    <Teleport to="body">
        <div v-if="open" class="modal">
            <p>Hello from the modal!</p>
            <button @click="open = false">Close</button>
        </div>
    </Teleport>
</template>
  
<script setup>
import {
      
       ref } from 'vue'

const open = ref(false)
</script>

<style scoped>
.modal {
      
      
    position: fixed;
    z-index: 999;
    top: 20%;
    left: 50%;
    width: 300px;
    margin-left: -150px;
}
</style>

Suspense

总结:

  • 等待异步组件时渲染一些额外内容,让应用有更好的体验;

  • 使用步骤:

    1. 异步引入组件
      在这里插入图片描述

    2. 使用Suspense包裹组件,并配置default(要显示哪个组件)与fallback(如果要显示的组件没加载完成,显示的内容)
      在这里插入图片描述

例子:

  • 使用Suspense标签:
    在这里插入图片描述
  • 把网络调成慢速3G,当子组件Child未加载出来的时候,显示正在加载...字样

在这里插入图片描述

  • 过一段事件,才显示Child组件中的内容:
    在这里插入图片描述
    这是子组件Child中的内容:
    在这里插入图片描述

完整代码:

  • App.vue
<template>
  <div class="outer">
    <h3>我是父组件!!!</h3>
    <Suspense>
      <!-- 主要内容 -->
      <template v-slot:default>
        <Child></Child>
      </template>

      <!-- 加载中状态 -->
      <template v-slot:fallback>
        正在加载...
      </template>
    </Suspense>
  </div>
</template>

<script setup>
import {
      
       defineAsyncComponent } from "@vue/runtime-core"
var Child = defineAsyncComponent(() => import("./components/16/Child.vue"))
</script>
  • App.vue
<template>
    <h3>
        我是子组件!!!
    </h3>
</template>

vue2 -> vu3 的其他变化:

全局API转移:

在这里插入图片描述

其他变化

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_55155505/article/details/127657968