Class与Style 绑定
绑定class和style ,可以绑定对象【非响应式对象、reactive对象或computed对象】或数组,数组元素可以是对象。
绑定class 如果绑定在组件上会透传到子组件上的class,如果组件只有一个根元素会与该元素的class 合并,如果有多个根元素,通过$attrs.class
来确定传给哪个元素。
- :class 指令也可以和一般的
class
attribute 共存。
子组件
<div class="$attrs.class">子组件<div>
<span class="test">test</span>
父组件
<Child class="child" :class="[oneClass,{[twoClass]:active}]" :style="[oneClass,{[twoClass]:active}]"></Child>
绑定的style样式会自动带上浏览器的兼容前缀,当然也可以自己用数组来给样式提供兼容性的值选项,最后渲染到浏览器上只会显示最后一个生效的。
- 推荐使用 camelCase,但 :style 也支持 kebab-cased 形式的 CSS 属性 key (对应其 CSS 中的实际名称)
- kebab-case 短横线命名法【烤肉串命名法】、camelCase 小驼峰命名法、 pascalCase 大驼峰命名法【帕斯卡命名法】、snakeCase【蛇式 -小蛇式、大蛇式】、匈牙利命名法【带上类型特征】
命名规则 Kebab-case、camelCase、Pascal case-优快云博客
<template>
<div :style="[oneStyleObj, twoStyleObj, threeStyleObjComputed, {
'align-items': 2 > 3 ? 'flex-end' : 'flex-start'
}]">测试style{{ threeClassComputed }}{{ fourClass }}</div>
<div :style="{
fourStyleObj: true
}">测试style1</div>
<div class="oldClass" :class="[oneClass, twoClass, { [threeClass]: true }]">测试class</div>
</template>
<script setup>
import { ref, computed, reactive } from 'vue';
const oneStyleObj = {
display: "flex",
"box-align": "center" //火狐浏览器独有
}
const twoStyleObj = ref({
"flex-direction": "row",
})
const threeStyleObj = reactive({
"justify-items": "flex-end"
})
const threeStyleObjComputed = computed(() => {
return threeStyleObj
})
// const fourStyleObj = {
// display: 'flex',
// "align-items": 'flex-end'
// }
const oneClass = "oneClass"
const twoClass = "twoClass"
const threeClass = "testClass"
</script>
<style>
.oneClass {
display: flex;
transition: all;
box-align: center; /* 火狐独有 绑定类不会自动添加前缀*/
}
</style>
条件和列表渲染
条件渲染: 模板中条件渲染通过v-if【v-else-if,v-else】、v-show指令实现,v-show 初始渲染开销更高,其原理是通过切换元素的display值实现,v-if 切换渲染开销更高,其原理是通过销毁和创建元素实现,惰性的,初始值如果为false 会不做任何处理。
<!-- template 标签渲染后不可见 v-show 不可用在此标签上-->
<template v-if="3>2">
<h1 v-if="false">Title</h1>
<!-- 可以有多个v-else-if-->
<p v-else-if="true">Paragraph 1</p>
<p v-else-if="true">Paragraph 21</p>
<p v-else>Paragraph 3</p>
<p v-show="2>1">Paragraph 4</p>
</template>
列表渲染:使用v-for 指令,与v-if 需错开层级元素结合使用时,v-if 优先级更高。如果单单只想根据遍历数据的某些条件来判断是否显示和隐藏元素,可以使用computed计算属性来实现。
const numbers = ref([1, 2, 3, 4, 5])
在计算函数中使用变更原始数组的方法需谨慎,如reverse() 和 sort()方法,很容易导致渲染异常或无限循环
const evenNumbers = computed(() => {
return numbers.value.filter((n) => n % 2 === 0)
})
<li v-for="n in evenNumbers">{{ n }}</li>
- v-for 渲染元素列表时,最佳实践是给每个元素对应的块提供一个唯一的
key
attribute,vue会根据这个key值来高效复用元素,但使用索引来作为key值的话,如果元素的内部有依赖子组件状态或者有临时 DOM 状态 (例如表单输入值),可能会导致渲染异常问题。默认会使用索引作为key值。key
绑定的值期望是一个基础类型的值使用基础类型的值,不要用对象作为v-for
的key。
当你使用 `<template v-for>` 时,`key` 应该被放置在这个 `<template>` 容器
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>
- 组件上使用
v-for
组件有自己独立的作用域。为了将迭代后的数据传递到组件中,我们还需要传递 props
<MyComponent
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
/>
不自动将 item 注入组件的原因是,这会使组件与 v-for 的工作方式紧密耦合。明确其数据的来源可以使组件在其他情况下重用。
- 嵌套数组
const sets = ref([
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10]
])
//方法
function even(numbers) {
return numbers.filter((number) => number % 2 === 0)
}
<ul v-for="numbers in sets">
<li v-for="n in even(numbers)">{{ n }}</li>
</ul>
- 综合案例
<template>
<button @click="addItem">【给input 输入值后,点击看看】点击我添加项</button>
<li v-for="({ message }, index) in items" :key="index">
in --- {{ index }} - {{ message }}
未绑定响应值的html 元素- 有问题,注意!!:<input type="text"><br>
绑定响应值的html 元素-没有问题:<input :value="message" type="text"><br>
</li>
<br>
--------------------
<br>
<!-- in of 语法 数组-->
<li v-for="({ message }, index) of items" :key="index">
in --- {{ index }} - {{ message }}
</li>
<li v-for="({ message }, index) of items" :key="index">
of --- {{ index }} - {{ message }}
</li>
<ul>
<!-- of 语法 对象 -->
<li v-for="(value, key, index) of myObject" :key="index">
{{ index }}. {{ key }}: {{ value }}
</li>
</ul>
--------------------
<!-- in 语法 对象 -->
<ul>
<li v-for="(value, key, index) in myObject" :key="index">
{{ index }}. {{ key }}: {{ value }}
</li>
</ul>
<!-- n从1开始 -->
<span v-for="n in 10" :key="n">{{ n }}-</span>
</template>
<script setup>
import { ref, reactive } from 'vue';
const items = ref([{ message: 'Bar0' }, { message: 'Bar1' }, { message: 'Bar2' }, { message: 'Bar3' }, { message: 'Bar4' }])
const willAddItem = { message: 'Bar-1' }
const addItem = () => {
items.value.unshift(willAddItem)
}
const myObject = reactive({
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
})
</script>
事件处理
模板中使用v-on指令【简写为@】来监听事件,并在事件触发时执行对于的JavaScript。
用法:v-on:click="handler"
或@click="handler"
事件处理器(handler)分为内联事件处理器和方法事件处理器。
- 内联事件处理器:事件被触发时执行的内联 JavaScript 语句 (与
onclick
类似)。通常用于简单场景。
<button @click="count++">Add 1</button>
<p>Count is: {{ count }}</p>
const count = ref(0)
- 方法事件处理器:一个指向组件上定义的方法的属性名或是路径。
const name = ref('Vue.js')
//允许我们向方法传入自定义参数以代替原生事件
function greet(msg,event) {
alert(msg+` ${name.value}!`)
// `event` 是 DOM 原生事件
if (event) {
//event.target 访问到该 DOM 元素
alert(event.target.tagName)
}
}
有时我们需要在内联事件处理器中访问原生 DOM 事件。你可以向该处理器方法传入一个特殊的 $event 变量,或者使用内联箭头函数
<!-- `greet` 是上面定义过的方法名 -->
<button @click="greet('Hello',$event)">Greet</button>
<!-- `greet` 箭头函数传入-->
<button @click="event=>greet('Hello',event)">Greet</button>
事件可带修饰符【修饰符可链式书写】:
- 事件修饰符:.once、.capture、.prevent、.stop、.passive、.self
- 使用修饰符时需要注意调用顺序,因为相关代码是以相同的顺序生成的。因此使用
@click.prevent.self
会阻止元素及其子元素的所有点击事件的默认行为,而@click.self.prevent
则只会阻止对元素本身的点击事件的默认行为。 - .passive 修饰符表明了你不想阻止事件的默认行为,一般用于触摸事件的监听器,可以用来改善移动端设备的滚屏性能,与.prevent 同时使用会忽略.prevent修饰符,并且浏览器会抛出警告。
- 使用修饰符时需要注意调用顺序,因为相关代码是以相同的顺序生成的。因此使用
<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>
<!-- 提交事件将不再重新加载页面 -->
<form @submit.prevent="onSubmit"></form>
<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>
<!-- 也可以只有修饰符 -->
<form @submit.prevent></form>
<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="doThat">...</div>
<!-- 添加事件监听器时,使用 `capture` 捕获模式 -->
<!-- 例如:指向内部元素的事件,在被内部元素处理前,先被外部处理 -->
<div @click.capture="doThis">...</div>
<!-- 点击事件最多被触发一次 -->
<a @click.once="doThis"></a>
<!-- 滚动事件的默认行为 (scrolling) 将立即发生而非等待 `onScroll` 完成 -->
<!-- 以防其中包含 `event.preventDefault()` -->
<div @scroll.passive="onScroll">...</div>
-
按键修饰符【键盘事件】:.enter、.esc、.tab、.space、.delete(捕获“Delete”和“Backspace”两个按键)、.up、.down、.left、.right等
- 可以直接使用
KeyboardEvent.key
暴露的按键名称作为修饰符,但需要转为 kebab-case 形式。
<input @keyup.page-down="onPageDown" />
- 可以直接使用
-
系统修饰符【触发鼠标或键盘事件监听器】:.shift、.ctrl、.alt、.meta、.exact(
.exact
修饰符允许精确控制触发事件所需的系统修饰符的组合。)- Mac 键盘上,meta 是 Command 键 (⌘)。在 Windows 键盘上,meta 键是 Windows 键 (⊞)。在 Sun 微机系统键盘上,meta 是钻石键 (◆)。在某些键盘上,特别是 MIT 和 Lisp 机器的键盘及其后代版本的键盘,如 Knight 键盘,space-cadet 键盘,meta 都被标记为“META”。在 Symbolics 键盘上,meta 也被标识为“META”或“Meta”。
系统按键修饰符和常规按键不同。与 keyup 事件一起使用时,该按键必须在事件发出时处于按下状态。换句话说,keyup.ctrl 只会在你仍然按住 ctrl 但松开了另一个键时被触发。若你单独松开 ctrl 键将不会触发
<!-- Alt + Enter -->
<input @keyup.alt.enter="clear" />
<!-- Ctrl + 点击 -->
<div @click.ctrl="doSomething">Do something</div>
<!-- 当按下 Ctrl 时,即使同时按下 Alt 或 Shift 也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 仅当按下 Ctrl 且未按任何其他键时才会触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 仅当没有按下任何系统按键时触发 -->
<button @click.exact="onClick">A</button>
- 鼠标修饰符【处理程序限定为由特定鼠标按键触发的事件】:.left、.right、.middle
请注意,.left,.right 和 .middle 这些修饰符名称是基于常见的右手用鼠标布局设定的,但实际上它们分别指代设备事件触发器的“主”、”次“,“辅助”,而非实际的物理按键。
<button @click.right="onClick('按下鼠标辅助功能键,一般是鼠标右键')">按下鼠标辅助功能键,一般是鼠标右键</button>
const onClick = (msg) => {
alert(msg)
}
表单输入绑定
表单输入绑定使用v-model 指令【是手动连接值绑定和更改事件监听器的语法糖】。
//这样如果有多个比较麻烦
<input
:value="text"
@input="event => text = event.target.value">
//vue 使用v-model 简化该步骤
<input v-model="text">
v-model
还可以用于各种不同类型的输入,<textarea>
、<select>
元素。它会根据所使用的元素自动使用对应的 DOM 属性和事件组合:
- 文本类型的
<input>
和<textarea>
元素会绑定value
property 并侦听input
事件; <input type="checkbox">
和<input type="radio">
会绑定checked
property 并侦听change
事件;<select>
会绑定value
property 并侦听change
事件。- v-model会忽略任何表单元素上初始的
value
、checked
或selected
attribute,它将始终将当前绑定的 JavaScript 状态视为数据的正确来源。你应该在 JavaScript 中使用响应式系统的 API来声明该初始值。
基本用法:
- 单个多选框,绑定值是布尔值。选择器的
v-model
表达式的初始值不匹配任何一个选择项,<select>
元素会渲染成一个“未选择”的状态。在 iOS 上,这将导致用户无法选择第一项,因为 iOS 在这种情况下不会触发一个 change 事件。因此,我们建议提供一个空值的禁用选项。
//v-for 动态渲染
<select v-model="selected">
<option v-for="option in options" :value="option.value" :disabled="option?.disbaled">
{{ option.text }}
</option>
</select>
<div>Selected: {{ selected }}</div>
const selected = ref('A')
const options = ref([
{ text: 'Please select one', value: '',disabled:true },
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
])
- 单个复选框可以通过绑定true-value、false-value来绑定选择或未选择值,表单不会提交未选择的多选框,为了保证这两个值 (例如:“yes”和“no”) 的其中之一被表单提交,请使用单选按钮作为替代。
- 对于单选按钮,复选框和选择器选项,
v-model
绑定的值通常是静态的字符串 (或者对复选框是布尔值)。如果想绑定到当前组件实例的动态数据,使用v-bind指令实现。此外,使用v-bind
还使我们可以将选项值绑定为非字符串的数据类型
<!-- `picked` 在被选择时是字符串 "a" -->
<input type="radio" v-model="picked" value="a" />
<!-- `toggle` 只会为 true 或 false -->
<input type="checkbox" v-model="toggle" />
<!-- `selected` 在第一项被选中时为字符串 "abc" -->
<select v-model="selected">
<option value="abc">ABC</option>
</select>
<!-- ----------- 动态绑定 ------------- -->
<input
type="checkbox"
v-model="toggle"
:true-value="dynamicTrueValue"
:false-value="dynamicFalseValue" />
<select v-model="selected">
<!-- 内联对象字面量 -->
<option :value="{ number: 123 }">123</option>
</select>
- 综合案例
<template>
<br>-----------单行文本输入框---------------<br>
<p>Message is: {{ message }}</p>
<input v-model="message" placeholder="edit me" />
<br>-----------多行文本输入框---------------<br>
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ areaMessage }}</p>
<textarea v-model="areaMessage" placeholder="add multiple lines"></textarea>
<br>-----------复选框-多选项---------------<br>
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
<br>-----------复选框-多选项---------------<br>
<div>Checked names: {{ checkedNames }}</div>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames" />
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
<label for="mike">Mike</label>
<br>-----------单选框---------------<br>
<div>Picked: {{ picked }}</div>
<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>
<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>
<br>-----------复选框---------------<br>
<div>Selected: {{ selected }}</div>
<select v-model="selected">
<option disabled value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<br>-----------多选复选框---------------<br>
<div>selectedTwo: {{ selectedTwo }}</div>
<select v-model="selectedTwo" multiple>
<option value="C">A</option>
<option value="B">B</option>
<option value="A">C</option>
</select>
<br>------------true-value 和 false-value 是 Vue 特有的 attributes,仅支持和 v-model 配套使用。-------------- <br>
toggle: {{ toggle }}
<input type="checkbox" v-model="toggle" true-value="yes" false-value="no" />
</template>
<script setup>
import { ref } from "vue"
const message = ref('') //单行文本输入框
const areaMessage = ref('') //多行文本输入框
const checked = ref('') //单个选项的复选框
const checkedNames = ref([]) //多个选项的复选框
const picked = ref('') //单选按钮
const selected = ref('') //选择器
const selectedTwo = ref([]) //选择器2
const toggle = ref('') //true-value 、false-value
</script>
修饰符
- .lazy:默认情况下,
v-model
会在每次input
事件后更新数据 (IME 拼字阶段的状态例外)。你可以添加lazy
修饰符来改为在每次change
事件后更新数据。 - .number:将用户输入自动转换为数字,如果parseFloat无法转换,如果该值无法被
parseFloat()
处理,那么将返回原始值。特别是当输入为空时 (例如用户清空输入字段之后),会返回一个空字符串。number
修饰符会在输入框有type="number"
时自动启用。 - .trim:自动去除用户输入内容中两端的空格。
<!-- 在 "change" 事件后同步更新而不是 "input" -->
<input v-model.lazy="msg" />
<input v-model.number="age" />
<input v-model.trim="msg" />
组件上的 v-model : HTML 的内置表单输入类型并不总能满足所有需求。幸运的是,我们可以使用 Vue 构建具有自定义行为的可复用输入组件,并且这些输入组件也支持 v-model
!
侦听器
在有些情况下,我们需要在状态变化时执行一些“副作用”:例如更改 DOM,或是根据异步操作的结果去修改另一处的状态。vue的组合式API中watch函数选项式API通过watch 选项在响应式状态发生变化时触发回调函数。
//组合式API
const 返回值 = watch({
数据源,
回调:(新值,旧值 , 清除函数)=>{ ... },
选项
})
//选项式API
watch:{
数据源(新值、旧值){
回调
}
}
watch的数据源可以是一个 ref (包括计算属性)、一个响应式对象、一个 getter 函数、或上述组成的数组。
<template>
<button @click="changeWatchValue">修改</button>
{{ x }} {{ y }}
</template>
<script setup>
import { ref, watch } from 'vue';
let x = ref(0)
let y = 0
// getter 函数
watch(
[x, y], //() => x.value + y 一样的效果
(sum, preSum) => {
console.log("preSum:" + preSum)
console.log(`sum of x + y is: ${sum}`)
}
)
function changeWatchValue() {
x.value++
y++
console.log(x, y)
}
</script>
直接给 watch()
传入一个响应式对象,会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发。
const obj = reactive({ count: 0 })
watch(obj, (newValue, oldValue) => {
// 在嵌套的属性变更时触发
// 注意:`newValue` 此处和 `oldValue` 是相等的
// 因为它们是同一个对象!
})
obj.count++
相比之下,一个返回响应式对象的 getter 函数,只有在返回不同的对象时,才会触发回调。
watch(
() => state.someObject,
(newValue, oldValue) => {
// 注意:`newValue` 此处和 `oldValue` 是相等的
// *除非* state.someObject 被整个替换了
},
//3.5+版本,deep选项可以是一个数字,表示最大遍历深度——即 Vue 应该遍历对象嵌套属性的级数,深度侦听需要遍历被侦听对象中的所有嵌套的属性,当用于大型数据结构时,开销很大。因此请只在必要时才使用它,并且要留意性能。
{ deep: true } //强制转成深层侦听器
)
注意,你不能直接侦听响应式对象的属性值,例如:
const obj = reactive({ count: 0 })
// 错误,因为 watch() 得到的参数是一个 number
watch(obj.count, (count) => {
console.log(`Count is: ${count}`)
})
//这里需要用一个返回该属性的 getter 函数
watch(
() => obj.count,
(count) => {
console.log(`Count is: ${count}`)
}
)
回调
watch(id, (newId, oldId, onCleanup) => {
//通过函数参数传递的 onCleanup 与侦听器实例相绑定,因此不受 onWatcherCleanup 的同步限制
onCleanup(() => { //3.5 之前的版本有效
// 清理无效副作用
})
})
watchEffect((onCleanup) => {
// ...
onCleanup(() => { //3.5 之前的版本有效
// 清理逻辑
})
})
选项
- immediate【即时回调的侦听器】:
watch
默认是懒执行的:仅当数据源变化时,才会执行回调。immediate: true
选项来强制侦听器的回调立即执行。
watch(
source,
(newValue, oldValue) => {
// 立即执行,且当 `source` 改变时再次执行
},
{ immediate: true }
)
- once【一次性侦听器,3.4+版本】:每当被侦听源发生变化时,侦听器的回调就会执行。如果希望回调只在源变化时触发一次,请使用
once: true
选项
watch(
source,
(newValue, oldValue) => {
// 当 `source` 变化时,仅触发一次
},
{ once: true }
)
-
flush【回调执行时机】 :pre、post、sync。类似于组件更新,用户创建的侦听器回调函数也会被批量处理以避免重复调用。默认情况下,侦听器回调会在父组件更新 (如有) 之后、所属组件的 DOM 更新之前被调用。这意味着如果你尝试在侦听器回调中访问所属组件的 DOM,那么 DOM 将处于更新前的状态。
- watchEffect 【默认-在父组件更新后,自身更新前】:侦听器的回调使用与源完全相同的响应式状态是很常见的。例
const todoId = ref(1) const data = ref(null) watch( todoId, async () => { const response = await fetch( `https://jsonplaceholder.typicode.com/todos/${todoId.value}` ) data.value = await response.json() }, { immediate: true } )
使用watchEffect函数简化上面代码,自动跟踪回调的响应式依赖
//回调立即执行,不需要指定 immediate: true。在执行期间,它会自动追踪 todoId.value 作为依赖(和计算属性类似)。每当 todoId.value 变化时,回调会再次执行。 watchEffect(async () => { const response = await fetch( `https://jsonplaceholder.typicode.com/todos/${todoId.value}` ) data.value = await response.json() })
注意:
watchEffect
仅会在其同步执行期间,才追踪依赖。在使用异步回调时,只有在第一个await
正常工作前访问到的属性才会被追踪。watch函数没这问题。 下面是案例<template> <button @click="changeWatchValue">修改</button> {{ x }} {{ y }} </template> <script setup async> import { ref, watch } from 'vue'; const todoId = ref(1) const data = ref(null) //干扰作用 const response = await fetch( `https://jsonplaceholder.typicode.com/todos/${todoId.value}` ) console.log(response) const x = ref(1) const y = ref(1) //使用watch 侦听 页面的y值会更新 watch( x, async (newValue) => { const response = await fetch( `https://jsonplaceholder.typicode.com/todos/${todoId.value}` ) data.value = await response.json() y.value = newValue * newValue }, { immediate: true } ) //使用watchEffect 侦听 页面的y值不会更新 // watchEffect(async () => { // const response = await fetch( // `https://jsonplaceholder.typicode.com/todos/${todoId.value}` // ) // data.value = await response.json() // y.value = x.value * x.value // }) function changeWatchValue() { x.value++ } </script>
- watchPostEffect – post 侦听器 【在DOM更新后执行】:后置刷新的
watchEffect()
有个更方便的别名watchPostEffect()
watch(source, callback, { flush: 'post' })
- watchSyncEffect – 同步侦听器【进行任何更新之前触发】: 用于清除缓存,同步触发的
watchEffect()
有个更方便的别名watchSyncEffect()
注意: 同步侦听器不会进行批处理,每当检测到响应式数据发生变化时就会触发。可以使用它来监视简单的布尔值,但应避免在可能多次同步修改的数据源 (如数组) 上使用。
watch(source, callback, { flush: 'sync' })
-
deep【深层侦听器】
watch函数返回值
在 setup()
或 <script setup>
中用同步语句创建的侦听器,会自动绑定到宿主组件实例上,并且会在宿主组件卸载时自动停止。因此,在大多数情况下,你无需关心怎么停止一个侦听器。
一个关键点是,侦听器必须用同步语句创建:如果用异步回调创建一个侦听器,那么它不会绑定到当前组件上,你必须手动停止它,以防内存泄漏。如下方这个例子:
<script setup>
import { watchEffect } from 'vue'
// 它会自动停止
watchEffect(() => {})
// ...这个则不会!
setTimeout(() => {
watchEffect(() => {})
}, 100)
//要手动停止一个侦听器,请调用 watch 或 watchEffect 返回的函数
const unwatch = watchEffect(() => {})
// ...当该侦听器不再需要时
unwatch()
</script>
注意,需要异步创建侦听器的情况很少,请尽可能选择同步创建。如果需要等待一些异步数据,你可以使用条件式的侦听逻辑。
- onWatchCleanUp(3.5+):使用
onWatcherCleanup()
API 来注册一个清理函数,当侦听器失效并准备重新运行时会被调用。
import { watch, onWatcherCleanup } from 'vue'
watch(id, (newId) => {
const controller = new AbortController()
fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {
// 回调逻辑
})
//必须在 watchEffect 效果函数或 watch 回调函数的同步执行期间调用:你不能在异步函数的 await 语句之后调用它
onWatcherCleanup(() => {
// 终止过期请求
controller.abort()
})
})
- stop、pause、resume 【3.5+版本】
const { stop, pause, resume } = watch(() => {})
// 暂停侦听器
pause()
// 稍后恢复
resume()
// 停止
stop()
带你吃透 Vue3 中 侦听器 【watch ,watchEffect】数据监听的使用及注意事项_watcheffect深度监听-优快云博客