前提,建议先学会前端几大基础:HTML、CSS、JS、Ajax,不然不好懂
这一专栏知识将一次性将vue、vue2、vue3全部讲明白
一、何为watch监视器
其实我个人理解,就跟原本的表单的input事件一样,实时监视事件发生并同步更新数据,input事件不就是只用输入框输入一个东西,不管摁没摁回车键,后台都会监视触发事件。
那么watch监视器就是这么个玩意,比如实时翻译器就需要监视输入的内容,同时在输入时进行翻译
watch跟data、methods、computed一样,都是同级别的配置项,写法也一样;然后里面你要监视哪个data的元素,你就以这个data的元素设置一个【同名】的函数,这里注意两点:
1、监视data里的对象的成员,函数名要【对象.成员名】
2、因为“.”是特殊字符,函数名带它,编译器会有波浪线报错,那就用''引号包起来即可
例子1:
<div id="app">
<input type="text" v-model="words">
</div>
<script>
new Vue({
el: '#app',
data: {
words: ''
},
//设置watch配置项
watch:{
//有两种形式:1、函数名(参数1,参数2),这样的话会自动获取【这次改变的值】和【上一次的值】,参数1就是【这次改变的值】,参数2反之
// 2、函数名(参数),一个参数就是自动获取实时更新的值(上一个写法了解就行,没人用)
words(value){
console.log('变化了', value)
}
}
})
</script>
例子2:对象也一样,就是'对象.成员'就行
<div id="app">
<input type="text" v-model="obj.word">
</div>
<script>
new Vue({
el: '#app',
data: {
obj:{
word: ''
}
},
//设置watch配置项
watch:{
//有两种形式:1、函数名(参数1,参数2),这样的话会自动获取【这次改变的值】和【上一次的值】,参数1就是【这次改变的值】,参数2反之
// 2、函数名(参数),一个参数就是自动获取实时更新的值(上一个写法了解就行,没人用)
'obj.word'(value){
console.log('变化了', value)
}
}
})
</script>
二、用watch尝试实时翻译项目
很简单,就是在watch配置项里设置axios库就行了
先看简单的例子:
<div id="app">
<input type="text" v-model="words">
<span>{{ translation }}</span>
</div>
<!-- 引入axios库 -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
words: '',
translation: ''
},
watch: {
//这里用的是async和await函数方法来获取axios返回的结果
async words(value){
const res = await axios({
url: 'https://applet-base-api-t.itheima.net/api/translate',
params: {
words: value //words是这个服务器发送get请求必须带的参数
}
})
console.log(res)
console.log(res.data.data)
this.translation = res.data.data
}
//上面的写法是等同于这种传统写法的
// axios({
// url: 'https://applet-base-api-t.itheima.net/api/translate',
// params: {
// words: value
// }
// }).then(res => {
// console.log(res)
// })
}
})
</script>
但是这样虽然成功获取了,但是因为watch的实时监视,导致没输入一个字都会获得一个翻译结果
但是我们实际翻译的时候希望的是输入一串字符串后,停了一小会没有再输入了,再进行翻译的
那么就要引入【防抖机制】,这个方法可以应用与【用户双十一疯狂乱点订单请求导致发送N多个请求给服务器,淘宝就爆了】、【滚动条往下滑一点就加载一堆数据】、【翻译敲一个字就翻译一次】这些问题
那么简单的方法就是:加个setTimeout,隔一段时间再执行就好了
<div id="app">
<input type="text" v-model="words">
<span>{{ translation }}</span>
</div>
<!-- 引入axios库 -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
words: '',
translation: ''
},
watch: {
words(value){
//用setTimeout控制发送请求的时间
setTimeout(async ()=>{
const res = await axios({
url: 'https://applet-base-api-t.itheima.net/api/translate',
params: {
words: value
}
})
console.log(res)
console.log(res.data.data)
this.translation = res.data.data
},1000)
}
}
})
</script>
但是发现还是输入几个字翻译几次,只不过是输出翻译结果的时间间隔了一会再执行的,那么关键来了,我们只需要每次输入的时候【先】【关闭计时器】!!!然后再开启计时器就行了。那么关闭计时器需要有一个具体的【名字】来代表【是哪个计时器】,那就在data里设置一个变量用来代表计时器,然后清理关闭计时器的时候就是指向这个data的变量就行了,看代码:
<script>
new Vue({
el: '#app2',
data: {
words: '',
translation: '',
//这里设置一个timer变量成员,用来代替setTimeout计时器,相当与它就是那个setTimeout的名字
timer: null
},
watch: {
words(value){
//那就每次监视输入框输入时,第一步是先把计时器关闭了
clearTimeout(this.timer)
this.timer = setTimeout(async ()=>{
const res = await axios({
url: 'https://applet-base-api-t.itheima.net/api/translate',
params: {
words: value
}
})
console.log(res)
console.log(res.data.data)
this.translation = res.data.data
},1000)
}
}
})
</script>
我画个图给大伙类捋一捋
每一次输入就会触发watch监视,
那这样一来stTimeout计时器已开启,马上又因为下一次输入而导致执行clrearTimeout()关闭掉它,
那么一直输入的情况下就一直没办法执行setTimeout计时器,直到有一段时间不输入了,达到了setTimeout定的时间,那么就足够它完成里面的内容了;
然后直到下一次输入内容从而触发watch监视器,才会再次执行clrearTimeout()把上一次的计时器给清理掉。
三、watch更屌的功能!深度监视对象值改变
按照上面教的方法我们已经可以实时监视表单事件改变了,但是加入我改变的值是多个地方的呢?
比方说我实时翻译的时候,你既要监视我的输入框<input>输入的内容值改变了,还要监视我选择的语言<select><option></option></select>改变了,按照老方法我要在data里设置两个值代表它两,然后再根据它两各自在watch里写两个对应的函数,太麻烦了,要是5、6、100个地方要怎么办?
那就应该在data里用一个【对象】来封装起来这些值,监视的时候直接监视这个对象,其中一个值数据改变了,就是整个对象数据发生改变,那么怎么监视对象的值呢?要按以前说的'对象.成员名'吗?那还是要写很多个函数
watch完整写法是,当监视一个对象时,在watch里直接写一个【同名】的【对象】,然后有两个配置项:
1、deep:true 这个配置项代表开启【深层监视】
2、immediate:true 这个配置项代表初始化立刻执行一次handler函数
至于这个handle函数,watch监视器里对某个变量成员监视,就是设一个【同名字的函数】;而对对象的监视要执行的函数,就是执行【handler函数】,不能改系统自带的,记住是【handler】不要漏了最后的【r】!!!
例子:
<div id="app2">
<!-- 这里v-model=""别忘了换成"对象.成员" -->
<input type="text" v-model="obj.words">
<!-- 这里给select表单元素设置了v-model,只要下拉菜单改变,马上把对应的option的value值传给Vue的data -->
<select v-model="obj.lang">
<option value="italy">意大利</option>
<option value="eglish">英语</option>
<option value="german">德语</option>
</select>
<span>{{ translation }}</span>
</div>
<!-- 第一步:引入axios库 -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
new Vue({
el: '#app2',
data: {
obj: {
words: '',
lang: 'eglish'
},
translation: ''
},
watch: {
obj: {
//开启深度监视,整个对象都可以监视了
deep: true,
handler(value){
console.log('对象值改变了', value)
}
}
}
})
</script>
那么现在优化一下网络请求,把整个两个参数值都给到axios库的params参数里,直接给他value就行了,value就是对象!然后其他操作就是把上面的操作复制粘贴进去就行了
<!-- 第一步:引入axios库 -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
new Vue({
el: '#app2',
data: {
obj: {
words: '初始值就翻译',
lang: 'eglish'
},
translation: '',
//这里设置一个timer变量成员,用来代替setTimeout计时器,相当与它就是那个setTimeout的名字
timer: null
},
watch: {
obj: {
//开启深度监视,可以监视整个对象里面的值改变
deep: true,
//这个是设置一开始还没有改变表单值、也就是没有触发watch监视时,按照data里的初始值直接先执行一次hangler函数
immediate: true,
handler(value){
//那就每次监视输入框输入时,第一步是先把计时器关闭了
clearTimeout(this.timer)
this.timer = setTimeout(async ()=>{
const res = await axios({
url: 'https://applet-base-api-t.itheima.net/api/translate',
params: value
//这里value就是data那个对象
//其实就等于下面这个麻烦的写法
// params: {
// words: value.words,
// lang: value.lang
// }
})
console.log(res.data.data)
this.translation = res.data.data
},1000)
}
}
}
})
</script>
总结: