响应式基础
- 使用ref()函数来声明响应式状态,
ref()接收参数,并将其包裹在一个带有.value属性的 ref 对象中返回, 在模板中使用 ref 时,我们不 需要附加.value
javascript
import { ref } from 'vue'
const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0
reactive()将使对象本身具有响应性 ,
**reactive()**API 有一些局限性:
-
有限的值类型 :它只能用于对象类型 (对象、数组和如
Map、Set这样的集合类型)。它不能持有如string、number或boolean这样的原始类型。 -
不能替换整个对象:由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用。这意味着我们不能轻易地"替换"响应式对象,因为这样的话与第一个引用的响应性连接将丢失
-
对解构操作不友好:当我们将响应式对象的原始类型属性解构为本地变量时,或者将该属性传递给函数时,我们将丢失响应性连接
-
由于这些限制,我们建议使用
ref()作为声明响应式状态的主要 API
javascript
import { reactive } from 'vue'
const state = reactive({ count: 0 })
console.log(state.count) // 0
计算属性
- computed() 方法期望接收一个 getter函数,返回值为一个计算属性 ref。和其他一般的 ref 类似,可以通过.value 访问计算结果。计算属性 ref 也会在模板中自动解包,因此在模板表达式中引用时无需添加 .value。一个计算属性仅会在其响应式依赖更新时才重新计算。
- 从计算属性返回的值是派生状态。可以把它看作是一个"临时快照",每当源状态发生变化时,就会创建一个新的快照。更改快照是没有意义的,因此计算属性的返回值应该被视为只读的,并且永远不应该被更改------应该更新它所依赖的源状态以触发新的计算。
条件渲染
- v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染。
- 也可以使用 v-else 为 v-if 添加一个"else 区块"。
v-else-if提供的是相应于v-if的"else if 区块"。它可以连续多次重复使用:和v-else类似,一个使用v-else-if的元素必须紧跟在一个v-if或一个v-else-if元素后面v-show仅切换了该元素上名为display的 CSS 属性。- 当
v-if和v-for同时存在于一个元素上的时候,v-if会首先被执行。
列表渲染
-
可以使用 v-for 指令基于一个数组来渲染一个列表。v-for 指令的值需要使用 item in items 形式的特殊语法,其中 items 是源数据的数组,而 item 是迭代项的别名
javascriptconst items = ref([{ message: 'Foo' }, { message: 'Bar' }]) <li v-for="item in items"> {{ item.message }} </li>
当它们同时存在于一个节点上时,v-if 比 v-for 的优先级更高。这意味着 v-if 的条件将无法访 问到 v-for 作用域内定义的变量别名:
javascript
<!--
这会抛出一个错误,因为属性 todo 此时
没有在该实例上定义
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>
在外先包装一层 <template> 再在其上使用 v-for 可以解决这个问题 (这也更加明显易读):
javascript
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
事件处理
- 可以使用 v-on 指令 (简写为 @) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:click="handler" 或 @click="handler"
侦听器
-
计算属性允许我们声明性地计算衍生值。然而在有些情况下,我们需要在状态变化时执行一些"副作用":例如更改 DOM,或是根据异步操作的结果去修改另一处的状态。
在组合式 API 中,我们可以使用 watch 函数在每次响应式状态发生变化时触发回调函数:
javascript<script setup> import { ref, watch } from 'vue' const question = ref('') const answer = ref('Questions usually contain a question mark. ;-)') const loading = ref(false) // 可以直接侦听一个 ref watch(question, async (newQuestion, oldQuestion) => { if (newQuestion.includes('?')) { loading.value = true answer.value = 'Thinking...' try { const res = await fetch('https://yesno.wtf/api') answer.value = (await res.json()).answer } catch (error) { answer.value = 'Error! Could not reach the API. ' + error } finally { loading.value = false } } }) </script> <template> <p> Ask a yes/no question: <input v-model="question" :disabled="loading" /> </p> <p>{{ answer }}</p> </template>明天继续........