零基础学习 Vue3 之 computed && watch ~ 贰

目录

一、computed

 二、侦听数据的变化之watchEffect

1. watchEffect的基本使用

代码

效果 

2. watchEffect的停止监听

代码

效果 

3. watchEffect清除副作用

什么是清除副作用

如何使用

代码

效果 

4. watchEffect的执行时机

代码

三、 侦听数据的变化之watch

1. 侦听单个数据源

01-传入getter函数 

02-传入响应式对象

2. 侦听多个数据源

代码

效果

3. watch的选项

代码


一、computed

在vue2中,我们也已经使用过computed属性了

在Vue3的Composition API中,则是需要在setup函数中使用computed方法来编写一个计算属性

computed :

  • 方式一:接收一个getter函数,并为 getter 函数返回的值,返回一个不变的 ref 对象
  • 方式二:接收一个具有 get 和 set 的对象,返回一个可变的(可读写)ref 对象
<template>
  <div>
    <h1>{
   
   { resName }}</h1>
    <button @click="change">change resName</button>
  </div>
</template>
<script>
import { ref, computed } from 'vue';
export default {
  setup() {
    let firstName = ref('hello');
    let lastName = ref('world');
    // 方式一
    // let resName = computed(() => firstName.value + lastName.value);

    //方式二
    let resName = computed({
      get() {
        return firstName.value + ' ' + lastName.value;
      },
      set(newValue) {
        const names = newValue.split(' ');
        firstName.value = names[0];
        lastName.value = names[1];
      }
    });

    const change = () => {
      resName.value = 'abc ddd';
      console.log(resName);
    };

    return {
      resName,
      change
    };
  }
};
</script>

效果 


 二、侦听数据的变化之watchEffect

在vue2中,是使用watch选项来侦听data或者props数据的变化,而在vue3中,有两种方式

1. watchEffect的基本使用

watchEffect : 

  • 自动收集响应式数据的依赖
  • watchEffect传入的函数会被立即执行一次,并且在执行的过程中会收集依赖
  • 只有收集的依赖发生变化时,watchEffect传入的函数才会再次执行

代码

<template>
  <div>
    <h1>{
   
   { name }} - {
   
   { age }}</h1>
    <button @click="changeName">changeName</button>
    <button @click="changeAge">changeAge</button>
  </div>
</template>
<script>
import { ref, watchEffect } from 'vue';
export default {
  setup() {
    let name = ref('star');
    let age = ref(18);

    const changeName = () => (name.value === 'star' ? (name.value = 'xuanyu') : (name.value = 'star'));
    const changeAge = () => age.value++;

    watchEffect(() => {
      // 因为这里只使用了name,所以只会监听name,如果把age也写进来,那么两个都会监听
      console.log('name:', name.value);
    });

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

<style lang="scss" scoped></style>

效果 

2. watchEffect的停止监听

假如,某些情况想要停止监听,那么可以获取watchEffect的返回值函数,调用该函数即可

代码

<template>
  <div>
    <h1>{
   
   { name }} - {
   
   { age }}</h1>
    <button @click="changeName">changeName</button>
    <button @click="changeAge">changeAge</button>
  </div>
</template>
<script>
import { ref, watchEffect } from 'vue';
export default {
  setup() {
    let name = ref('star');
    let age = ref(18);

    const changeName = () => (name.value === 'star' ? (name.value = 'xuanyu') : (name.value = 'star'));
    // 获取返回值
    const stopWatchEffect = watchEffect(() => {
      // 自动监听age
      console.log('age:', age.value);
    });
    const changeAge = () => {
      age.value++;
      if (age.value > 22) {
        // 停止监听
        stopWatchEffect();
      }
    };

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

<style lang="scss" scoped></style>

效果 

3. watchEffect清除副作用

什么是清除副作用

  • 比如在开发中可能需要在侦听函数中执行网络请求,但是在网络请求还没有达到的时候,停止了侦听器,或者侦听器侦听函数被再次执行了
  • 那么上一次的网络请求应该被取消掉,这个时候就可以清除上一次的副作用

如何使用

  • 在给watchEffect传入的函数被回调时,其实可以获取到一个参数:onInvalidate
  • 副作用即将重新执行 或者 侦听器被停止 时会执行该函数传入的回调函数
  • 可以在传入的回调函数中,执行一些清除工作

代码

<template>
  <div>
    <h1>{
   
   { name }} - {
   
   { age }}</h1>
    <button @click="changeName">changeName</button>
    <button @click="changeAge">changeAge</button>
  </div>
</template>
<script>
import { ref, watchEffect } from 'vue';
export default {
  setup() {
    let name = ref('star');
    let age = ref(18);

    const changeName = () => (name.value === 'star' ? (name.value = 'xuanyu') : (name.value = 'star'));
    // 获取返回值
    const stopWatchEffect = watchEffect((onInvalidate) => {
      // 自动监听age
      console.log('age:', age.value);
      const timer = setTimeout(() => {
        console.log('1s后执行');
      }, 1000);
      // 取消副作用,清除上一次的定时器
      onInvalidate(() => {
        clearTimeout(timer);
      });
    });
    const changeAge = () => {
      age.value++;
      if (age.value > 22) {
        // 停止监听
        stopWatchEffect();
      }
    };

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

<style lang="scss" scoped></style>

效果 

4. watchEffect的执行时机

  • pre : 默认值,它会在元素 挂载 或者 更新 之前执行
  • post : 元素 挂载 或者 更新 之后执行
  • sync : 强制同步一起执行,效率很低,不推荐

一般来说,如果需要等dom挂载完后操作dom元素的时候,传post即可

代码

<template>
  <div>
    <h1 ref="hRef">star</h1>
  </div>
</template>
<script>
import { ref, watchEffect } from 'vue';
export default {
  setup() {
    // 先声明一个null的ref,等到元素挂载后,会自动赋值过来
    const hRef = ref(null);

    watchEffect(
      () => {
        console.log(hRef.value);
      },
      {
        // 设定元素挂载再执行这个函数
        flush: 'post'
      }
    );
    return {
      hRef
    };
  }
};
</script>

<style lang="scss" scoped></style>

三、 侦听数据的变化之watch

watch : 

  • watch需要侦听特定的数据源,并在回调函数中执行副作用
  • 默认情况下它是惰性的,只有当被侦听的源发生变化时才会执行回调
  • 与watchEffect的比较,watch允许我们懒执行副作用(第一次不会直接执行)
  • 更具体的说明当哪些状态发生变化时,触发侦听器的执行
  • 访问侦听状态变化前后的值

1. 侦听单个数据源

watch侦听函数的数据源有两种类型:
  • 一个getter函数:但是该getter函数必须引用可响应式的对象(比如reactive或者ref)
  • 直接写入一个可响应式的对象,reactive或者ref(比较常用的是ref)

01-传入getter函数 

用来监听ref活着reactive对象中的具体属性可使用

02-传入响应式对象

  • ref对象
<template>
  <div>
    <h1>
      {
   
   { star }}
    </h1>
    <button @click="change">change</button>
  </div>
</template>
<script>
import { ref, reactive, watch } from 'vue';
export default {
  setup() {
    /**
     * 一、如果ref响应式对象中的是基本数据类型
     */
    const star = ref('123');
    // const star = ref('123');
    // 改变
    const change = () => (star.value = 'coder');
    // 那么直接这样传入即可,拿到的是value值本身
    watch(star, (newValue, oldValue) => {
      console.log('newValue:', newValue, 'oldValue:', oldValue);
    });

    /**
     * 二、如果ref对象中的是对象数据,那么也需要结构 () => ({...star.value}),如果不结构,拿到的是ref对象
     */
    const star = ref({ name: '123', age: 14 });
    // 改变
    const change = () => (star.value.name = 'coder');
    // 那么需要结构,如果不结构,拿到的是ref对象
    watch(
      () => ({ ...star.value }),
      (newValue, oldValue) => {
        console.log('newValue:', newValue, 'oldValue:', oldValue);
      }
    );

    return {
      star,
      change
    };
  }
};
</script>

<style lang="scss" scoped></style>
  • reactive对象
<template>
  <div>
    <h1>
      {
   
   { star.name }}
    </h1>
    <button @click="change">change</button>
  </div>
</template>
<script>
import { ref, reactive, watch } from 'vue';
export default {
  setup() {
    const star = reactive({ name: '123', age: 15 });
    // 改变
    const change = () => (star.name = 'coder');
    /**
     * 一、如果直接传入reactive对象,那么打印出的也是两个reactive对象
     */
    watch(star, (newValue, oldValue) => {
      console.log('newValue:', newValue, 'oldValue:', oldValue);
    });
    /**
     * 二、如果希望获得普通对象,结构一下
     */
    watch(
      () => ({ ...star }),
      (newValue, oldValue) => {
        console.log('newValue:', newValue, 'oldValue:', oldValue);
      }
    );
    return {
      star,
      change
    };
  }
};
</script>

<style lang="scss" scoped></style>

2. 侦听多个数据源

传入数组即可

代码

<template>
  <div>
    <h1>
      {
   
   { star.name }}
    </h1>
    <button @click="change">change</button>
  </div>
</template>
<script>
import { ref, reactive, watch } from 'vue';
export default {
  setup() {
    // ref对象
    const coder = ref('know');
    // reactive对象
    const star = reactive({ name: '123', age: 15 });
    // 改变
    const change = () => {
      star.name = 'coder';
      coder.value = 'unKnow';
    };
    // 传入数组即可                      // 对应结构
    watch([coder, () => ({ ...star })], ([newCoder, newStar], [oldCoder, oldStar]) => {
      console.log(newCoder, newStar, '----', oldCoder, oldStar);
    });

    return {
      star,
      change
    };
  }
};
</script>

<style lang="scss" scoped></style>

效果

3. watch的选项

配置第三个参数 : 

  • deep : 是否深度监听
  • immediate : 是否立即执行

代码

<template>
  <div>
    <h1>
      {
   
   { info.name }}
    </h1>
  </div>
</template>
<script>
import { ref, reactive, watch } from 'vue'
export default {
  setup() {
    // reactive对象
    const info = reactive({
      name: '123',
      age: 15,
      friend: { name: '456' }
    })
    watch(
      () => {
        const obj = { ...info }
        // 因为有两层,需要自己结构下,否则返回的是proxy
        obj.friend = { ...obj.friend }
        return obj
      },
      (newValue, oldValue) => {
        console.log(newValue, oldValue)
      },
      {
        // 深度监听
        deep: true,
        // 立即执行
        immediate: true
      }
    )

    return {
      info
    }
  }
}
</script>

<style lang="scss" scoped></style>

猜你喜欢

转载自blog.csdn.net/a15297701931/article/details/125094024