Appearance
侦听器
watch
计算属性允许我们声明性地计算衍生值。然而在有些情况下,我们需要在状态变化时执行一些“副作用”:例如更改 DOM,或是根据异步操作的结果去修改另一处的状态。 在组合式 API 中,我们可以使用 watch 函数在每次响应式状态发生变化时触发回调函数
监听单个ref
js
<el-button type="primary" @click="updateNum">修改数字</el-button>
const num1 = ref(0);
watch(num1, (newNum, oldNum) => {
ElMessage(`旧数字:${oldNum},新数字是${newNum}`);
});监听getter函数
js
<el-button type="primary" @click="updateNum">修改数字</el-button>
const num1 = ref(0);
const num2 = ref(1);
const updateNum = () => {
num1.value = 1;
};
watch(
() => num1.value + num2.value,
(newSum, oldSum) => {
ElMessage(`旧的相加的和:${oldSum},新的相加的和是${newSum}`);
},
);监听对象的属性值
js
const personInfo = ref({
age: '18',
});
const updateObj = () => {
personInfo.value.age = '20';
};
// 监控对象的属性值:不能直接监控personInfo.value.age
// 这里需要用一个返回该属性的 getter 函数
watch(
() => personInfo.value.age,
(newAge, oldAge) => {
ElMessage(`之前的年龄是:${newAge},现在的年龄是${oldAge}`);
},
);监听响应式对象
js
const obj1 = reactive({
count: 0,
info: {
city: '郑州',
},
});
const updateReponseObj = () => {
obj1.info.city = '北京';
};
watch(obj1, (newValue, oldValue) => {
// 在嵌套的属性变更时触发
// 注意:`newValue` 此处和 `oldValue` 是相等的
// 因为它们是同一个对象!
ElMessage(`响应式对象触发:老的城市是${newValue.info.city},新的数是${oldValue.info.city}`);
});深度监听
js
<el-button type="primary" @click="updateTotalObj">监听响应式对象的getter</el-button>
// 监控响应式对象的getter:即监控下方的info对象的时候,只有在返回不同的对象时,才会触发回调
// 也可以给上面这个例子显式地加上 deep 选项,强制转成深层侦听器:
const obj2 = reactive({
count: 0,
info: {
city: '郑州',
},
});
const updateTotalObj = () => {
obj2.info.city = '桂林';
};
watch(
() => obj2.info,
(newValue, oldValue) => {
ElMessage(`不深层监控非响应式对象对象:老的城市是${newValue.city},新的数是${oldValue.city}`);
},
);
watch(
() => obj2.info,
(newValue, oldValue) => {
ElMessage(`深层监控非响应式对象对象:老的城市是${newValue.city},新的数是${oldValue.city}`);
},
{ deep: true },
);即时回调的侦听器
js
const computerBrand = ref('联想');
watch(
computerBrand,
(newValue, oldValue) => {
// 立即执行,且当 `computerBrand` 改变时再次执行
// 立即执行的话,
ElMessage(`立即回调的侦听器:老的品牌是${oldValue},新的品牌是${newValue}`);
},
// { immediate: true },
);watchEffect
js
1、初始化执行回调函数里面的代码
2、当回调函数里面有响应式的数据变化,执行回调函数的代码
3、回调函数的形参时清除函数onCleanUp,可以清除回调里面的挂载的属性和方法
4、参数2传递配置项,配置项目只有flush,分别时pre、post和sync,
代表挂载前/后/异步,默认情况下,用户创建的侦听器回调,都会在 Vue 组件更新之前被调用。这意
味着你在侦听器回调中访问的 DOM 将是被 Vue 更新之前的状态。
5、如果想在侦听器回调中能访问被 Vue 更新之后的 DOM,你需要指明 flush: 'post' 选项:
后置刷新的 watchEffect() 有个更方便的别名 watchPostEffect():
6、返回停止函数,停止侦听,会执行一次清除函数
在 setup() 或 <script setup> 中用同步语句创建的侦听器,
会自动绑定到宿主组件实例上,并且会在宿主组件卸载时自动停止。
因此,在大多数情况下,你无需关心怎么停止一个侦听器
一个关键点是,侦听器必须用同步语句创建:如果用异步回调创建一个侦听器,
那么它不会绑定到当前组件上,你必须手动停止它,以防内存泄漏。
这个不会自动停止
setTimeout(() => {
watchEffect(() => {})
}, 100)代码如下
js
<div>
{{ newValue }}
<button @click="newValue++">num++</button>
<button @click="stop">停止侦听</button>
<button @click="closeTimer">关闭定时器</button>
</div>
const newValue = ref(0)
const initCompleteFlag = ref(false)
const stop = watchEffect((onCleanUp) => {
console.log('pppooo')
let num2 = newValue.value
console.log('num2', num2)
// let timer = setInterval(() => {
// console.log('666')
// })
onCleanUp(() => {
console.log('清除')
// clearInterval(timer)
})
}, {
flush: 'pre'
})
const closeTimer = () => {
clearInterval()
}watch和watchEffect的区别
1、与watch不同,watchEffect不需要显式地指定要监听的数据,它会自动追踪函数内部使用的响应式数据。 2、watch具有一定的惰性lazy 第一次页面展示的时候不会执行,只有数据变化的时候才会执行;watchEffect在页面展示的时候就会执行一次,然后数据变化的时候还会执行一次。 watch也可以变为非惰性的 立即执行的 添加第三个参数 immediate: true 3、watch参数可以拿到当前值和原始值,watchEffect参数只能拿到当前值。