Vue3 —— 常用 Composition API(一)(computed函数、watch函数、watchEffect函数、生命周期钩子)

简介: Vue3 —— 常用 Composition API(一)(computed函数、watch函数、watchEffect函数、生命周期钩子)

一、computed 函数

1. 计算属性 — 简写(不考虑计算属性被修改的情况)

  1. 在 setup 中定义 person 对象,通过 reactive 设置成响应式
  2. 给 person 添加计算属性,名为 fullName,返回全名
  <template>
    <div>
      <h3>一个人的信息</h3>
      姓:<input type="text" v-model="person.firstName" /><br />
      名:<input type="text" v-model="person.lastName" /><br />
      <span>全名:{{ person.fullName }}</span><br/>
    </div>
  </template>
  <script>
  import { reactive, computed } from "vue";
  export default {
    name: "Demo",
    setup() {
      // 数据
      let person = reactive({
        firstName: "张",
        lastName: "三",
      });
      // 计算属性——简写(没有考虑计算属性被修改的情况)
      person.fullName = computed(()=>{
        return person.firstName + '-' + person.lastName
      })
      // 返回一个对象
      return {
        person,
      };
    },
  };
  </script>

计算属性显示全名:

bf2b9510425944178c57ca79beb15374.png

2. 计算属性 — 完整写法(考虑计算属性被修改的情况)

  1. 动态修改 input 框,响应式变化
  2. 完整写法,要在计算属性内配置 get 和 set
  3. get 里面是返回值,set 里面给对应属性赋值
  <template>
    <div>
      <h3>一个人的信息</h3>
      姓:<input type="text" v-model="person.firstName" /><br />
      名:<input type="text" v-model="person.lastName" /><br />
      <span>全名:{{ person.fullName }}</span><br/>
      全名:<input type="text" v-model="person.fullName">
    </div>
  </template>
  <script>
  import { reactive, computed } from "vue";
  export default {
    name: "Demo",
    setup() {
      // 数据
      let person = reactive({
        firstName: "张",
        lastName: "三",
      });
      // 计算属性——完整写法(考虑读和写)
      person.fullName = computed({
        get(){
          return person.firstName + '-' + person.lastName
        },
        set(value){
          const nameArr = value.split('-')
          person.firstName = nameArr[0]
          person.lastName = nameArr[1]
        }
      })
      // 返回一个对象
      return {
        person,
      };
    },
  };
  </script>

效果如下:

e1b1763f605e4942aabbad2e6e3b8215.png

二、watch 函数

1. 监视 ref 所定义的一个响应式数据

  1. 第一个参数:监听的是谁
  2. 第二个参数:监视的回调
  3. 第三个参数:监视的配置 => 立即执行(页面一经加载就执行一次)
  <template>
    <div>
      <h3>当前求和为:{{ sum }}</h3>
      <button @click="sum++">点我+1</button>
    </div>
  </template>
  <script>
  import { ref, watch } from "vue";
  export default {
    name: "Demo",
    setup() {
      // 数据
      let sum = ref(0);
      // 情况一:监视ref所定义的一个响应式数据
      watch(sum, (newValue, oldValue) => {
        console.log("sum变了", newValue, oldValue);
      }, {immediate: true});
      // 返回一个对象
      return {
        sum,
      };
    },
  };
  </script>

监听 ref 所定义的一个响应式数据:

16682c9cfe044b4fa687cdf12cc7710b.png

2. 监视 ref 所定义的多个响应式数据

  1. 监视多个响应式数据:sum 和 msg
  2. sum 每次 +1,msg 每次多一个 !
  3. 监听多个数据:用 [] 括起来
  <template>
    <div>
      <h3>当前求和为:{{ sum }}</h3>
      <button @click="sum++">点我+1</button>
      <hr/>
      <h3>当前的信息为:{{ msg }}</h3>
      <button @click="msg+='!'">修改信息</button>
    </div>
  </template>
  <script>
  import { ref, watch } from "vue";
  export default {
    name: "Demo",
    setup() {
      // 数据
      let sum = ref(0);
      let msg = ref('你好啊')
      // 情况二:监视ref所定义的多个响应式数据
      watch([sum, msg], (newValue, oldValue)=>{
        console.log('sum或msg变了', newValue, oldValue);
      })
      // 返回一个对象
      return {
        sum,
        msg,
      };
    },
  };
  </script>

按钮分别点击两次:

c1248e02169b430190d2a7ba925c6a02.png

3. 监视 reactive 所定义一个响应式数据的全部数据

  1. 监视 reactive 定义的响应式数据时:oldValue 无法正确获取
  2. 监视 reactive 定义的响应式数据时:强制开启了深度监视(deep 配置失效)
  <template>
    <div>
      <h3>姓名:{{person.name}}</h3>
      <h3>年龄:{{person.age}}</h3>
      <button @click="person.name+='~'">修改姓名</button>
      <button @click="person.age++">增长年龄</button>
    </div>
  </template>
  <script>
  import { reactive, watch } from "vue";
  export default {
    name: "Demo",
    setup() {
      // 数据
      let person = reactive({
        name: '张三',
        age: 18,
      })
      /* 
        情况三:监视reactive所定义一个的响应式数据的全部数据
          1.注意:此处无法正确的获取oldValue
          2.注意:强制开启了深度监视(即deep配置无效)
      */
      watch(person, (newValue, oldValue)=>{
        console.log('person变化了', newValue, oldValue);
      }, {deep: true})
      // 返回一个对象
      return {
        person
      };
    },
  };
  </script>

都是显示的 newValue:

9611e0c082a541538121255d2226e775.png

4. 监视 reactive 所定义一个响应式数据中的某个属性

  1. 要写成函数的形式 () => person.age
  <template>
    <div>
      <h3>姓名:{{person.name}}</h3>
      <h3>年龄:{{person.age}}</h3>
      <button @click="person.name+='~'">修改姓名</button>
      <button @click="person.age++">增长年龄</button>
    </div>
  </template>
  <script>
  import { reactive, watch } from "vue";
  export default {
    name: "Demo",
    setup() {
      // 数据
      let person = reactive({
        name: '张三',
        age: 18,
      })
      // 情况四:监视reactive所定义一个响应式数据中的某个属性
      watch(() => person.age, (newValue, oldValue)=>{
        console.log('person的age变化了', newValue, oldValue);
      })
      // 返回一个对象
      return {
        person
      };
    },
  };
  </script>

某个属性:oldValue 可以获取:a5e23d169db546bdb9b767ba72a3b8c0.png


5. 监视 reactive 所定义一个的响应式数据中的某些属性

  1. 用 [] 包裹起来,写成数组的形式
  2. 多个属性分别用函数形式表示
  <template>
    <div>
      <h3>姓名:{{person.name}}</h3>
      <h3>年龄:{{person.age}}</h3>
      <button @click="person.name+='~'">修改姓名</button>
      <button @click="person.age++">增长年龄</button>
    </div>
  </template>
  <script>
  import { reactive, watch } from "vue";
  export default {
    name: "Demo",
    setup() {
      // 数据
      let person = reactive({
        name: '张三',
        age: 18,
      })
      // 情况五:监视reactive所定义一个的响应式数据中的某些属性
      watch([() => person.name, () => person.age], (newValue, oldValue) => {
        console.log('person的name或age变化了', newValue, oldValue);
      })
      // 返回一个对象
      return {
        person
      };
    },
  };
  </script>

依次点击修改姓名,增长年龄:

308dc7a7ed7c4da4a415685f7719c66a.png

6. 监视 reactive 定义的响应式数据中某个属性时:deep配置有效。

  1. 若设置 deep: false ,则控制台没有输出
  2. 监视 reactive 定义的响应式数据中某个属性时:deep配置有效。
  <template>
    <div>
      <h3>姓名:{{person.name}}</h3>
      <h3>年龄:{{person.age}}</h3>
      <h3>薪资:{{person.job.j1.salary}}K</h3>
      <button @click="person.name+='~'">修改姓名</button>
      <button @click="person.age++">增长年龄</button>
      <button @click="person.job.j1.salary++">增加薪资</button>
    </div>
  </template>
  <script>
  import { reactive, watch } from "vue";
  export default {
    name: "Demo",
    setup() {
      // 数据
      let person = reactive({
        name: '张三',
        age: 18,
        job: {
          j1:{
            salary: 20
          }
        }
      })
      // 特殊情况:监视reactive定义的响应式数据中某个属性时:deep配置有效。
      watch(() => person.job, (newValue, oldValue) => {
        console.log('person的job变化了', newValue, oldValue);
      }, {deep: false})
      // 返回一个对象
      return {
        person
      };
    },
  };
  </script>

开启深度监视:

ba8ebdda09ed496988eb3d1e4c8c1acf.png

三、watchEffect 函数

1. 对比 watch 和 watchEffect

  1. watch 的套路:既要指明监视的属性,也要指明监视的回调
  2. watchEffect 的套路:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性

2. watchEffect 类似于 computed

  1. 但 computed 注重的计算出来的值(回调函数的返回值),所以必须要写返回值
  2. 而 watchEffect 更注重的是过程(回调函数的函数体),所以不用写返回值

当点击 点我+1 和 增加薪资 时会被监视:

  <template>
    <div>
      <h3>当前求和为:{{ sum }}</h3>
      <button @click="sum++">点我+1</button>
      <hr/>
      <h3>薪资:{{person.job.j1.salary}}K</h3>
      <button @click="person.job.j1.salary++">增加薪资</button>
    </div>
  </template>
  <script>
  import { ref, reactive, watchEffect } from "vue";
  export default {
    name: "Demo",
    setup() {
      // 数据
      let sum = ref(0);
      let person = reactive({
        job: {
          j1:{
            salary: 20
          }
        }
      })
      watchEffect(()=>{
        const x1 = sum.value
        const x2 = person.job.j1.salary
        console.log('watchEffect所指定的回调执行了', x1, x2);
      })
      // 返回一个对象
      return {
        sum,
        msg,
        person
      };
    },
  };
  </script>

第一个按钮点击一次,第二个按钮点击两次:

519588f1cc8e487a991f41e5f5c5d629.png

四、生命周期钩子

1. 官方图解


c3791a973d0541f18a0e8270958e53b3.png

2. 通过配置项的形式使用生命周期钩子

  1. setup 就是一个配置项,通过配置项的形式使用钩子
  2. 下面对生命周期钩子进行简单测试

App.vue

  <template>
    <div>
      <button @click="isShowDemo = !isShowDemo">切换隐藏/显示</button>
      <Demo v-if="isShowDemo" />
    </div>
  </template>
  <script>
  import { ref } from "vue";
  import Demo from "./components/Demo.vue";
  export default {
    name: "App",
    components: { Demo },
    setup() {
      let isShowDemo = ref(true);
      return { isShowDemo };
    },
  };
  </script>

Demo.vue

  <template>
    <div>
      <h3>当前求和为:{{ sum }}</h3>
      <button @click="sum++">点我+1</button>
    </div>
  </template>
  <script>
  import { ref } from "vue";
  export default {
    name: "Demo",
    setup() {
      // 数据
      let sum = ref(0);
      // 返回一个对象
      return { sum };
    },
    // 通过配置项的形式使用生命周期钩子
    beforeCreate(){
      console.log('---beforeCreate---');
    },
    created(){
      console.log('---created---');
    },
    beforeMount(){
      console.log('---beforeMount---');
    },
    mounted(){
      console.log('---mounted---');
    },
    beforeUpdate(){
      console.log('---beforeUpdate---');
    },
    updated(){
      console.log('---updated---');
    },
    beforeUnmount(){
      console.log('---beforeUnmount---');
    },
    unmounted(){
      console.log('---unmounted---');
    }
  };
  </script>

页面一加载:1df1c733720d40e48bc90da847c3e9af.png


点击求和:

c1bedc094da5463c94aae3f6d2a0ff39.png

点击切换/隐藏显示:

74a497c2993f41869a0149b729f14054.png

3. 通过组合式API的形式去使用生命周期钩子

  1. 把生命周期钩子写入 setup 配置项里面
  <template>
    <div>
      <h3>当前求和为:{{ sum }}</h3>
      <button @click="sum++">点我+1</button>
    </div>
  </template>
  <script>
  import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from "vue";
  export default {
    name: "Demo",
    setup() {
      // 数据
      let sum = ref(0);
      // 通过组合式API的形式去使用生命周期钩子
      onBeforeMount(() => {
        console.log('---onBeforeMount---');
      })
      onMounted(() => {
        console.log('---onMounted---');
      })
      onBeforeUpdate(() => {
        console.log('---onBeforeUpdate---');
      })
      onUpdated(() => {
        console.log('---onUpdated---');
      })
      onBeforeUnmount(() => {
        console.log('---onBeforeUnmount---');
      })
      onUnmounted(() => {
        console.log('---onUnmounted---');
      })
      // 返回一个对象
      return { sum };
    },
  };
  </script>

不积跬步无以至千里 不积小流无以成江海

相关文章
|
1月前
|
JavaScript 前端开发 API
Vue 3新特性详解:Composition API的威力
【10月更文挑战第25天】Vue 3 引入的 Composition API 是一组用于组织和复用组件逻辑的新 API。相比 Options API,它提供了更灵活的结构,便于逻辑复用和代码组织,特别适合复杂组件。本文将探讨 Composition API 的优势,并通过示例代码展示其基本用法,帮助开发者更好地理解和应用这一强大工具。
30 1
|
1月前
Vue3 项目的 setup 函数
【10月更文挑战第23天】setup` 函数是 Vue3 中非常重要的一个概念,掌握它的使用方法对于开发高效、灵活的 Vue3 组件至关重要。通过不断的实践和探索,你将能够更好地利用 `setup` 函数来构建优秀的 Vue3 项目。
|
2月前
|
JavaScript API
vue3知识点:ref函数
vue3知识点:ref函数
36 2
|
2月前
|
JavaScript API
vue3知识点:自定义hook函数
vue3知识点:自定义hook函数
28 2
|
2月前
|
API
vue3知识点:reactive函数
vue3知识点:reactive函数
29 1
|
2月前
|
JavaScript
Vue 的父组件和子组件生命周期钩子执行顺序
在 Vue 中,父组件和子组件的生命周期钩子执行顺序如下:
|
2月前
|
JavaScript
|
2月前
|
API
《vue3第四章》Composition API 的优势,包含Options API 存在的问题、Composition API 的优势
《vue3第四章》Composition API 的优势,包含Options API 存在的问题、Composition API 的优势
27 0
|
2月前
|
JavaScript 前端开发 API
《vue3第六章》其他,包含:全局API的转移、其他改变
《vue3第六章》其他,包含:全局API的转移、其他改变
23 0
|
2月前
|
JavaScript 前端开发 API
深入探索挖掘vue3 生命周期
【10月更文挑战第10天】
45 0

热门文章

最新文章