赞
踩
在 vue3 的 setup 里使用 computed、watch 和 watchEffect,一定记得先引入 computed、watch 和 watchEffect。
在 vue3 中,computed 可以在 setup 函数里实现。除了写法不一样,功能上与 vue2 中的 computed 是一致的。
其中,defineComponent 以及 <script setup> 都是 setup 的语法糖。
例如:
<template>
<div>{{ fullName }}</div>
</template>
<script>
import { ref, computed } from 'vue'
export default {
setup() {
const firstName = ref('hello')
const lastName = ref('world')
const fullName = computed(() => {
return firstName.value + '-·-' + lastName.value
})
return {
firstName,
lastName,
fullName
}
}
}
</script>
defineComponent 函数是 vue3 的语法糖:
例如:
<template>
<div>{{ fullName }}</div>
</template>
<script>
import { defineComponent, ref, computed } from 'vue'
export default defineComponent({
setup() {
const firstName = ref('hello')
const lastName = ref('world')
const fullName = computed(() => {
return firstName.value + '-·-' + lastName.value
})
return {
firstName,
lastName,
fullName
}
}
})
</script>
<script setup> 是 vue3 的新的语法糖,之前的组合 API 相比:
return
,使用 <script setup> 后就不必了。例如:
<template>
<div>{{ fullName }}</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('hello')
const lastName = ref('world')
const fullName = computed(() => {
return firstName.value + '-·-' + lastName.value
})
</script>
当 computed 有 getter 和 setter 时,需要传入一个对象而不是一个函数作为 computed 的参数,然后在 computed 中实现 get 和 set 两个属性方法。
例如:
<template>
<div> firstName: {{ firstName }} </div>
<div> lastName: {{ lastName }} </div>
<div> fullName: {{ fullName }} </div>
</template>
<script>
import { reactive, toRefs, computed } from 'vue'
export default {
setup() {
const user = reactive({
firstName: 'hello',
lastName: 'world'
})
const fullName = computed({
get() {
return user.firstName + '-·-' + user.lastName
},
set(val) {
const nameList = val.split('-·-')
user.firstName = nameList[0]
user.lastName = nameList[1]
}
})
return {
...toRefs(user),
fullName
}
}
}
</script>
推荐优先考虑使用 watchEffect。
immdiate: true
)。在 vue3 中,watch 可以在 setup 函数里实现。除了写法不一样,功能上与 vue2 中的 watch 以及 $watch 是一致的。
setup 里的 watch 完全等同于组件侦听器 property。watch 需要侦听特定的数据源,并在回调函数中执行副作用。默认情况下,它也是惰性的,即只有当被侦听的源发生变化时才执行回调。
watch 的工作原理:侦听特定的数据源,并在回调函数中执行副作用。它默认是惰性的——只有当被侦听的源发生变化时才执行回调,不过,可以通过配置 immediate 为 true 来指定初始时立即执行第一次。可以通过配置 deep 为 true,来指定深度监视。
watch 的两个属性:
例如:
<template>
<div>
<span>姓名:</span>
<input type="text" v-model="name" />
</div>
<div>
<span>年龄:</span>{{ age }}
<input type="button" value="+" @click="age++" />
</div>
</template>
<script>
import { ref, toRefs, watch } from 'vue'
export default {
setup() {
const name = ref('小樱')
const age = ref(0)
const selectLoves = ref([])
const user = ref({ age: 0, gender: '女' })
// 侦听一个 ref
watch(age, (newValue, oldValue) => {
console.log('111', newValue, oldValue)
}, { immdiate: true })
// 侦听多个 ref
watch([name, age], (newValue, oldValue) => {
console.log('222', newValue, oldValue)
}, { immdiate: true })
// 侦听一个数组
watch(selectLoves, (newVal, oldVal) => {
console.log('333', newVal, oldVal)
}, { immdiate: true })
// 侦听对象里的某个属性
watch(
() => user.gender,
(newValue, oldValue) => {
console.log('444', newValue, oldValue)
},
{ immdiate: true, deep: true }
)
// 侦听对象里的多个属性
watch(
[() => user.age, () => user.gender],
(newValue, oldValue) => {
console.log('555', newValue, oldValue)
},
{ immdiate: true, deep: true }
)
return { ...toRefs(user), name, age, selectLoves }
}
}
</script>
直接侦听一个对象时,建议:直接侦听对象里的具体的属性,而不是侦听对象本身。
【注意】:直接侦听一个对象时有 2 点需要注意:
deep: true
),且将 deep 置为 false 无效。watch 和 watchEffect 都能响应式地执行有副作用的回调。它们之间的主要区别是追踪响应式依赖的方式:
例如:
<template>
<h1>Vue3新特性 -watchEffect 监听属性</h1>
<div>
<p>{{name}}</p>
<p>{{nameObj.name}}</p>
</div>
</template>
<script>
import { ref, reactive, watch, watchEffect } from 'vue'
export default {
setup() {
// 监听基本类型
const name = ref('张三')
setTimeout(() => {
name.value = '李四'
}, 1000)
watch(name, (newVal, oldVal) => {
console.log(newVal, oldVal)
}, {immediate: true}) //立即执行
//监听复杂类型
const nameObj = reactive({name: 'zhangsan'})
setTimeout(() => {
nameObj.name = 'list'
}, 2000)
//复杂数据无法直接监听、惰性
watch(() => nameObj, (newVal, oldVal) => {
console.log(newVal, oldVal) //不会触发
})
//需要深度监听、不惰性
watch(() => nameObj, (newVal, oldVal) => {
console.log(newVal, oldVal) //newVal、oldVal具有响应式
}, { deep: true })
//也可以直接监听对象的属性
watch(() => nameObj.name, (newVal, oldVal) => {
console.log(newVal, oldVal)
})
// 同时监听多个对象的属性
watch([() => nameObj.name, () => nameObj.lastName], ([newName, newLastName], [oldName, oldLastName]) => {
console.log(newName, oldName, newLastName, oldLastName)
})
const stop = watchEffect(() => {
console.log(name);
console.log(nameObj.name);
})
// 5秒后停止监听
setTimeout(()=>{
stop()
},5000)
return {
name,
nameObj
}
}
}
</script>
当你更改了响应式状态,它可能会同时触发 Vue 组件更新和侦听器回调。
默认情况下,用户创建的侦听器回调,都会在 Vue 组件更新之前被调用。这意味着你在侦听器回调中访问的 DOM 将是被 Vue 更新之前的状态。
vue3 给 watchEffect 提供了 flush 属性,用来调整回调函数的刷新时机。并分别为他们起了别名:
flush 有 3 个值可以选择:
如果想在侦听器回调中能访问被 Vue 更新之后的 DOM,你需要指明 flush: ‘post’ 选项:
watch(source, callback, {
flush: 'post'
})
watchEffect(callback, {
flush: 'post',
onTrack(e) {
debugger
},
onTrigger(e) {
debugger
}
})
上述代码,可简写为:
import { watchPostEffect } from 'vue'
watchPostEffect(() => {
/* 在 Vue 更新后执行 */
})
同理 watchSyncEffect 也是同理。
【注意】:需要异步创建侦听器的情况很少,请尽可能选择同步创建。如果需要等待一些异步数据,你可以使用条件式的侦听逻辑:
// 需要异步请求得到的数据
const data = ref(null)
watchEffect(() => {
if (data.value) {
// 数据加载后执行某些操作...
}
})
假设我们定义了下面这个侦听器:
const count = ref(0)
watchEffect(() => console.log(count.value))
// -> 输出 0
count.value++
// -> 输出 1
副作用清除:
watchEffect(async (onCleanup) => {
const { response, cancel } = doAsyncWork(id.value)
// `cancel` 会在 `id` 更改时调用
// 以便取消之前
// 未完成的请求
onCleanup(cancel)
data.value = await response
})
停止侦听器:
const stop = watchEffect(() => {})
// 当不再需要此侦听器时:
stop()
【参考】
VUE3(十四)使用计算属性computed和监听属性watch
vue3的计算属性与watch
Vue 3 响应式侦听与计算
vue3计算属性(computed)与监听(watch)
vue3的 computed 计算属性 与 watch监听
watchEffect函数
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。