Watch侦听器(监视器)
作用:监视数据变化,执行一些业务逻辑或异步操作
语法:
①简单写法 → 简单类型数据,直接监视
②完整写法 → 添加额外配置项
①简单写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 条件选择框 -->
<div class="query">
<span>翻译成的语言:</span>
<select>
<option value="italy">意大利</option>
<option value="english">英语</option>
<option value="german">德语</option>
</select>
</div>
<div class="box">
<div class="input-wrap">
<textarea v-model="obj.words"></textarea>
<span>文档翻译</span>
</div>
<div class="output-wrap">
<div class="transbox">meal</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
const app = new Vue({
el:'#app',
data:{
//words:''
obj:{
words:''
}
},
//该方法会在数据变化时调用执行
//newValue新值,oldValue老值(一般不用,可以删掉)
// words(newValue,oldValue){
// }
watch:{
'obj.words' (newValue){
console.log('变化了',newValue)
}
}
})
</script>
</body>
</html>
以下部分为上述代码的业务实现👇(延时器:防抖)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.output-wrap{
width: 200px;
height: 200px;
background-color: aquamarine;
}
</style>
</head>
<body>
<div id="app">
<!-- 条件选择框 -->
<div class="query">
<span>翻译成的语言:</span>
<select>
<option value="italy">意大利</option>
<option value="english">英语</option>
<option value="german">德语</option>
</select>
</div>
<div class="box">
<div class="input-wrap">
<textarea v-model="obj.words"></textarea>
<span>文档翻译</span>
</div>
<div class="output-wrap">
<div class="transbox">{{ result }}</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
//接口地址:https://applet-base-apl-t.ithelma.net/api/translate
//请求方式:get
//请求参数:
// 1.words:需要被翻译的文本(必传)
// 2.lang:需要被翻译成的语言(可选)默认值-意大利
const app = new Vue({
el:'#app',
data:{
obj:{
words:'',
lang:'italy'
},
result:'',//翻译结果
},
watch:{
'obj.words' (newValue){
clearTimeout(this.timer)
this.timer = setTimeout (async () => {
const res = await axios({
url:'https://applet-base-api-t.itheima.net/api/translate',
params:{
words:newValue
}
})
this.result = res.data.data
console.log(res.data.data)
},300)
}, //如果每次都要写一遍这个,太麻烦了修改此方法,可以一次性全部监视
}
})
</script>
</body>
</html>
②完整写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.output-wrap{
width: 200px;
height: 200px;
background-color: aquamarine;
}
</style>
</head>
<body>
<div id="app">
<!-- 条件选择框 -->
<div class="query">
<span>翻译成的语言:</span>
<select>
<option value="italy">意大利</option>
<option value="english">英语</option>
<option value="german">德语</option>
</select>
</div>
<div class="box">
<div class="input-wrap">
<textarea v-model="obj.words"></textarea>
<span>文档翻译</span>
</div>
<div class="output-wrap">
<div class="transbox">{{ result }}</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
//接口地址:https://applet-base-apl-t.ithelma.net/api/translate
//请求方式:get
//请求参数:
// 1.words:需要被翻译的文本(必传)
// 2.lang:需要被翻译成的语言(可选)默认值-意大利
const app = new Vue({
el:'#app',
data:{
obj:{
words:'我是你爸爸',
lang:'italy'
},
result:'',//翻译结果
},
watch:{
//完整写法要写成一个对象
obj:{
deep:true,//深度监视:对所有都进行监视
immediate:true,//立刻执行,已进入页面,handler就立刻执行一次
handler (newValue) {//此时 handler只会在数据修改的时候触发,所以如果先设定的话,他不会自动翻译,要输入一下才能翻译
//所以就要用到第二个配置项:immediate:true
clearTimeout(this.timer)
this.timer = setTimeout (async () => {
const res = await axios({
url:'https://applet-base-api-t.itheima.net/api/translate',
params: newValue//{
//因为默认值是意大利,所以除了传words,还要传langi
//words:newValue
//这里的newValue包括了words和lang,所以可以直接丢newValue
//}
})
this.result = res.data.data
console.log(res.data.data)
},300)
}
}
// 'obj.words' (newValue){
// clearTimeout(this.timer)
// this.timer = setTimeout (async () => {
// const res = await axios({
// url:'https://applet-base-api-t.itheima.net/api/translate',
// params:{
// words:newValue
// }
// })i
// this.result = res.data.datai
// console.log(res.data.data)
// },300)
// }, 如果每次都要写一遍这个,太麻烦了修改此方法,可以一次性全部监视
}
})
</script>
</body>
</html>
案例:水果购物车
</head>
<body>
<div class="app-container" id="app">
<!-- 顶部banner -->
<div class="banner-box"><img src="http://autumnfish.cn/static/fruit.jpg" alt="" /></div>
<!-- 面包屑 -->
<div class="breadcrumb">
<span>🏠</span>
/
<span>购物车</span>
</div>
<!-- 购物车主体 -->
<div class="main" v-if="fruitList.length >0">
<div class="table">
<!-- 头部 -->
<div class="thead">
<div class="tr">
<div class="th">选中</div>
<div class="th th-pic">图片</div>
<div class="th">单价</div>
<div class="th num-th">个数</div>
<div class="th">小计</div>
<div class="th">操作</div>
</div>
</div>
<!-- 身体 -->
<div class="tbody">
<div v-for="(item,index) in fruitList" :key="item.id" class="tr" :class="{active:item.isChecked}">
<div class="td"><input type="checkbox" v-model="item.isChecked" /></div>
<div class="td"><img :src="item.icon" alt="" /></div>
<div class="td">{{ item.price }}</div>
<div class="td">
<div class="my-input-number">
<button :disabled="item.num <=1" class="decrease" @click="sub(item.id)"> - </button>
<span class="my-input__inner">{{ item.num }}</span>
<button class="increase" @click="add(item.id)"> + </button>
</div>
</div>
<div class="td">{{ item.num * item.price }}</div>
<div class="td"><button @click="del(item.id)">删除</button></div>
</div>
</div>
</div>
<!-- 底部 -->
<div class="bottom">
<!-- 全选 -->
<label class="check-all">
<input type="checkbox" v-model="isAll" />
全选
</label>
<div class="right-box">
<!-- 所有商品总价 -->
<span class="price-box">总价 : ¥ <span class="price">{{ totalPrice }}</span></span>
<!-- 结算按钮 -->
<button class="pay">结算( {{ totalCount }} )</button>
</div>
</div>
</div>
<!-- 空车 -->
<div class="empty" v-else>🛒空空如也</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
const defaultArr = [
{
id: 1,
icon: './火龙果.png',
isChecked: true,
num: 2,
price: 6,
},
{
id: 2,
icon: './荔枝.png',
isChecked: false,
num: 7,
price: 20,
},
{
id: 3,
icon: './榴莲.png',
isChecked: false,
num: 3,
price: 40,
},
{
id: 4,
icon: './鸭梨.png',
isChecked: true,
num: 10,
price: 3,
},
{
id: 5,
icon: './樱桃.png',
isChecked: false,
num: 20,
price: 34,
},
]
const app = new Vue({
el: '#app',
data: {
// 水果列表
fruitList:JSON.parse(localStorage.getItem('list')) || defaultArr,
},
computed:{
// isAll () {
// //必须所有的小选框都选中,全选按钮才选中 → every
// return this.fruitList.every(item => item.isChecked)//本身就是一个布尔值,所以=== true可以不写
// }
//完整写法=get + set
isAll:{
get (){
return this.fruitList.every(item => item.isChecked)
},
set (value){
//基于拿到的布尔值,要让所有的小选框,同步状态
this.fruitList.forEach(item => item.isChecked = value)//一个等号赋值
}
},
//统计选中的总数
totalCount(){
return this.fruitList.reduce((sum,item) => {
if (item.isChecked){
//选中,需要累加
return sum + item.num
} else{
//没选中,不需要累加
return sum
}
},0)
},
//总计选中的总价 num* price,把这个再做累加
totalPrice(){
return this.fruitList.reduce((sum,item) => {
if (item.isChecked) {
return sum + item.num * item.price
}else {
return sum
}
},0)
}
},
methods:{
del(id){
this.fruitList = this.fruitList.filter(item => item.id !== id)
},
add (id){
//1.根据id找到数组中的对应项 → find
const fruit = this.fruitList.find(item => item.id === id)//是否和传过来的id相同,
//如果是,那么就是它,然后操作数量
//2.操作num数量
fruit.num++
},
sub(id){
//1.根据id找到数组中的对应项 → find
const fruit = this.fruitList.find(item => item.id === id)//是否和传过来的id相同,
//如果是,那么就是它,然后操作数量
//2.操作num数量
fruit.num--
}
},
watch:{
fruitList:{
deep:true,
handler( newValue){
// 需要将变化后的 newValue 存入本地 (转JSON)
localStorage.setItem('list',JSON.stringify(newValue))
}
}
}
})
</script>
</body>
</html>