• 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    子组件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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    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">点击增加agebutton>h2>
      <h2>info.hobby:{{info.hobby}}h2>
      <h2>info.address:{{info.address}}h2>
      <h2>updateInfo:<button @click="updateInfo">点击修改infobutton>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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    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">点击修改infobutton>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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    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 }}
        
        <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    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 }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    App.vue:

    <template>
      <h3>Mouse position is at: {{ x }}, {{ y }}h3>
    template>
    
    <script setup>
    import {useMouse} from "./hooks/useMouse"
    const {x,y} = useMouse();
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    其他组合式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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    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>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 父: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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 孙: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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    新的组件

    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 Teleporth3>
        <div>
          <MyModal />
        div>
      div>
    template>
    
    <script setup>
    import MyModal from './components/15/MyModal.vue';
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • MyModal.vue
    <template>
        <button @click="open = true">Open Modalbutton>
    
        <Teleport to="body">
            <div v-if="open" class="modal">
                <p>Hello from the modal!p>
                <button @click="open = false">Closebutton>
            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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • App.vue
    <template>
        <h3>
            我是子组件!!!
        h3>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    vue2 -> vu3 的其他变化:

    全局API转移:

    在这里插入图片描述

    其他变化

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

  • 相关阅读:
    Docker Compose安装milvus向量数据库单机版-milvus基本操作
    利用procrank和lsof定位出客户软件内存OOM的问题
    MySQL之账号管理、建库以及四大引擎
    Clion 搭建Qt projects
    Linux 应用领域
    「Redis数据结构」列表对象(List)
    字符串压缩(一)之ZSTD
    【Go】十九、网络连接与请求发送
    bpmnjs开始的时间事件和中间事件的时间
    Ps:选框工具
  • 原文地址:https://blog.csdn.net/m0_55155505/article/details/127657968