目錄
引言
一、watch偵聽器(監視器)
1.作用:
2.語法:
3.偵聽器代碼準備
4. 配置項
?5.總結
二、翻譯案例-代碼實現
1.需求
2.代碼實現
三、綜合案例——購物車案例
1. 需求?
?2. 代碼
引言
💬 歡迎討論:關于Vue偵聽器應用、防抖優化與響應式設計,歡迎評論區交流技術細節!
👍 點贊支持:若本文助你攻克watch難題,歡迎三連助力,共享前端技術精粹!
🚀 進階指南:watch與計算屬性聯奏,演繹Vue響應式交響曲,構建數據與視圖的動態協奏。
一、watch偵聽器(監視器)
1.作用:
??監視數據變化,執行一些業務邏輯或異步操作
2.語法:
-
watch同樣聲明在跟data同級的配置項中
-
簡單寫法: 簡單類型數據直接監視
-
完整寫法:添加額外配置項
?
3. 配置項
完整寫法 —>添加額外的配置項
- deep:true 對復雜類型進行深度監聽
- immdiate:true 初始化 立刻執行一次
data: {obj: {words: '蘋果',lang: 'italy'},
},watch: {// watch 完整寫法對象: {deep: true, // 深度監視immdiate:true,//立即執行handler函數handler (newValue) {console.log(newValue)}}
}
?4.總結
watch偵聽器的寫法有幾種?
1.簡單寫法
2.完整寫法
二、翻譯案例-代碼實現
1.需求
- 當文本框輸入的時候 右側翻譯內容要時時變化(實時翻譯)
- 當下拉框中的語言發生變化的時候 右側翻譯的內容依然要時時變化
- 如果文本框中有默認值的話要立即翻譯
2.代碼
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><style>* {margin: 0;padding: 0;box-sizing: border-box;font-size: 18px;}#app {padding: 10px 20px;}.query {margin: 10px 0;}.box {display: flex;}textarea {width: 300px;height: 160px;font-size: 18px;border: 1px solid #dedede;outline: none;resize: none;padding: 10px;}textarea:hover {border: 1px solid #1589f5;}.transbox {width: 300px;height: 160px;background-color: #f0f0f0;padding: 10px;border: none;}.tip-box {width: 300px;height: 25px;line-height: 25px;display: flex;}.tip-box span {flex: 1;text-align: center;}.query span {font-size: 18px;}.input-wrap {position: relative;}.input-wrap span {position: absolute;right: 15px;bottom: 15px;font-size: 12px;}.input-wrap i {font-size: 20px;font-style: normal;}</style></head><body><div id="app"><!-- 條件選擇框 --><div class="query"><span>翻譯成的語言:</span><select v-model="obj.lang"><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><i>??</i>文檔翻譯</span></div><div class="output-wrap"><div class="transbox">{{ result }}</div></div></div></div><script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>// 需求:輸入內容,修改語言,都實時翻譯// 接口地址:https://applet-base-api-t.itheima.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) {clearTimeout(this.timer)this.timer = setTimeout(async () => {const res = await axios({url: 'https://applet-base-api-t.itheima.net/api/translate',params: newValue})this.result = res.data.dataconsole.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// }// })// this.result = res.data.data// console.log(res.data.data)// }, 300)// }}})</script></body>
</html>
三、綜合案例——購物車案例
1. 需求?
需求說明:
- 渲染功能
- 刪除功能
- 修改個數
- 全選反選
- 統計 選中的 總價 和 總數量
- 持久化到本地
實現思路:
1.基本渲染: v-for遍歷、:class動態綁定樣式
2.刪除功能 : v-on 綁定事件,獲取當前行的id
3.修改個數 : v-on綁定事件,獲取當前行的id,進行篩選出對應的項然后增加或減少
4.全選反選
- 必須所有的小選框都選中,全選按鈕才選中 → every
- 如果全選按鈕選中,則所有小選框都選中
- 如果全選取消,則所有小選框都取消選中
聲明計算屬性,判斷數組中的每一個checked屬性的值,看是否需要全部選
5.統計 選中的 總價 和 總數量 :通過計算屬性來計算選中的總價和總數量
6.持久化到本地: 在數據變化時都要更新下本地存儲 watch
?2. 代碼
css?
.app-container {padding-bottom: 300px;width: 800px;margin: 0 auto;
}
@media screen and (max-width: 800px) {.app-container {width: 600px;}
}
.app-container .banner-box {border-radius: 20px;overflow: hidden;margin-bottom: 10px;
}
.app-container .banner-box img {width: 100%;
}
.app-container .nav-box {background: #ddedec;height: 60px;border-radius: 10px;padding-left: 20px;display: flex;align-items: center;
}
.app-container .nav-box .my-nav {display: inline-block;background: #5fca71;border-radius: 5px;width: 90px;height: 35px;color: white;text-align: center;line-height: 35px;margin-right: 10px;
}.breadcrumb {font-size: 16px;color: gray;
}
.table {width: 100%;text-align: left;border-radius: 2px 2px 0 0;border-collapse: separate;border-spacing: 0;
}
.th {color: rgba(0, 0, 0, 0.85);font-weight: 500;text-align: left;background: #fafafa;border-bottom: 1px solid #f0f0f0;transition: background 0.3s ease;
}
.th.num-th {flex: 1.5;
}
.th {text-align: center;
}
.th:nth-child(4),
.th:nth-child(5),
.th:nth-child(6),
.th:nth-child(7) {text-align: center;
}
.th.th-pic {flex: 1.3;
}
.th:nth-child(6) {flex: 1.3;
}.th,
.td {position: relative;padding: 16px 16px;overflow-wrap: break-word;flex: 1;
}
.pick-td {font-size: 14px;
}
.main,
.empty {border: 1px solid #f0f0f0;margin-top: 10px;
}
.tr {display: flex;cursor: pointer;border-bottom: 1px solid #ebeef5;
}
.tr.active {background-color: #f5f7fa;
}
.td {display: flex;justify-content: center;align-items: center;
}.table img {width: 100px;height: 100px;
}button {outline: 0;box-shadow: none;color: #fff;background: #d9363e;border-color: #d9363e;color: #fff;background: #d9363e;border-color: #d9363e;line-height: 1.5715;position: relative;display: inline-block;font-weight: 400;white-space: nowrap;text-align: center;background-image: none;border: 1px solid transparent;box-shadow: 0 2px 0 rgb(0 0 0 / 2%);cursor: pointer;transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;touch-action: manipulation;height: 32px;padding: 4px 15px;font-size: 14px;border-radius: 2px;
}
button.pay {background-color: #3f85ed;margin-left: 20px;
}.bottom {height: 60px;display: flex;align-items: center;justify-content: space-between;padding-right: 20px;border: 1px solid #f0f0f0;border-top: none;padding-left: 20px;
}
.right-box {display: flex;align-items: center;
}
.check-all {cursor: pointer;
}
.price {color: hotpink;font-size: 30px;font-weight: 700;
}
.price-box {display: flex;align-items: center;
}
.empty {padding: 20px;text-align: center;font-size: 30px;color: #909399;
}
.my-input-number {display: flex;
}
.my-input-number button {height: 40px;color: #333;border: 1px solid #dcdfe6;background-color: #f5f7fa;
}
.my-input-number button:disabled {cursor: not-allowed!important;
}
.my-input-number .my-input__inner {height: 40px;width: 50px;padding: 0;border: none;border-top: 1px solid #dcdfe6;border-bottom: 1px solid #dcdfe6;
}
html?
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><link rel="stylesheet" href="./css/inputnumber.css" /><link rel="stylesheet" href="./css/index.css" /><title>購物車</title></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: 'http://autumnfish.cn/static/火龍果.png',isChecked: true,num: 2,price: 6,},{id: 2,icon: 'http://autumnfish.cn/static/荔枝.png',isChecked: false,num: 7,price: 20,},{id: 3,icon: 'http://autumnfish.cn/static/榴蓮.png',isChecked: false,num: 3,price: 40,},{id: 4,icon: 'http://autumnfish.cn/static/鴨梨.png',isChecked: true,num: 10,price: 3,},{id: 5,icon: 'http://autumnfish.cn/static/櫻桃.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)// }// 完整寫法 = get + setisAll: {get () {return this.fruitList.every(item => item.isChecked)},set (value) {// 基于拿到的布爾值,要讓所有的小選框 同步狀態this.fruitList.forEach(item => item.isChecked = value)}},// 統計選中的總數 reducetotalCount () {return this.fruitList.reduce((sum, item) => {if (item.isChecked) {// 選中 → 需要累加return sum + item.num} else {// 沒選中 → 不需要累加return sum}}, 0)},// 總計選中的總價 num * pricetotalPrice () {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 找到數組中的對應項 → findconst fruit = this.fruitList.find(item => item.id === id)// 2. 操作 num 數量fruit.num++},sub (id) {// 1. 根據 id 找到數組中的對應項 → findconst fruit = this.fruitList.find(item => item.id === id)// 2. 操作 num 數量fruit.num--}},watch: {fruitList: {deep: true,handler (newValue) {// 需要將變化后的 newValue 存入本地 (轉JSON)localStorage.setItem('list', JSON.stringify(newValue))}}}})</script></body>
</html>
以上就是關于【Vue篇】數據秘語:從watch源碼看響應式宇宙的蝴蝶效應? 內容啦。本文?剖析了watch的監聽機制、深度追蹤技巧,并通過翻譯防抖與購物車案例實戰,解構了數據與視圖的動態綁定邏輯。若對watch配置、計算屬性聯用或本地持久化方案存在疑問,歡迎評論區留下技術火花!💡
?