Vue3基础学习二

Class与Style 绑定

绑定class和style ,可以绑定对象【非响应式对象、reactive对象或computed对象】或数组,数组元素可以是对象。

绑定class 如果绑定在组件上会透传到子组件上的class,如果组件只有一个根元素会与该元素的class 合并,如果有多个根元素,通过$attrs.class 来确定传给哪个元素。

  • :class 指令也可以和一般的 classattribute 共存。
子组件
<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会忽略任何表单元素上初始的 valuecheckedselected 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深度监听-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值