美文网首页
Vue3新的api

Vue3新的api

作者: 欢西西西 | 来源:发表于2023-05-08 18:08 被阅读0次

    1. composition api

    1.1 data → ref / reactive

    refreactive使得我们主动去包装那些会修改的数据,不变的则将原始对象交给模板;在Vue2中,为了能在模板中使用一些数据,我们通常将那些不变的数据也放在data里面,而Vue默认会为这些数据做响应式,所以就有了Object.freeze()这种优化手段。而这个问题在Vue3中就不用担心了

    import { ref, reactive } from "vue";
    const type = ref("order"); 
    const pageInfo = reactive({
      pageIndex: 0,
      pageSize: 20,
    });
    
    // methods:直接声明成一个函数
    const change = function (e, num) {
      pageInfo.pageSize = num;
      type.value = "task"; // ref包装的在读取时要使用.value,在模板中不需要
    };
    

    ref包装原始类型,会被包装成一个RefImpl实例,劫持value属性。用reactive包装引用类型,返回一个Proxy代理对象

    image.png
    image.png
    image.png

    1.2 props

    • options写法
    export default {
      props: {
        pageType: {
          type: String,
          default: "task",
        },
        taskList: {
          type: Array,
          default: () => [{}, {}],
        },
      },
    };
    
    • 在组合式setup函数中,props也需要选项式定义,并且在setup的第一个参数接收
    • <script setup>中,defineProps不需要手动引入,且不能重复调用
    // 如果仅在模板中使用props,可以不用接收defineProps的返回值
    defineProps({
      pageType: {
        type: String,
        default: "task",
      },
      taskList: {
        type: Array,
        default: () => [{}, {}],
      },
    });
    
    // 如果需要在js中使用props,则接收defineProps的返回值
    const props = defineProps(["pageType"]);
    console.log(props.pageType)
    

    1.3 computed方法

    import { reactive, computed } from "vue";
    const person = reactive({firstName: '张', lastName: '三'})
    person.fullname = computed(() => person.firstName + person.lastName);
    

    1.4 watch

    image.png
    • watch一个ref


      image.png
    • watch一个响应式对象(监听整个对象的话,无法拿到正确的oldValue)

    import { reactive, watch } from "vue";
    const pageInfo = reactive({
      pageIndex: { value: 0 },
      pageSize: 20,
    });
    watch(pageInfo, () => { // 深层监听,内部变化都会触发
      console.log("pageInfo发生变化", pageInfo);
    });
    
    • 如果只需要监听对象的某一个属性,需要用一个返回该属性的 getter 函数
    watch(
      () => pageInfo.pageIndex.value, 
      () => {
        console.log("pageInfo发生变化", pageInfo);
      }
    );
    
    • watchEffect简写 ↓
    import { watchEffect } from "vue";
    watchEffect(() => {
      console.log("type变化", type.value, pageInfo.pageSize);
    });
    
    // 发现甚至没有传我要watch谁,vue会自动跟踪回调的响应式依赖(你用谁我就监视谁)
    // 也就是type.value 和 pageInfo.pageSize变化时都会执行该回调
    // watchEffect的immediate为true
    
    有点像computed,初始执行一次,依赖值改变时再执行一次
    computed注重返回值。watchEffect注释过程
    
    • watchEffect的好处
      对于有多个依赖项的侦听器来说,避免多次使用watch来侦听
      watchEffect() 将只跟踪回调中被使用到的属性,而不是像深度跟踪器一样递归跟踪所有的属性

    1.5 自定义指令

    • options中需要声明directives选项
    export default {
        directives: {
            focus: (el) => { el.focus(); }
        }
    };
    
    • <script setup>中使用命名方式来确定一个自定义指令
    const vFocus = (el) => { // 类型可以是函数也可以是对象,对象的话可以配置指令的各个钩子
      el.focus(); 
    };
    
    // 只看代码的话会觉得这怎么就是个自定义指令呢?
    // Vue定义的:<script setup> 中
    // 靠命名来判定它是一个自定义指令:1: 变量以 v 开头  2: 驼峰式命名
    
    // 那么假如我不知道这个规则,刚好这样命名了一个变量,值为原始类型?
    结果是:不会报错,不过也没有什么效果罢了
    
    指令钩子
    bind  -》 beforeMount 指令与元素成功绑定
    inserted -》 mounted 指令所在元素插入页面时 
    update -》updated  父节点和子节点更新后调用
    
    指令定义为函数类型时,默认钩子是:
    ——在Vue3中:mounted 和 updated
    ——在vue2中是:bind 和 update
    

    2. setup选项:

    setup是一个函数,需要有一个返回值(<script setup>则不需要返回值)

    • 当返回值是一个对象,则对象属性都能用于模板中
    • 也可以返回一个渲染函数,则忽略模板中的内容

    但不能是一个async函数。唯一可以使用 async setup() 的情况是,该组件是 Suspense 组件的后裔。

    setup中不包含对组件实例的访问权,它的执行执行时机在beforeCreate之前。
    在 <script setup> 中创建的变量不会作为属性添加到组件实例中,这使得它们无法从选项式 API 中访问。如果是setup函数的返回值,则会添加,选项式API中可访问

    setup函数收到的2个参数

    image.png

    3. toRef和toRefs

    将响应式对象的某个属性交给另一个变量去使用时,不想丢失响应式。

    image.png image.png image.png

    4. shallowReactive和shallowRef

    只对对象的根级别属性做响应式

    • shallowReactive


      image.png
    image.png
    • shallowRef


      image.png

    5. toRaw

    返回代理对象的原对象。代理对象和原对象的联系:

    1. 一个是在reactiveMap中保存了这种关联关系(类型是WeakMap,key是原对象,value是代理对象)
    2. 一种是在new Proxy时配置的getter函数内部,可以同时访问到原对象和代理对象的引用
    • readonly包装一个reactive生成的响应式对象,再对它进行toRaw,结果还是最初的原始对象。所以toRaw并不是简单读取这个响应式对象上的__v_raw的属性,而是要递归取最原始的那个对象
    const src = { info: { name: "祖先" } };
    const ret = reactive(src);
    const locked = readonly(ret);
    
    console.log(toRaw(locked) === src); // true  —— readonly包装的对象toRaw也是那个最初的src,而不是ret
    console.log(toRaw(ret) === src); // true
    
    image.png

    6. markRaw

    将一个新对象挂在响应式对象上时它也会变成响应式对象,如果你不想为这个内部的对象做响应式,可以使用markRaw

    const a = reactive({
        age: 20,
        tool: markRaw(Tooltip),
    });
    
    使用 markRaw 的前提是:你这个对象(例如上面的Tooltip)是一个不会更改的对象,而且不应在模板中使用
    因为 markRaw 虽然为你跳过了响应式,一旦你改了这个对象(Tooltip,而且模板中展示了这个Tooltip)
    而当响应式对象中其他数据发生变更(例如改变age)导致模板更新,则这个对象的变更也会反映在模板上
    
    • markRaw和readonly的区别
      image.png

    7. customRef

    借用vue的【收集依赖track】和【通知更新trigger】,再加上自己的getter和setter拦截逻辑,创建一个自定义ref。

    • 如果不拦截set的赋值逻辑,只是在值修改的时候执行其他逻辑,那么watch也可以实现
    • 不过想要拦截getter的话,就可以用customRef,自已定义【一部分】getter和setter逻辑
    • customRef传入一个工厂函数,这个工厂函数接收2个参数:track, trigger,并返回一个有get和set方法的对象。
    import { customRef } from "vue";
    
    const debounceChangeValue = (value, interval) => {
      let timer = null;
      return customRef((track, trigger) => {
        // customRef传入一个工厂函数,这个工厂函数接收2个参数:track, trigger
        // 并返回一个有get和set方法的对象
        return {
          get() {
            track(); // 收集依赖(必需)
            return value;
          },
          set(newValue) {
            clearTimeout(timer);
            timer = setTimeout(() => {
              value = newValue;
              trigger(); // 数据修改之后需要通知依赖(必需)
            }, interval);
          },
        };
      });
    };
    
    const text = debounceChangeValue("初始值", 300);
    

    8. provide/inject

    <script setup>中,祖先已经可以向后代组件提供响应式数据了

    • 响应式数据的控制权应掌握在提供方手里(可以对外提供 【readonly的数据】和【修改函数】供后代调用,而修改权仍然在提供方)


      image.png

    9. 一些判断函数: isRef / isReactive / isReadonly / isProxy

    10. 内置组件:Teleport 传送

    它可以将组件内部的一部分模板传送到该组件DOM之外的结构中去,即该组件内部的DOM不再受组件层级的影响。

    <Teleport to="body">
          <p>我的DOM直接添加在body下面</p>
    </Teleport>
    
    <Teleport to="#app">
          <p>我的DOM直接追加在#app里面</p>
    </Teleport>
    

    11. 内置组件:Suspense 悬而不决

    相关文章

      网友评论

          本文标题:Vue3新的api

          本文链接:https://www.haomeiwen.com/subject/lxtksdtx.html