Vue 学习笔记-2022/12/10

Composition Api

一、setup() 函数

Composition api 的入口

<template>
  <ul>
    <li v-for="msg in messages" :key="msg.id">{{ msg.content }}</li>
  </ul>
</template>
<script>
export default {
  setup() {
    const messages = [
      { id: 1, content: "这是一条消息提醒1" },
      { id: 2, content: "这是一条消息提醒2" },
      { id: 3, content: "这是一条消息提醒3" },
      { id: 4, content: "这是一条消息提醒4" },
    ];

    return { messages };
  },
};
</script>
二、ref() 函数

ref() 函数里面接收一个任意类型的参数,该参数会返回一个全新的响应类型的对象,不过该对象是基于原始的代理,如果需要访问对象的值,需要用 .value 来进行访问,并且因为是代理对象,值与原对象也不全等。

setup() {
    const messages = ref([
      { id: 1, content: "这是一条消息提醒1" },
      { id: 2, content: "这是一条消息提醒2" },
      { id: 3, content: "这是一条消息提醒3" },
      { id: 4, content: "这是一条消息提醒4" },
    ]);
三、reactive() 函数

只接收对象,广义对象,包括数组,如果传值为基本数据类型 Vue 会进行警告

ref() 函数相比 返回值是有区别的 ref() 函数需要访问 .value 属性才能返回 proxy 代理对象,而reactive() 函数 直接返回 proxy 代理对象

ref() 函数在转换数据为响应类型的时候 为去调用 reactive() 函数

setup() {
    const messages = reactive([
      { id: 1, content: "这是一条消息提醒1" },
      { id: 2, content: "这是一条消息提醒2" },
      { id: 3, content: "这是一条消息提醒3" },
      { id: 4, content: "这是一条消息提醒4" },
    ]);

一般来说 reactive() 函数一般适用于复杂的配置文件 ,ref() 函数因为可以使用基本数据类型,一般通用

四、computed() 计算属性

computed() 函数需要一个无参的回调函数

// 同样里面的属性都是ref 所以需要.value才能进行访问
const searchTerm = ref("");   
const searchedMessages = computed(() => {
      if (searchTerm.value === "") return messages.value;
      return messages.value.filter((msg) => {
        return msg.content.includes(searchTerm.value);
      });
    });
五、watch() 函数
1. 基本数据类型的监听
// 监听 ref 属性 
const searchTerm = ref("");
watch(searchTerm, (newVal, oldVal) => {
      console.log(messages.value);
      console.log("搜索词:", newVal, oldVal);
    });
// 监听 ref的value属性 需要使用无参回调函数
watch(() => searchTerm.value,
      (newVal, oldVal) => {
        console.log("搜索词:", newVal, oldVal);
});
2. 对象的监听
// 如果是 reactive创建的响应对象就不需要要访问 .value 
<script>
import { ref, reactive, computed, watch } from "vue";

export default {
  setup() {
    const messages = ref([
      { id: 1, content: "这是一条消息提醒1" },
      { id: 2, content: "这是一条消息提醒2" },
      { id: 3, content: "这是一条消息提醒3" },
      { id: 4, content: "这是一条消息提醒4" },
    ]);

    const options = ref({
      // const options = reactive({
      title: "消息列表",
      user: {
        name: "张三",
        active: true,
      },
    });

    // 监听浅层 Object 属性
    watch(
      () => options.value.title,
      // () => options.title, // reactive
      (newVal, oldVal) => {
        console.log(newVal, oldVal);
      }
    );

    // 监听深层 Object 属性
    watch(
      () => options.value.user.name,
      // () => options.user.name, // reactive
      (newVal, oldVal) => {
        console.log(newVal, oldVal);
      }
    );

    return { messages, options };
  },
};
</script>

watch() 函数 默认只监听 属性的引用是否发生变化,但是我们修改数据的时候一般不会创建新的对象 ,而是在原对象上进行修改,这样即使我们对对象进行改动,页面发生了变化,但是 watch() 函数 监听不到这种操作。

解决方法是 让 watch() 去比对对象中的每一个属性是否发生了变化

 // with deep true,可以比对对象的属性
    watch(
      () => options.value,
      (newVal, oldVal) => {
        console.log(newVal, oldVal, newVal === oldVal); // 相同的引用
      },
      { deep: true }
    );
// 但是此时 newVal 和 oldVal 的对象引用 还是不变的 所以他们对的对象进行全等的时候是 true

// 解决的方法是 在修改的时候 生成一个全新的对象

// 浅克隆
watch(
    // 解构语法
    () => ({ ...options.value }),
    (newVal, oldVal) => {
        console.log(newVal, oldVal); // user 对象没有克隆,所以是同一个引用
    }
);
// 完全克隆
watch(
    () => JSON.parse(JSON.stringify(options.value)),
    (newVal, oldVal) => {
        let obj = () => JSON.parse(JSON.stringify(options.value));
        console.log(obj);
        console.log(newVal, oldVal, newVal === oldVal); // 不同的引用
    }
);

return { messages, options };
},
3.监听多个响应性数据
// 同时监听多个响应性数据
watch(
    [() => options.value.title, () => options.value.user.name],
    (newVals, oldVals) => {
        console.log(newVals, oldVals);
    }
);
4. watchEffect()

基本和 watch 的作用是一样的

watchEffect() 不需要指定哪个响应性数据进行监听 ,它会根据里面的代码进行监听,假设里面的代码有用到响应性数据,那么就会重新执行该函数

watchEffect() 不管 数据是否发生变化,总会先执行一次,类似于 do while

同时在 watchEffect() 里面也能执行异步方法,但是和 watch() 不一样的是 watchEffect() 不支持获取修改前的数据

watchEffect(() => {
      console.log(options.value.title);
      console.log(options.value.user.name);
    });
5. onInvalidate() 函数

onInvalidate() 会在下次监听代码执行前执行

// 传参位置不一样
watchEffect((onInvalidate) => {
    console.log(options.value.title);
    console.log(options.value.user.name);

    onInvalidate(() => {
        console.log("做一些清理操作...");
    });
});

watch(
    () => options.value.title,
    (newVal, oldVal, onInvalidate) => {
        console.log(newVal, oldVal);
        onInvalidate(() => {
            console.log("做一些清理操作...");
    });
 });
六、传递和访问 Props 属性

setup() 函数无法直接访问 Props 属性 但是可以把 Props 当作参数传递进去

1. 将 Props中非响应性的属性转为响应性
import {  toRefs } from "vue";

// 用 toRefs 包裹 Props属性 即可转为响应性

如果被包裹的是基本类型数据,那么在数据传递的时候就会失去响应性,解决的方法就是用 toRefs 包裹使用

七、method() 函数

<template>
  <li>{{ msg }} <button @click="removeMessage(id)">删除</button></li>
</template>
<script>
import { ref, watch, watchEffect, toRefs } from "vue";

export default {
  props: ["msg", "id"],
  setup(props) {
    // 无参数
    function removeMessage() {
      console.log("删除消息");
    }

    // 有参数
    function removeMessage(id) {
      console.log("删除消息", id);
    }

    return { removeMessage };
  },
};
</script>
八、Emit 自定义事件
emits: ["remove"],
setup(props, { emit }) {
   // 增加一个事件数组
    return {};
  },
九、生命周期钩子

_23CDSBJC4T_J)@IUM8YFUI

十、provide 和 inject

TR%TV28%I3H)NHS`9FW(E~M

Composition Api 被替换成了对应的函数形式 provide()inject()

和普通的没什么区别,需要传递响应性的数据就 用 ref 转换

十一、获取 template 的 ref

十二、渲染函数

十三、attrs

可以通过 attrs 获取 pros 里未明确定义的属性,并且 attrs 默认是响应性的 在 template 里面可以用 this 直接访问到

十四、script setup

O301SR4KE<code>5_KW$</code>B02E~NH

为了简写 setup 而出现的

不用 手动 return 数据了,可以直接在 模板中使用

组件可以直接使用 import 导入 可以直接在 模板中使用

props 改为了 defineProps 用法没什么区别

const props = defineProps(["msg", "id"]);

emits 改为了 defineEmits 用法没什么区别

<button @click="$emit('remove', id)">
const emits = defineEmits(["remove"]);


slotsattrs 需要导入使用

import { useSlots, useAttrs } from "vue";
const slots  = useSlots()
const attrs  = useAttrs()
End

本文标题: Vue 学习笔记-2022/12/10

本文链接: https://dnslin.com/archives/91.html

除非另有说明,本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

声明:转载请注明文章来源。

最后修改:2022 年 12 月 21 日
如果觉得我的文章对你有用,请随意赞赏