开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情
说点题外话
上一篇介绍了侦听器watch在option 选项式API中的用法和Vue3和解的Day6--侦听器watch:
- 我们知道了watch有三个参数:
handler
、deep
、immediate
- vue2由于响应式原理的问题watch只能侦听数据本身的变化,不能侦听数据内部的变化
- watch的第二种写法this.$watch
说正文
setup
组合式写法中我们不再使用data、watch等这些函数或者对象,我们又需要数据做到响应式,那么在组合式写法中官方引入了一个函数setup
,我们将所有的数据都放在setup函数中最后再返回出去。
setup的返回值可以在模板template中被使用,也就是我们可以通过setup的返回值来替代data选项。也是需要返回一个对象。
data和setup会同时生效,但是如果data选项和setup同时存在相同属性名称,会取setup中的值
<h2>{{ message }}</h2>
<script>
export default {
setup() {
return {
message: "我是代替data选项的"
}
}
}
</script>
ref和reactive
在vue3组合式API中,响应式数据不再定义在data函数里面,我们可以使用组合式提供的两种api实现数据响应式ref
和reactive
。
ref
ref是 renfence(引用)的缩写,ref会返回一个可变的响应式对象,该对象作为一个响应式引用,维护着它内部的值,它内部的值是在ref的value属性中被维护的。
这里我拿一个计数器举例
<template>
<div>
<h2>{{ counter }}</h2>
<button @click="addCounter">+1</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
// 1. ref定义数据
const counter = ref(0)
// 2. ref定义方法
const addCounter = () => counter.value++
// 3. 返回需要在模板中使用的数据或方法
return {
counter,
addCounter
}
}
}
</script>
我们会发现在template模板中我们是直接使用的counter, 但是在addCounter方法中是通过counter.value
进行的处理。ref会再template模板中进行自动解包,也就是我们可以直接调用变量名字;但是在我们需要操作这个变量的时候需要从value中取值
其实ref对数据进行解包也有条件限制:仅当 ref 是模板渲染上下文的顶层属性时才适用自动“解包”。 还是看案例说话
<template>
<div>
<h2>{{ info.counter + 1 }}</h2>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const counter = ref(0)
const info = {
counter
}
return { info }
}
}
</script>
此时状态栏的输出结果是
说明template模板对info对象里面的counter并没有被解析出来,也就验证了上面说的话,自动解析的数据一定是顶层元素。那如果我们不改变数据的结构,如何让页面展示我们想要的数据呢
答案很简单,和我们在setup函数中操作数据一样手动解析数据即可,也就是从value中取值。(如下0
<h2>{{ info.counter.value + 1 }}</h2>
reactive
如上文所见,ref在定义一个变量的时候绰绰有余,那如果我想要定义一个对象呢?那就需要另一个api了reactive
,这里还是以计数器为案例
<template>
<div>
<h2>{{ state.counter }}</h2>
<button @click="addCounter">+1</button>
</div>
</template>
<script>
import { reactive } from 'vue';
export default {
setup() {
const state = reactive({
counter: 0
})
const addCounter = () => state.counter++
return {
state,
addCounter
}
}
}
</script>
这里能看出来我们使用reactive定义响应式数据的时候,我们不再需要使用.value的形式操作数据。
那如果是更深层次的数组或者对象呢?页面是否能正常显示?是否能正常操作数据呢?
<template>
<div>
<h2>{{ state.counter }}</h2>
<h2>{{ state.foo.name }}</h2>
<button @click="addCounter">+1</button>
<button @click="changeName">改变名字</button>
</div>
</template>
<script>
import { reactive } from 'vue';
export default {
setup() {
const state = reactive({
counter: 0,
foo: {
name: "小白"
}
})
const addCounter = () => state.counter++
const changeName = () => state.foo.name = "小刚"
return {
state,
addCounter,
changeName
}
}
}
</script>
通过整个案例我们验证,针对更深层次的数据依然可以正常显示并且可以正常操作
那么再过分一点,我直接替换reactive定义的数据呢?
<template>
<div>
<h2>{{ state.counter }}</h2>
<button @click="addCounter">+1</button>
</div>
</template>
<script>
import { reactive } from 'vue';
export default {
setup() {
let state = reactive({
counter: 0,
})
const addCounter = () => {
state = reactive({ counter: 200 })
}
return {
state,
addCounter,
}
}
}
</script>
这次在点击按钮+1之后页面没有任何操作效果,说明这种方式并不能修改数据。
因为 Vue 的响应式系统是通过属性访问进行追踪的,因此我们必须始终保持对该响应式对象的相同引用。这意味着我们不可以随意地“替换”一个响应式对象,因为这将导致对初始引用的响应性连接丢失
总结
这里我们也可以做一个简单的总结:ref更适合我们定义一个String、Number、Boolean`类型的数据, 而reactive定义复杂数据类型Object。
setup语法糖
在vue3.2之后官方提出了setup语法糖的写法,直接省略了我们return的步骤,举例如下
<template>
<div>
<h2>{{ counter }}</h2>
<button @click="addCounter">+1</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
const counter = ref(100)
const addCounter = () => counter.value++
</script>
只需要直接定义变量即可,不需要我们在return出去定义的变量或方法
说再见
本来这一篇是要接着说侦听器watch的,但是在说组合式的侦听器之前忘记写一篇关于组合式响应式数据如何定义了,导致无法进行侦听器watch的讲解,这一篇就用大量的篇幅和代码说了定义变量的两种方式:ref
和reactive
, 下一篇我会接上一篇的进度继续说侦听器watch
难忘今宵
使人变胖的是糖分还是脂肪?
糖分和脂肪都是人的身体所需要的物质,但糖分和脂肪不会使人发胖,使人发胖的是糖脂混合物。