vue列表渲染

基本用法

v-for指令:
1.用于展示列表数据
2.语法:v-for="(item, index) in xxx" :key=“yyy”
3.可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)

vue如何检测与更新列表数据

  1. 虚拟DOM中key的作用:
    key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
    随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
    2.对比规则:
    (1).旧虚拟DOM中找到了与新虚拟DOM相同的key:
    ①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
    ②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
    (2).旧虚拟DOM中未找到与新虚拟DOM相同的key:创建新的真实DOM,随后渲染到到页面。
  2. 用index作为key可能会引发的问题:
    1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
    2. 如果结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题。
  3. 开发中如何选择key?:
    1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
    2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。

为什么index作为key值会有问题?

首先需要清楚,index表示的数组的下标,当数组的长度发生变化时同一个index可能会对应不同的元素,而key的作用是为了标识元素,确保无论数字如何变化通过key值获取的都是同一个元素,显然index无法实现这一点:

<button @click.once="add">添加一个老刘</button>
			<ul>
				<li v-for="(p,index) of persons" :key="index">
					{{p.name}}-{{p.age}}--{{index}}
					<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>

2.关于列表数据更新

vue在检测数据变化时底层使用的是defineProperty的setter和getter,这意味这,当我们不采用这种方式修改DOM中的数据时,vue是无法检测到数据变化的(虽然赋值完成),也就不会更新DOM,如下:

		<div id="root">
			<h2>人员列表</h2>
			<button @click="updateMei">更新马冬梅的信息</button>
			<button @click="add">添加数据</button>
			<ul>
				<li v-for="(p,index) of persons" :key="p.id">
					{{p.name}}-{{p.age}}-{{p.sex}}--{{p.id}}
				</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[0] = {id:'001',name:'马老师',age:50,sex:'男'} //不奏效
						console.log(this.persons[0])
					}
				},
			}) 

尽管从控制台可以看到this.persons[0]的数据已经变化,但是页面不会有任何变化,原因就是这种直接复制的方式没有调用setter,通过如下方式赋值都可以实现:

						 this.persons[0].name = '马老师' 
						 this.persons[0].age = 50 
						 this.persons[0].sex = '男'
						console.log(this.persons[0])
						this.persons.splice(0,1,{id:'001',name:'马老师',age:50,sex:'男'})

总结

  1. vue会监视data中所有层次的数据。

  2. 如何监测对象中的数据?
    通过setter实现监视,且要在new Vue时就传入要监测的数据。
    (1).对象中后追加的属性,Vue默认不做响应式处理
    (2).如需给后添加的属性做响应式,请使用如下API:
    Vue.set(target,propertyName/index,value) 或
    vm.$set(target,propertyName/index,value)

  3. 如何监测数组中的数据?
    通过包裹数组更新元素的方法实现,本质就是做了两件事:
    (1).调用原生对应的方法对数组进行更新。
    (2).重新解析模板,进而更新页面。

  4. 在Vue修改数组中的某个元素一定要用如下方法:
    1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
    2.Vue.set() 或 vm.$set()

上一篇:2022年上半年教师资格证科目三【十三门专业】


下一篇:面试题:Vue虚拟Dom