大家好,本篇文章我们继续学习和 Vue 相关的内容,今天我们归纳总结下如何使用 watch 监听组件中的数据变化,以及 computed 和 watch 的区别。
什么是 watch,以及如何使用?
watch 是 Vue.js 中用于监听数据变化的一种机制。它允许我们在数据发生变化时执行特定的操作。
在 Vue 中使用 watch 的方法如下:
在 Vue 组件中,定义一个 watch 对象,其中包含要监听的数据属性以及对应的回调函数。
watch: {
dataName: function(newValue, oldValue) {
// code
}
}
其中,dataName 是要监听的数据名称,newValue 是新的值,oldValue 是旧的值。
在 Vue 实例中,使用 $watch() 方法进行监听
vm.$watch('someData', function(newVal, oldVal) {
// do something with newVal
});
注意:watch 回调函数会在侦听的数据发生变化时立即执行,而 computed 属性只有在其依赖的数据发生变化时才会计算。
watch 通常用于监听一个数据的变化并执行复杂的业务逻辑,例如在某个数据变化后需要进行 HTTP 请求或者调用其他函数。
下面是一个简单的 watch 的例子:
<template>
<div>
<input v-model="message" type="text" placeholder="请输入内容">
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: '',
}
},
watch: {
message: function (newVal, oldVal) {
console.log('message changed from ' + oldVal + ' to ' + newVal)
}
},
}
</script>
在这个例子中,我们使用了 watch 来监听 message 的变化,并在数据变化时打印出更改前后的值。
当然,watch 还可以接收一个对象,其中可以定义多个监听器。这里有一个例子,它监听了多个数据:
watch: {
firstName: function (newVal, oldVal) {
console.log('firstName changed from ' + oldVal + ' to ' + newVal)
},
lastName: function (newVal, oldVal) {
console.log('lastName changed from ' + oldVal + ' to ' + newVal)
}
}
一些高级用法介绍
深度观察 (deep: true):如果你希望对对象内部属性的变化进行监听,可以使用 deep: true 选项。
data() {
user: {
name: 'John',
age: 25
}
},
watch: {
'user.name': function (val) {
console.log('user name changed:', val)
}
}
在这个例子中,我们监听了 user 对象中的 name 属性,当该属性变化时,会执行回调函数。
设置初始值 (immediate: true):如果你希望 watch 在组件创建时立即执行一次,可以使用 immediate: true 选项。
data() {
count: 0
},
watch: {
count: {
handler: function (val, oldVal) {
console.log('count changed');
},
immediate: true
}
}
异步处理 (handler):watch 的回调函数是异步执行的,这意味着如果有多个值在短时间内发生变化,回调函数只会在这些变化结束后执行一次。
watch: {
searchText: function (val) {
this.searching = true
setTimeout(() => {
this.searchData(val)
this.searching = false
}, 500)
}
}
在这个例子中,我们监听了 searchText 属性,并在数据变化后延迟 500 毫秒执行搜索操作。
使用 watch 观察器实现自动保存。
data() {
content: ''
},
watch: {
content: function (val) {
localStorage.setItem('content', val)
}
}
在这个例子中,我们监听了 content 属性,并在数据变化时自动保存到本地存储中。
应用场景介绍
watch 监听器还有许多其他的应用场景,例如:
- 在表单输入时进行验证,并显示错误消息。
- 在表格中进行排序和过滤。
- 在地图上实时显示用户位置。
- 监听路由变化并执行相应操作。
- 监听窗口大小变化并调整布局。
- 监听滚动事件并实现懒加载。
- ……
1、在表单输入时进行验证,并显示错误消息
<template>
<form>
<label>
Email:
<input v-model="email" @keyup="validateEmail"/>
</label>
<p v-if="error">{{ error }}</p>
</form>
</template>
<script>
export default {
data() {
return {
email: '',
error: ''
}
},
watch: {
email: {
immediate: true,
handler(val) {
if (!val.includes('@')) {
this.error = 'Invalid email address'
} else {
this.error = ''
}
}
}
}
}
</script>
2、在地图上实时显示用户位置
<template>
<div>
<div id="map"></div>
</div>
</template>
<script>
export default {
data() {
return {
userLocation: {
lat: 0,
lng: 0
},
map: null
}
},
mounted() {
this.map = new google.maps.Map(document.getElementById("map"), {
center: { lat: 0, lng: 0 },
zoom: 8
});
navigator.geolocation.getCurrentPosition(position => {
this.userLocation = {
lat: position.coords.latitude,
lng: position.coords.longitude
}
});
},
watch: {
userLocation: {
deep: true,
handler(val) {
this.map.setCenter(val);
new google.maps.Marker({
position: val,
map: this.map
});
}
}
}
}
</script>
在这个示例中,我们使用了 watch 来监听 userLocation 的变化,在用户位置发生变化时,使用 setCenter 方法将地图中心设置为用户当前位置,并使用 google maps API 在地图上添加一个标记,显示用户当前位置。
注意:这个例子需要引入 google maps 的 js 文件。
3、监听路由变化并执行相应操作
<template>
<!-- 省略 -->
</template>
<script>
export default {
watch: {
$route(to, from) {
// 根据路由变化执行相应操作
if (to.path === '/home') {
this.getHomeData()
} else if (to.path === '/about') {
this.getAboutData()
}
}
},
methods: {
getHomeData() {
// 获取首页数据
},
getAboutData() {
// 获取关于页数据
}
}
}
</script>
4、监听窗口大小变化并调整布局
<template>
<!-- 省略 -->
</template>
<script>
export default {
data() {
return {
windowWidth: 0
}
},
created() {
this.windowWidth = window.innerWidth
},
watch: {
windowWidth(newWidth, oldWidth) {
// 监听窗口大小变化并调整布局
if (newWidth < 768) {
// 小屏幕布局
} else {
// 大屏幕布局
}
}
},
mounted() {
window.addEventListener('resize', () => {
this.windowWidth = window.innerWidth
})
}
}
</script>
5、监听滚动事件并实现懒加载
<template>
<div class="container" ref="container" @scroll="handleScroll">
<img v-for="(item, index) in images" :key="index" :src="item.src" v-show="item.isLoaded" />
</div>
</template>
<script>
export default {
data() {
return {
images: [
{ src: 'image1.jpg', isLoaded: false },
{ src: 'image2.jpg', isLoaded: false },
{ src: 'image3.jpg', isLoaded: false },
// ...
]
}
},
mounted() {
// 初始化加载第一屏图片
this.lazyLoad();
},
methods: {
handleScroll() {
this.lazyLoad();
},
lazyLoad() {
const container = this.$refs.container;
const imageList = Array.from(container.querySelectorAll('img'));
// 遍历图片列表,如果图片进入了可视区域,就加载
imageList.forEach(img => {
if (this.isInViewport(img)) {
img.src = img.dataset.src;
img.isLoaded = true;
}
});
},
isInViewport(img) {
// 获取图片相对于视口的位置
const rect = img.getBoundingClientRect();
// 判断图片是否进入了可视区域
return rect.top < window.innerHeight && rect.bottom > 0;
}
},
watch: {
images: {
handler: function(newVal, oldVal) {
// 每当图片加载完成时,就移除已加载图片的 isLoaded 属性
newVal.forEach((item, index) => {
if (item.isLoaded) {
this.$set(this.images[index], 'isLoaded', false);
}
});
},
deep: true
}
}
}
</script>
注意:需要注意的是,在这个案例中,因为images数组中的对象被改变了,所以需要设置deep: true来监听对象
总之,watch 是一个非常强大和灵活的功能,它可以在数据变化时执行任何操作,并且可以与 computed 计算属性配合使用,来实现更复杂的逻辑。
computed 和 watch 的区别
watch和computed都可以监听Vue实例中的数据变化,但是它们有着明显的不同。
watch | computed |
用于监听某个特定的数据变化。 | 用于计算属性,可以计算出一个新的值。 |
每次数据变化都会触发回调函数。 | 仅在相关依赖发生改变时才会触发重新计算。 |
适用于异步操作或复杂逻辑。 | 适用于简单计算。 |
不可以在HTML模板中使用 | 可以在HTML模板中使用 |
没有返回值 | 有返回值/getter |
可以修改data中的数据 | 也可以使用setters 修改 data 中的数据 |
总之,如果你需要在数据变化时执行异步操作或复杂逻辑,使用watch是更好的选择;如果你需要在数据变化时计算出一个新值,使用computed是更好的选择。
关于watch的性能
watch的性能取决于你的代码实现方式和监听的数据量。
- 监听的数据量:如果你监听了大量的数据,那么 watch 的性能可能会受到影响。
- 代码实现:如果你在 watch 回调函数中执行了复杂的逻辑或异步操作,那么 watch 的性能可能会受到影响。
- 如果你只是需要在数据变化时执行一些简单的操作,那么 watch 的性能应该是可以接受的。
所以,在使用watch时,应该注意监听的数据量,并且在watch回调函数中尽量少执行复杂的逻辑.总之,watch监听数据更新并执行回调函数,性能会受到监听数据量和回调函数实现方式的影响,如果有性能问题,应该优化监听的数据量和回调函数的实现方式.
结束
今天的文章就介绍到这里,关于 watch 的用法你学会了,希望今天的文章能帮助到你,感谢你的阅读。