• vue3.2的特性


    vue3.2的特性

    全局方法

    因为vue3不再有Vue构造函数,所以一些全局的自定义属性或者方法也没法通过Vue.prototype.xx挂在到vm实例上,这时候需要借助app.config.globalProperties来实现这一功能

    //如果项目采用了typescript,那么就需要扩展一下`@vue/runtime-core`模块,否则在使用的时候会报找不到$http属性
    //在main.ts加上如下代码
    declare module '@vue/runtime-core' {
      interface ComponentCustomProperties {
        $http: any;
      }
    }
    定义全局方法
    import { createApp } from 'vue'
    const app = createApp(App)
    app.config.globalProperties.$http = () => {
     //do something
    }
    
    使用全局方法
    import { getCurrentInstance } from 'vue'
    // getCurrentInstance必须在.vue文件中才获取得到
    const { proxy } = getCurrentInstance() as any
    console.log('proxy', proxy.$http )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    环境变量

    ## vue2.X
    process.env.VUE_APP_BASE_API
    ## vue3.2
    const href = import.meta.env.VITE_APP_CONSOLE_URL + path
    
    • 1
    • 2
    • 3
    • 4

    style v-bind

    // 定义颜色变量
    let stateStyle = reactive({
      color: 'red',
      fontSize: '20px'
    })
    
    function changeColor() {
      stateStyle.color = 'blue'
      stateStyle.fontSize = '30px'
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    响应式侦听

    computed是多对一的关系,而watch则是一对多的关系;vue3也提供了两个函数来侦听数据源的变化:watch和watchEffect。

    watch的使用

    监听单个的ref
    const  a = ref(0)
      watch(a,(newval,oldval)=>{
       console.log(newval,oldval)
      })
    
    • 1
    • 2
    • 3
    • 4
    监听多个ref
    const  b = ref(0)
      watch([a,b],(newval,oldval)=>{
       console.log(newval,oldval)
      })
    
    • 1
    • 2
    • 3
    • 4
    监听整个reactive
    const data = reactive({
       a:1,
       b:2,
       c:3
      })
      watch(data,(newVal,oldVal)=>{
       console.log(newVal,oldVal)
      })
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    监听reactive下的属性
      watch([()=>data.a,()=>data.b],(newVal,oldVal)=>{
       console.log(newVal,oldVal)
      })
    
    • 1
    • 2
    • 3
    侦听getter函数
    watch(
      () => state.count,
      (count, prevCount) => {
        // 1 0
        console.log(count, prevCount);
      }
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    侦听深度嵌套的对象属性

    侦听深度嵌套的对象属性变化时,需要设置deep:true

    注意⚠️

    侦听响应式对象始终返回该对象的引用,所以打印结果发现都是改变后的值。

    解决:对侦探的对象进行深拷贝

    import _ from "lodash";
    const deepObj = reactive({
      a: {
        b: {
          c: "hello",
        },
      },
    });
    
    watch(
      () => _.cloneDeep(deepObj),
      (val, old) => {
        // new hello hello
        console.log(val.a.b.c, old.a.b.c);
      },
      { deep: true }
    );
    
    deepObj.a.b.c = "new hello";
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    停止侦听

    一般侦听都会在组件销毁时自动停止,但是有时候我们想在组件销毁前手动的方式进行停止,可以调用watch返回的stop函数进行停止:

    const count = ref(0);
    
    const stop = watch(count, (count, prevCount) => {
      // 不执行
      console.log(count, prevCount);
    });
    
    setTimeout(()=>{
      count.value = 2;
    }, 1000);
    // 停止watch
    stop();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    watchEffect

    • watchEffect不需要手动传入依赖
    • 每次初始化时watchEffect都会执行一次回调函数来自动获取依赖
    • watchEffect无法获取到原值,只能得到变化后的值
    import { reactive, ref, watch, watchEffect } from "vue";
    
    const count = ref(0);
    const state = reactive({
      year: 2021,
    });
    
    watchEffect(() => {
      console.log(count.value);
      console.log(state.year);
    });
    setInterval(() => {
      count.value++;
      state.year++;
    }, 1000);
    
    // 分析: watchEffect会在页面加载时自动执行一次,追踪响应式依赖;在加载后定时器每隔1s执行时,watchEffect都会监听到数据的变化自动执行,每次执行都是获取到变化后的值。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    computed

    • computed接收一个函数,该函数的返回值作为计算属性的值。
    get函数
    • 需要的值依赖于其他值的状态,computed接受一个getter函数,并为getter返回的值创建了一个不可变的响应式ref对象
    const num = ref(0);
    const double = computed(() => num.value * 2);
    num.value++;
    // 2
    console.log(double.value);
    // Warning: computed value is readonly
    double.value = 4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    get和set函数

    可以使用get和set函数创建一个可读写的ref对象

    const num = ref(0);
    const double = computed({
      get: () => num.value * 2,
      set: (val) => (num.value = val / 2),
    });
    
    num.value++;
    // 2
    console.log(double.value);
    
    double.value = 8
    // 4
    console.log(num.value);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    案例

    
    
    
    
    
    • 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

    ref和reactive

    reactive主要负责复杂数据结构,而ref主要处理基本数据结构,但ref本身也是能处理对象和数组的:

    let book = reactive({
      name: 'Learn Vue',
      year: 2020,
      title: 'Chapter one'
    })
    
    
    
    // 1.会消除它的响应式
    let {
      name,
    } = book
    
    name = 'new Learn'
    // Learn Vue
    console.log(book.name);
     
     
     
    // 2.保存响应式
    let {
      name,
    } = toRefs(book)
    
    // 注意这里解构出来的name是ref对象
    // 需要通过value来取值赋值
    name.value = 'new Learn'
    // new Learn
    console.log(book.name);
    
    //3.通过readonly来创建一个只读的对象
    
    const copy = readonly(book);
    //Set operation on key "name" failed: target is readonly.
    copy.name = "new copy";
    
    
    • 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

    Teleport

    • Teleport翻译过来就是传送、远距离传送的意思;它可以将插槽中的元素或者组件传送到页面的其他位置:
    • Teleport一个常见的使用场景,就是在一些嵌套比较深的组件来转移模态框的位置。虽然在逻辑上模态框是属于该组件的,但是在样式和DOM结构上,嵌套层级后较深后不利于进行维护(z-index等问题);因此我们需要将其进行剥离出来:
    
    
    //解析: Teleport中的modal div就被传送到了body的底部;虽然在不同的地方进行渲染,但是Teleport中的元素和组件还是可以和父组件进行数据通信。Teleport接收两个参数to和disabled:
    
    to - string:必须是有效的查询选择器或 HTMLElement,可以id或者class选择器等。
    disabled - boolean:如果是true表示禁用teleport的功能,其插槽内容将不会移动到任何位置,默认false不禁用
    
    • 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

    Suspense

    作用:suspense在等待异步组件时额外渲染一些内容,使用户拥有更好的体验

    定义:是Vue3推出的一个内置组件,它允许我们的程序在等待异步组件时渲染一些后备的内容,可以让我们创建一个平滑的用户体验;Vue中加载异步组件其实在Vue2.x中已经有了,我们用的vue-router中加载的路由组件其实也是一个异步组件

    语法关键:提供了两个slot插槽,一个default默认,一个fallback加载中的状态:

    // 1.定义
    
    // 全局定义异步组件
    //src/main.js
    import { defineAsyncComponent } from "vue";
    const AsyncButton = defineAsyncComponent(() =>
      import("./components/AsyncButton.vue")
    );
    app.component("AsyncButton", AsyncButton);
    
    
    // 组件内定义异步组件
    // src/views/Home.vue
    import { defineAsyncComponent } from "vue";
    export default {
      components: {
        AsyncButton: defineAsyncComponent(() =>
          import("../components/AsyncButton")
        ),
      },
    };
    
    // 2.使用-定义异步加载的子组件
    export default {
      components: {
        AsyncButton: defineAsyncComponent({
          delay: 100,
          timeout: 3000,
          loader: () => import("../components/AsyncButton"),
          errorComponent: ErrorComponent,
          onError(error, retry, fail, attempts) {
            if (attempts <= 3) {
              retry();
            } else {
              fail();
            }
          },
        }),
      },
    };
    
    // 3.使用异步加载的子组建
    
    
    
    • 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

    Fragment

    所谓的Fragment,就是片段;在vue2.x中,要求每个模板必须有一个根节点,在Vue3中我们可以直接不需要根节点

    API 改变

    sync修饰符

    .sync修饰符 => v-model:propName

    data、mixin和filter

    • 在Vue3中,data只接受function类型,通过function返回对象;同时Mixin的合并行为也发生了改变,当mixin和基类中data合并时,会执行浅拷贝合并
    • vue3只进行浅层拷贝,对data中数据发现已存在就不合并拷贝。
    • 在vue3中,过滤器filter已经删除,不再支持了,官方建议使用方法调用或者计算属性computed来进行代替。
    const Mixin = {
      data() {
        return {
          user: {
            name: 'Jack',
            id: 1,
            address: {
              prov: 2,
              city: 3,
            },
          }
        }
      }
    }
    const Component = {
      mixins: [Mixin],
      data() {
        return {
          user: {
            id: 2,
            address: {
              prov: 4,
            },
          }
        }
      }
    }
    
    // vue2结果:
    {
      id: 2,
      name: 'Jack',
      address: {
        prov: 4,
        city: 3
      }
    }
    
    // vue3结果:
    user: {
      id: 2,
      address: {
        prov: 4,
      },
    }
    
    • 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

    v-for和key

    在Vue3中,key值应该被放置在template标签上

    bind合并

    在vue3中,如果一个元素同时定义了v-bind="object"和一个相同的单独的属性,那么声明绑定的顺序决定了最后的结果(后者覆盖前者)

    在vue2.x中,如果一个元素同时定义了v-bind="object"和一个相同的单独的属性,那么这个单独的属性会覆盖object中的绑定

    // vue2.x
    
    // vue3.x
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    for中ref

    vue2.x中,在v-for上使用ref属性,通过this.$refs会得到一个数组:

    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    vue3不再自动创建数组,而是将ref的处理方式变为了函数,该函数默认传入该节点:

    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    v-for和v-if优先级

    在vue3中,v-if比v-for有更高的优先级。因此下面的代码,在vue2.x中能正常运行,但是在vue3中v-if生效时并没有item变量,因此会报错:

    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    参考

    官方文档——内置指令

    官方文档——内置组件

    官方文档——SFC 语法定义

    官方文档——单文件组件 CSS 功能

    官方文档——响应式 API:核心

    官方文档——响应式 API:工具函数

  • 相关阅读:
    Jetsonnano B01 笔记7:Mediapipe与人脸手势识别
    eyb:RubbitMQ学习2
    带头双向循环链表
    Spring MVC响应处理
    巨噬细胞膜包裹PLGA纳米粒HCPT-MCNP/MCF-7细胞膜包覆PLGA纳米球共载姜黄素和二氢卟吩e6的研究
    ZYNQ之简易流水灯(EMIO、AXI GPIO)
    NLP(20)--知识图谱+实体抽取
    java: 错误: 无效的源发行版:17 【解决】
    创邻科技再获人行旗下《金融电子化》2023年度大奖
    go的爬虫工具教你如何去翻译(go调用js,colly的使用)
  • 原文地址:https://blog.csdn.net/qq_38918953/article/details/128136421