Vue3.0(1):组合式API

本文深入探讨了Vue3的组合式API,包括setup函数的使用、props和响应式、上下文对象、生命周期钩子、监听器以及模板渲染。通过示例代码,解释了如何避免2.0版本中的代码碎片化,提高代码可维护性。同时,文章指出ref和reactive在不同场景下的应用,并提到了在处理组件间逻辑时的组织策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

最近想明白了一个问题,关于组合式api的应用理解错了,推荐下面这个文章,非常好。

vue3 composition(组合式)API 是什么?我为什么要使用它?

组合式API

官方文档

从官方文档来看,使用组合式API是为了解决碎片化,避免断地“跳转”相关代码。

setup 组件选项

  • 新的 setup 选项在组件创建之前执行,一旦 props 被解析,就将作为组合式 API 的入口。
  • setup 选项是一个接收 props 和 context 的函数,将 setup 返回的所有内容都暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。
  • setup 函数中的 props 是响应式的,当传入新的 prop 时,它将被更新。因为 props 是响应式的,你不能使用 ES6 解构,它会消除 prop 的响应性。如果需要解构 prop,可以在 setup 函数中使用 toRefs 函数。
//一般情况
 props: {
    title: String
  },
  setup(props) {
    console.log(props.title)
  }

//解构
import { toRefs } from 'vue'

setup(props) {
  const { title } = toRefs(props)

  console.log(title.value)
}

//特殊情况,如果title这个属性不存在,需要手动创建
setup(props) {
  const title = toRef(props, 'title')
  console.log(title.value)
}
  • context 是一个普通的 JavaScript 对象,它暴露组件的三个 property。它不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构。
//一般
setup(props, context) {
    // Attribute (非响应式对象)
    console.log(context.attrs)

    // 插槽 (非响应式对象)
    console.log(context.slots)

    // 触发事件 (方法)
    console.log(context.emit)
  }

//解构
 setup(props, { attrs, slots, emit }) {
    ...
  }
  • 访问组件的 property。执行 setup 时,组件实例尚未被创建,只能够访问到props、attrs、slots、emit,不能访问data、computed、methods
  • 在setup()中不使用this,因为这时候组件实例还没有被创建。但是你可以使用context来获取当前组件的实例

setup的使用

setup相当于data、 methods、watch的组合。

data+methods

<template>
  <div>
    <el-button type="primary" @click="addNumber">加一</el-button>
    <div>现在的值是:{{ number }}</div>
  </div>
</template>

<script>
//import { ref } from 'vue'
export default {
  name: "HelloWorld",
  props: {},
  setup() {
    let number = 0;
    function addNumber() {
      number += 1;
    }
    return {
      number,
      addNumber,
    };
  },

};
</script>

<style scoped>
</style>

在这里插入图片描述

一点反应都没有,因为他不是响应式的。按照官方文档你还需要使用一个新的 ref 函数,将它变成响应式的。

<script>
import { ref } from "vue";
export default {
  name: "HelloWorld",
  props: {},
  setup() {
    let number = ref(0);
    function addNumber() {
      number.value += 1;
    }
    return {
      number,
      addNumber,
    };
  },
};
</script>
ref 接收参数并将其包裹在一个带有 value property 的对象中返回,然后可以使用该 property 访问或更改响应式变量的值

在这里插入图片描述

简单试了一下,3.0是兼容2.0的

<script>
import { ref } from "vue";
export default {
  name: "HelloWorld",
  props: {},
  setup() {
    let number = ref(0);
    // function addNumber() {
    //   number.value += 1;
    // }
    return {
      number,
      // addNumber,
    };
  },
  methods: {
    addNumber() {
      this.number += 1;
    },
  },
};
</script>

这样也是可以正常运行的。但是既然打算用3.0就用3.0的语法去写,不要既有3.0又有2.0,这样更加影响后期的维护。

在setup中使用生命周期函数

在2.0中一般在mounted中调用初始化数据的函数,在3.0中可以在onMounted中调用函数

setup() {
    let number = ref(0);
    function addNumber() {
      setTimeout(() => {
        number.value += 1;
      }, 3000);
    }
    //初始化数据
    onMounted(addNumber);
    return {
      number,
      addNumber,
    };
  },

在setup中使用监听

在3.0中监听也有一些区别,watch同样需要写在setup中,另外watch函数有两个参数,第一个是要监听的参数,第二个是响应的回调函数

<script>
import { watch, ref } from "vue";
export default {
  name: "HelloWorld",
  props: {},
  setup() {
    let number = ref(0);
    function addNumber() {
      number.value += 1;
    }
    //方式一,ref创建
    watch(number, (nValue, oValue) => {
      console.log("新值:" + nValue, "旧值:" + oValue);
    });
    return {
      number,
      addNumber,
    };
  },
};
</script>

//方式二,reactive创建
let number = reactive({ number: 0 });
watch(
   () =>number.number,
   (nval) => {
     console.log(nval);
   }
 );
  • ref和reactive两种监听方式,实际上就是非对象响应式变量和对象响应式变量
  • 关于props属性的监听,props是一个对象,要采用第二种方式才能实现监听(第一种试过了,没有反应)
watch(
   () => props.msg,
   (nval) => {
     console.log(nval);
   }
 );

在setup中使用computed
computed与watch的使用类似,这里就不介绍了。

渲染是函数方式

import { h, reactive, ref } from "vue";
export default {
    name: "test",
    props: {},
    setup() {
        const readersNumber = ref(0)
        const book = reactive({ title: 'Vue 3 Guide' })
        // 请注意这里我们需要显式调用 ref 的 value
        return () => h('div', [
            h('p', { style: 'font-size:30px' }, readersNumber.value),
            h('p', { style: 'font-size:20px' }, book.title)
        ])
    },
};

渲染时的方式不熟,有感兴趣的可以自己去百度。
在这里插入图片描述
注:

  • ref要访问value,reactive访问自己定义的属性。
  • ref好像一般用于number、string、array、Boolean等类型;reactive用于对象类型(ref也可以用于对象,不过比reactive多嵌套一层)
  • 其他区别不清楚,没仔细研究。

生命周期函数

这个没什么好说的,看官方文档就好。

生命周期钩子

模板引用

普通元素的引用

<template>
  <div>
    <p ref="refP">元素上的ref</p>
  </div>
</template>

<script>
import { onMounted, ref } from "vue";
export default {
  setup() {
    let refP = ref(null);

    onMounted(() => {
      console.log(refP);
    });
    return {
      refP,
    };
  },
};
</script>

注:要等到元素全都初始化后,才能绑定到元素上

在这里插入图片描述

v-for循环中的引用

<template>
  <div v-for="(item, i) in list" :ref="el => { if (el) divs[i] = el }">
    {{ item }}
  </div>
</template>

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

  export default {
    setup() {
      const list = reactive([1, 2, 3])
      const divs = ref([])

      // 确保在每次更新之前重置ref
      onBeforeUpdate(() => {
        divs.value = []
      })

      return {
        list,
        divs
      }
    }
  }
</script

补充

就文章开头推荐的那篇文章:vue3 composition(组合式)API 是什么?我为什么要使用它?
我非常推荐这样的写法(我自己也会这样写),这样可以避免2.0中代码从上往下,不同的业务逻辑相互交叉。这会造成后期的维护十分困难;而拆分组合的方式更方便维护

遇到的问题:

会出现业务逻辑交叉的情况
举一个例子,有一个新增弹窗,弹窗新增的数据会显示在主页面的表格里。正常情况是新增弹窗的相关逻辑放在一个函数块里,主页面表格的逻辑放在一个函数块里。
这里的问题是:当新增完弹窗关闭后,你应该重新获取一下表格的数据,但是相应的逻辑是分离的

解决如下:

// 处理表格的相关业务逻辑
let handleTable = () => {
  
  //逻辑1
  //逻辑2
  //逻辑n
 
 //获取数据的方法
 let getData = () => {}

 return {
      ......
      getData
 }
}

//处理新增的相关逻辑
let handleAdd = () =>{
   let { getData } = {...handleTable()}

   //关闭弹窗的逻辑
   let closeDialog = () =>{
         //其他逻辑
         //刷新数据
         getData();
   }

}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无知的小菜鸡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值