687 vue3 Composition API:computed,watchEffect,watch

computed


01_computed的使用.vue

<template>
  <div>
    <h2>{{ fullName }}</h2>
    <button @click="changeName">修改firstName</button>
  </div>
</template>

<script>
  import { ref, computed } from "vue";

  export default {
    setup() {
      const firstName = ref("Kobe");
      const lastName = ref("Bryant");

      // 1.用法一: 传入一个getter函数
      // computed的返回值是一个ref对象
      const fullName = computed(() => firstName.value + " " + lastName.value);

      // 2.用法二: 传入一个对象, 对象包含getter/setter
      const fullName = computed({
        get: () => firstName.value + " " + lastName.value,
        set(newValue) {
          const names = newValue.split(" ");
          firstName.value = names[0];
          lastName.value = names[1];
          // [firstName.value, lastName.value] = names
        },
      });

      const changeName = () => {
        // firstName.value = "James"
        fullName.value = "haha xixi";
      };

      return {
        fullName,
        changeName,
      };
    },
  };
</script>

<style scoped></style>

侦听数据的变化


watchEffect


02_watchEffect基本使用.vue

<template>
  <div>
    <h2>{{ name }}-{{ age }}</h2>
    <button @click="changeName">修改name</button>
    <button @click="changeAge">修改age</button>
  </div>
</template>

<script>
  import { ref, watchEffect } from "vue";

  export default {
    setup() {
      // watchEffect: 自动收集响应式的依赖
      const name = ref("why");
      const age = ref(18);

      const changeName = () => (name.value = "kobe");
      const changeAge = () => age.value++;

      // watchEffect会立即执行一次
      watchEffect(() => {
        console.log("name:", name.value, "age:", age.value);
      });

      return {
        name,
        age,
        changeName,
        changeAge,
      };
    },
  };
</script>

<style scoped></style>

watchEffect的停止侦听


03_watchEffect停止侦听.vue

<template>
  <div>
    <h2>{{ name }}-{{ age }}</h2>
    <button @click="changeName">修改name</button>
    <button @click="changeAge">修改age</button>
  </div>
</template>

<script>
  import { ref, watchEffect } from "vue";

  export default {
    setup() {
      // watchEffect: 自动收集响应式的依赖
      const name = ref("why");
      const age = ref(18);

      // 【停止监听,但是界面数据继续更新】
      // watchEffect():返回的是一个函数
      const stop = watchEffect(() => {
        console.log("name:", name.value, "age:", age.value);
      });

      const changeName = () => (name.value = "kobe");
      const changeAge = () => {
        age.value++;
        if (age.value > 25) {
          stop(); // age.value > 25时,停止监听
        }
      };

      return {
        name,
        age,
        changeName,
        changeAge,
      };
    },
  };
</script>

<style scoped></style>

watchEffect清除副作用


04_watchEffect清除副作用.vue

<template>
  <div>
    <h2>{{ name }}-{{ age }}</h2>
    <button @click="changeName">修改name</button>
    <button @click="changeAge">修改age</button>
  </div>
</template>

<script>
  import { ref, watchEffect } from "vue";

  export default {
    setup() {
      // watchEffect: 自动收集响应式的依赖
      const name = ref("why");
      const age = ref(18);

      const stop = watchEffect((onInvalidate) => {
        // 【这里用定时器模拟网络请求】
        const timer = setTimeout(() => {
          console.log("网络请求成功~");
        }, 2000);

        // 根据name和age两个变量发送网络请求
        // 在这个函数中清除额外的副作用 
        // 【组件销毁,监听器也随着销毁,并执行onInvalidate的回调函数,可在这里做清理相关工作。】
        onInvalidate(() => {
          // request.cancel() // 【取消上次的网络请求】
          clearTimeout(timer);
          console.log("onInvalidate---------");
        });

        console.log("name:", name.value, "age:", age.value);
      });

      const changeName = () => (name.value = "kobe");
      const changeAge = () => {
        age.value++;
        if (age.value > 25) {
          stop();
        }
      };

      return {
        name,
        age,
        changeName,
        changeAge,
      };
    },
  };
</script>

<style scoped></style>

setup中使用ref


watchEffect的执行时机


调整watchEffect的执行时机


05_watchEffect执行时机ref引用.vue

<template>
  <div>
    <h2 ref="title">哈哈哈</h2>
  </div>
</template>

<script>
  import { ref, watchEffect } from "vue";

  export default {
    setup() {
      // 【常量名要和ref="title"中的title一致,否则打印的值都是null。】
      const title = ref(null);

      watchEffect(
        // 【副作用函数】
        () => {
          console.log(title.value); // <h2>哈哈哈</h2>
          // 哈哈哈, 通过innerHTML拿到DOM元素的值
          console.log(title.value.innerHTML); 
        },
        {
          // pre: 提前执行;  post:DOM挂载、更新完后执行
          flush: "post",
        }
      );

      return {
        title,
      };
    },
  };
</script>

<style scoped></style>

Watch的使用


侦听单个数据源


06_watch侦听的数据源类型.vue

<template>
  <div>
    <h2 ref="title">{{ info.name }}</h2>
    <button @click="changeData">修改数据</button>
  </div>
</template>

<script>
  import { ref, reactive, watch } from "vue";

  export default {
    setup() {
      // watchEffect是直接在函数里使用即可,不用管有哪些依赖
      const info = reactive({ name: "why", age: 18 });

      // 1.侦听watch时,传入一个getter函数 【() => info.name就是getter函数。】
      watch(
        () => info.name,
        (newValue, oldValue) => {
          console.log("newValue:", newValue, "oldValue:", oldValue);
        }
      );

      // 2.传入一个可响应式对象: reactive对象/ref对象
      // 情况一: reactive对象获取到的newValue和oldValue本身都是reactive对象
      // watch(info, (newValue, oldValue) => {
      //   console.log("newValue:", newValue, "oldValue:", oldValue);
      //   console.log("newValue:", newValue.name, "oldValue:", oldValue.name);
      // })

      // 如果希望newValue和oldValue是一个普通的对象
      watch(
        // 简写:() => ({...info})
        () => {
          return { ...info };
        },
        (newValue, oldValue) => {
          // 【此时,newValue和oldValue是一个普通的对象】
          console.log("newValue:", newValue, "oldValue:", oldValue);
          // console.log("newValue:", newValue.name, "oldValue:", oldValue.name);
        }
      );

      // 情况二: ref对象获取newValue和oldValue是value值的本身
      const name = ref("why");
      // watch(name, (newValue, oldValue) => {
      //   // 【这里不是newValue.value】
      //   console.log("newValue:", newValue, "oldValue:", oldValue);
      // })

      const changeData = () => {
        info.name = "kobe";
      };

      return {
        changeData,
        info,
      };
    },
  };
</script>

<style scoped></style>

侦听多个数据源


侦听响应式对象


07_watch侦听多个数据源.vue

<template>
  <div>
    <h2 ref="title">{{ info.name }}</h2>
    <button @click="changeData">修改数据</button>
  </div>
</template>

<script>
  import { ref, reactive, watch } from "vue";

  export default {
    setup() {
      // 1.定义可响应式的对象
      const info = reactive({ name: "why", age: 18 });
      const name = ref("haha");

      // 2.侦听器watch
      // 【变成普通的对象,如果不加圆括号,编译器就不知道是要返回...info,还是{ ...info}。】
      watch(
        [() => ({ ...info }), name],
        ([newInfo, newName], [oldInfo, oldName]) => {
          console.log(newInfo, newName);
          console.log(oldInfo, oldName);
        }
      );

      const changeData = () => {
        info.name = "kobe";
      };

      return {
        changeData,
        info,
      };
    },
  };
</script>

<style scoped></style>

watch的选项


08_深度监听.vue

<template>
  <div>
    <h2 ref="title">{{info.name}}</h2>
    <button @click="changeData">修改数据</button>
  </div>
</template>

<script>
  import { ref, reactive, watch } from 'vue';

  export default {
    setup() {
      // 1.定义可响应式的对象
      const info = reactive({
        name: "why", 
        age: 18,
        friend: {
          name: "kobe"
        }
      });

      // 2.侦听器watch
      watch(() => ({...info}), (newInfo, oldInfo) => {
        console.log(newInfo, oldInfo);
      }, {
        // 【默认是可以深度监听的,源码中,当监听的数据源是reactive时,deep=true。】
        deep: true,
        immediate: true
      })

      const changeData = () => {
        info.friend.name = "james";
      }

      return {
        changeData,
        info
      }
    }
  }
</script>

原文地址:https://www.cnblogs.com/jianjie/p/14919591.html