列表渲染
基本列表
v-for
指令
- 用于展示列表数据
- 语法:
<li v-for="(item, index) of items" :key="index">
,这里key
可以是index
,更好的是遍历对象的唯一标识
- 可遍历:数组、对象、字符串(用的少)、指定次数(用的少)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| <title>基本列表</title> <script type="text/javascript" src="../js/vue.js"></script>
<div id="root"> <h3>人员列表(遍历数组)</h3> <ul> <li v-for="(p,index) of persons" :key="index">{{ p.name }}-{{ p.age }}</li> </ul>
<h3>汽车信息(遍历对象)</h3> <ul> <li v-for="(value,k) of car" :key="k">{{ k }}-{{ value }}</li> </ul>
<h3>测试遍历字符串(用得少)</h3> <ul> <li v-for="(char,index) of str" :key="index">{{ char }}-{{ index }}</li> </ul>
<h3>测试遍历指定次数(用得少)</h3> <ul> <li v-for="(number,index) of 5" :key="index">{{ index }}-{{ number }}</li> </ul> </div>
<script type="text/javascript"> Vue.config.productionTip = false new Vue({ el: '#root', data: { persons: [ { id: '001', name: '张三', age: 18 }, { id: '002', name: '李四', age: 19 }, { id: '003', name: '王五', age: 20 } ], car: { name: '奥迪A8', price: '70万', color: '黑色' }, str: 'hello' } }) </script>
|

key 的作用与原理
原理


面试题:react
vue
中的key
有什么作用?(key
的内部原理)
1、虚拟DOM
中key
的作用:key
是虚拟DOM
中对象的标识,当数据发生变化时,Vue
会根据新数据
生成新的虚拟DOM
,随后Vue
进行新虚拟DOM
与旧虚拟DOM
的差异比较
,比较规则如下
2、对比规则
a、旧虚拟DOM
中找到了与新虚拟DOM
相同的key
- 若
虚拟DOM
中内容没变, 直接使用之前的真实DOM
- 若
虚拟DOM
中内容变了, 则生成新的真实DOM
,随后替换掉页面中之前的真实DOM
b、旧虚拟DOM
中未找到与新虚拟DOM
相同的key
3、用index
作为key
可能会引发的问题
- 若对数据进行逆序添加、逆序删除等
破坏顺序操作
,会产生没有必要的真实DOM
更新 ==> 界面效果没问题,但效率低
- 若结构中还包含
输入类的DOM
:会产生错误DOM
更新 ==> 界面有问题
4、开发中如何选择key?
- 最好使用每条数据的
唯一标识作为key
,比如 id、手机号、身份证号、学号等唯一值
- 如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表,使用
index
作为key
是没有问题的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <title>key的原理</title> <script type="text/javascript" src="../js/vue.js"></script>
<div id="root"> <h2>人员列表(遍历数组)</h2> <button @click.once="add">添加一个老刘</button> <ul> <li v-for="(p,index) of persons" :key="index"> {{p.name}}-{{p.age}} <input type="text"> </li> </ul> </div>
<script type="text/javascript"> Vue.config.productionTip = false new Vue({ el: '#root', data: { persons: [ { id: '001', name: '张三', age: 18 }, { id: '002', name: '李四', age: 19 }, { id: '003', name: '王五', age: 20 } ] }, methods: { add() { const p = { id: '004', name: '老刘', age: 40 } this.persons.unshift(p) } }, }) </script>
|

列表过滤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| <title>列表过滤</title> <script type="text/javascript" src="../js/vue.js"></script>
<div id="root"> <h2>人员列表</h2> <input type="text" placeholder="请输入名字" v-model="keyWord"> <ul> <li v-for="(p,index) of filPersons" :key="p.id"> {{ p.name }}-{{ p.age }}-{{ p.sex }} </li> </ul> </div>
<script type="text/javascript"> Vue.config.productionTip = false
new Vue({ el: '#root', data: { keyWord: '', persons: [ { id: '001', name: '马冬梅', age: 19, sex: '女' }, { id: '002', name: '周冬雨', age: 20, sex: '女' }, { id: '003', name: '周杰伦', age: 21, sex: '男' }, { id: '004', name: '温兆伦', age: 22, sex: '男' } ] }, computed: { filPersons() { return this.persons.filter((p) => { return p.name.indexOf(this.keyWord) !== -1 }) } } }) </script>
|
列表排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| <title>列表排序</title> <script type="text/javascript" src="../js/vue.js"></script>
<div id="root"> <h2>人员列表</h2> <input type="text" placeholder="请输入名字" v-model="keyWord"> <button @click="sortType = 2">年龄升序</button> <button @click="sortType = 1">年龄降序</button> <button @click="sortType = 0">原顺序</button> <ul> <li v-for="(p,index) of filPersons" :key="p.id"> {{p.name}}-{{p.age}}-{{p.sex}} <input type="text"> </li> </ul> </div>
<script type="text/javascript"> Vue.config.productionTip = false new Vue({ el: '#root', data: { keyWord: '', sortType: 0, persons: [ { id: '001', name: '马冬梅', age: 30, sex: '女' }, { id: '002', name: '周冬雨', age: 31, sex: '女' }, { id: '003', name: '周杰伦', age: 18, sex: '男' }, { id: '004', name: '温兆伦', age: 19, sex: '男' } ] }, computed: { filPersons() { const arr = this.persons.filter((p) => { return p.name.indexOf(this.keyWord) !== -1 }) if (this.sortType) { arr.sort((p1, p2) => { return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age }) } return arr } } }) </script>
|
Vue数据监视
更新时的一个问题
this.persons[0] = {id:'001',name:'马老师',age:50,sex:'男'}
更改data
数据,Vue
不监听,模板不改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <title>更新时的一个问题</title> <script type="text/javascript" src="../js/vue.js"></script>
<div id="root"> <h2>人员列表</h2> <button @click="updateMei">更新马冬梅的信息</button> <ul> <li v-for="(p,index) of persons" :key="p.id"> {{p.name}}-{{p.age}}-{{p.sex}} </li> </ul> </div>
<script type="text/javascript"> Vue.config.productionTip = false
const vm = new Vue({ el: '#root', data: { persons: [ { id: '001', name: '马冬梅', age: 30, sex: '女' }, { id: '002', name: '周冬雨', age: 31, sex: '女' }, { id: '003', name: '周杰伦', age: 18, sex: '男' }, { id: '004', name: '温兆伦', age: 19, sex: '男' } ] }, methods: { updateMei() { this.persons.splice(0, 1, { id: '001', name: '马老师', age: 50, sex: '男' }) } } }) </script>
|
模拟一个数据监测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| let data = { name: '尚硅谷', address: '北京', }
function Observer(obj) { const keys = Object.keys(obj) keys.forEach((k) => { Object.defineProperty(this, k, { get() { return obj[k] }, set(val) { console.log(`${k}被改了,我要去解析模板,生成虚拟DOM.....我要开始忙了`) obj[k] = val } }) }) }
const obs = new Observer(data) console.log(obs)
let vm = {} vm._data = data = obs
|
原理
1、vue
会监视data
中所有层次的数据
2、如何监测对象
中的数据?
通过setter
实现监视,且要在new Vue()
时就传入要监测的数据
○对象创建后追加的属性,Vue
默认不做响应式处理
○如需给后添加的属性做响应式,请使用如下API
Vue.set(target,propertyName/index,value)
vm.$set(target,propertyName/index,value)
3、如何监测数组
中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事
a、调用原生对应的方法对数组进行更新
b、重新解析模板,进而更新页面
4、在Vue
修改数组中的某个元素一定要用如下方法
push()
pop()
unshift()
shift()
splice()
sort()
reverse()
这几个方法被Vue
重写了
Vue.set()
或vm.$set()
特别注意:Vue.set()
和 vm.$set()
不能给vm
或vm
的根数据对象(data
等)添加属性