Vue3新的api

2023-05-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

export default {
  props: {
    pageType: {
      type: String,
      default: "task",
    },
    taskList: {
      type: Array,
      default: () => [{}, {}],
    },
  },
};
// 如果仅在模板中使用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
import { reactive, watch } from "vue";
const pageInfo = reactive({
  pageIndex: { value: 0 },
  pageSize: 20,
});
watch(pageInfo, () => { // 深层监听,内部变化都会触发
  console.log("pageInfo发生变化", pageInfo);
});
watch(
  () => pageInfo.pageIndex.value, 
  () => {
    console.log("pageInfo发生变化", pageInfo);
  }
);
import { watchEffect } from "vue";
watchEffect(() => {
  console.log("type变化", type.value, pageInfo.pageSize);
});
// 发现甚至没有传我要watch谁,vue会自动跟踪回调的响应式依赖(你用谁我就监视谁)
// 也就是type.value 和 pageInfo.pageSize变化时都会执行该回调
// watchEffect的immediate为true

有点像computed,初始执行一次,依赖值改变时再执行一次
computed注重返回值。watchEffect注释过程

1.5 自定义指令

export default {
    directives: {
        focus: (el) => { el.focus(); }
    }
};
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

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

image.png

5. toRaw

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

  1. 一个是在reactiveMap中保存了这种关联关系(类型是WeakMap,key是原对象,value是代理对象)
  2. 一种是在new Proxy时配置的getter函数内部,可以同时访问到原对象和代理对象的引用
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)导致模板更新,则这个对象的变更也会反映在模板上

7. customRef

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

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>中,祖先已经可以向后代组件提供响应式数据了

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 悬而不决

上一篇下一篇

猜你喜欢

热点阅读