一、完整源碼
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="../js/vue.js"></script>
</head>
<body><div id="root">監視屬性實現按名模糊搜索:<input type="text" v-model="keyword" /></br></br><table border="1px solid black"><tr><td>id</td><td>姓名</td><td>年齡</td></tr><tr v-for = 'person in filterPersons' :key="person.id"><td>{{person.id}}</td><td>{{person.name}}</td><td>{{person.age}}</td></tr></table><hr>計算屬性實現按名模糊搜索:<input type="text" v-model="keyword2" /><input type="button" @click="sortType = 1" value="年齡升序"/><input type="button" @click="sortType = 2" value="年齡降序"/></br></br><table border="1px solid black"><tr><td>id</td><td>姓名</td><td>年齡</td></tr><tr v-for = 'person in filterPersons2' :key="person.id"><td>{{person.id}}</td><td>{{person.name}}</td><td>{{person.age}}</td></tr></table></div>
</body><script>const vm = new Vue({el:'#root',data() {return {persons:[{id:1,name:'張三',age:19},{id:2,name:'李四',age:15},{id:3,name:'王五',age:16},{id:4,name:'張三2',age:17}],filterPersons:[],keyword:'',keyword2:'',sortType:0}},watch:{keyword:{immediate:true, //立即執行監視handler(val){//filter將返回一個新的數組;'abc'.indexOf('')的返回值為0this.filterPersons = this.persons.filter((person)=>{return person.name.indexOf(val) !== -1 //包含val則保留該person})}},},//filterPersons2 何時調get? 1 上來就調用 2 依賴的keyword2,sortType變化就調用computed:{filterPersons2(){const arr = this.persons.filter((person)=>{return person.name.indexOf(this.keyword2) !== -1 })if(this.sortType){arr.sort((person1,person2)=>{return this.sortType == 2 ?person2.age - person1.age:person1.age - person2.age})}return arr}}})</script>
</html>
二、核心知識點解析
1. 功能模塊拆解
頁面分為兩個獨立模塊,對比展示watch
與computed
的差異:
模塊 | 核心技術 | 功能 | 依賴數據 |
---|---|---|---|
上方表格 | watch | 僅姓名模糊搜索 | keyword |
下方表格 | computed | 姓名模糊搜索 + 年齡升 / 降序排序 | keyword2、sortType |
2. 監視屬性(watch)詳解
2.1 為什么需要immediate: true
?
Vue 的watch
默認僅在監聽的數據(如 keyword)發生變化時才觸發 handler,初始化時(頁面加載時)不會執行。
若不加immediate: true
,頁面打開時filterPersons
為空,表格會顯示空白;加上后,初始化時會主動執行一次 handler,加載所有人員數據。
2.2?filter
與indexOf
的核心邏輯
Array.prototype.filter()
:遍歷數組,返回一個新數組,包含所有滿足 “回調函數返回 true” 的元素(不修改原數組)。String.prototype.indexOf(val)
:返回val
在字符串中首次出現的索引,若不存在則返回-1
。
關鍵細節:'abc'.indexOf('')
返回0
,因此當搜索框為空(keyword=''
)時,person.name.indexOf('') !== -1
恒成立,表格會顯示所有數據。
3. 計算屬性(computed)詳解
3.1 computed 的核心特性:依賴緩存
computed
的屬性(如filterPersons2
)會緩存計算結果,只有當它依賴的數據(keyword2
、sortType
)發生變化時,才會重新執行getter
(即函數體);若依賴數據不變,多次訪問filterPersons2
會直接返回緩存值,避免重復計算,效率高于methods
。
3.2 排序邏輯解析
filteredArr.sort((p1, p2) => {return this.sortType === 2 ? p2.age - p1.age : p1.age - p2.age
})
sort
方法的回調函數返回值規則:- 返回正數:p1 排在 p2 后面(升序);
- 返回負數:p1 排在 p2 前面(降序);
- 返回 0:順序不變。
- 此處通過
sortType
控制排序方向:sortType=1
:升序 →?p1.age - p2.age
(如 15-16=-1,15 排在 16 前);sortType=2
:降序 →?p2.age - p1.age
(如 16-15=1,16 排在 15 前)。
三、運行效果與注意事項
1. 運行效果
- 頁面加載時,兩個表格均顯示所有 4 條人員數據;
- 上方搜索框輸入 “張”,僅顯示 “張三” 和 “張三 2”;
- 下方搜索框輸入 “張”,再點擊 “年齡降序”,表格按 “19(張三)→17(張三 2)” 排序;
- 點擊 “年齡升序”,下方表格按 “17(張三 2)→19(張三)” 排序。
2. 注意事項
- Vue 版本:本文使用Vue2(代碼中
new Vue({el: '#root'})
為 Vue2 語法),若使用 Vue3,需調整為createApp
語法; - 數組方法影響:
sort
方法會修改原數組,本文中filteredArr
是filter
返回的新數組,修改它不會影響原始persons
數據,避免數據污染; - 兼容性:
indexOf
在所有現代瀏覽器中支持,若需兼容更老瀏覽器,可替換為includes
(如person.name.includes(val)
)。
四、總結
watch
更適合 “監聽單個數據變化并執行邏輯” 的場景,如數據變化后發起接口請求;computed
更適合 “依賴多個數據計算派生值” 的場景,如表格的過濾 + 排序,且緩存機制能提升性能。