一、完整源码
<!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
更适合 “依赖多个数据计算派生值” 的场景,如表格的过滤 + 排序,且缓存机制能提升性能。