0
点赞
收藏
分享

微信扫一扫

0401_Vue_D4_列表渲染、数据劫持

水沐由之 2022-04-03 阅读 41
vue.js

v-for指令

●用于展示列表数据
●语法:<li v-for="(item, index) of items" :key="index">,这里key可以是index,更好的是遍历对象的唯一标识
●可遍历:数组、对象、字符串(用的少)、指定次数(用的少)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<!-- 引入vue -->
		<script type="text/javascript" src="../js/vue.js">
			
		</script>
	</head>
	<body>
		<div id="root">
		<!-- 遍历数组 【用的最多】-->
		<ul>
			<li v-for="(p,index) in persons" :key="index" > 
			{{p.name}}--{{p.age}}
			</li>
		</ul>	
		<!-- 遍历对象 -->
		<ul>
			<li v-for="(a,b) in car" :key='b'  > 
				{{b}}--{{a}}
			</li>
		</ul>	
		</div>
	</body>
	
	<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:22}
				  
			   ],
			   car:{
				   name:'奥迪',
				   price:'40w'
			   }
		   }
	   })
	 
	</script>
</html>

index作为key【出问题,复用率低】

 id作为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
创建新的真实DOM,随后渲染到到页面
3、用index作为key可能会引发的问题
a若对数据进行逆序添加、逆序删除等破坏顺序操作,会产生没有必要的真实DOM更新 ==> 界面效果没问题,但效率低
b若结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题
4、开发中如何选择key?
a最好使用每条数据的唯一标识作为key,比如 id、手机号、身份证号、学号等唯一值
b如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表,使用index作为key是没有问题的
 

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<!-- 引入vue -->
		<script type="text/javascript" src="../js/vue.js">
			
		</script>
	</head>
	<body>
		<div id="root">
		<!-- 遍历数组 【用的最多】-->
		<h2>人员列表 --遍历数组 【用的最多】</h2>
		<button @click.once="add">添加一个老刘</button>
		<ul>
			<li v-for="(p,index) in persons" :key="index" > 
			{{p.name}}--{{p.age}}
			</li>
		</ul>	
	
		</div>
	</body>
	
	<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:22}
				  
			   ],
			
		   },
		   methods:{
			   add(){
				   const p={id:'004', name:'老刘',age:50}
				   this.persons.unshift( p)  //将元素往最前面放
			}
		   }
	   })
	 
	</script>
</html>

???列表过滤

 

 

 

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<!-- 引入vue -->
		<script type="text/javascript" src="../js/vue.js">
			
		</script>
	</head>
	<body>
		<div id="root">
		  <input type="text" placeholder="请输入名字" v-model="keyWord"/>
		<ul>
			<li v-for="(p,index) in filPersons" :key="index" > 
			{{p.name}}--{{p.age}}--{{p.sex}}
			</li>
		</ul>	
		 
		</div>
	</body>
	
	<script type="text/javascript">
		Vue.config.productionTip=false;
		//用watch实现列表过滤
	  /* new Vue({
		   el:'#root',
		   data:{
			  keyWord:'',
			  persons:[
				  {id:'001',name: '马冬梅',age:18,sex:'女'},
				  {id:'002 ',name:'周冬雨',age:19,sex:'女'},
				  {id:'003',name:'周杰伦',age:22,sex:'男'},
				  {id:'004',name: '温兆伦',age:27,sex:'男'} 
			   ] ,
			  filPersons:[]
		   },
			
			watch:{
				keyWord:{
					
				immediate:true, //执行一次空字符串
				handler(newValue){
				this.filPersons=this.persons.filter((p)=>{
					return p.name.indexOf(newValue)!==-1  //返回一个含有指定字符的名字
				})
				}
				}
			}
	   })
	 */
	
	 //用computed实现
	  new Vue({
			   el:'#root',
			   data:{
				  keyWord:'',
				  persons:[
					  {id:'001',name: '马冬梅',age:18,sex:'女'},
					  {id:'002 ',name:'周冬雨',age:19,sex:'女'},
					  {id:'003',name:'周杰伦',age:22,sex:'男'},
					  {id:'004',name: '温兆伦',age:27,sex:'男'} 
				   ] ,
				 
			   },
		 computed:{
			 filPersons(){
				return  this.persons.filter((p)=>{ //返回计算属性的值
					return p.name.indexOf(this.keyWord)!==-1  //返回过滤条件
					})
			 }
		 }
	  })
	 
	</script>
</html>

 计算属性

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<!-- 引入vue -->
		<script type="text/javascript" src="../js/vue.js">
			
		</script>
	</head>
	<body>
		<div id="root">
		  <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) in filPersons" :key="index" > 
			{{p.name}}--{{p.age}}--{{p.sex}}
			</li>
		</ul>	
		 
		</div>
	</body>
	
	<script type="text/javascript">
		Vue.config.productionTip=false;
		//用watch实现列表过滤
	  new Vue({
		   el:'#root',
		   data:{
			   sortType:0,  //0原顺序,1降序 ,2升序
			  keyWord:'',
			  persons:[
				  {id:'001',name: '马冬梅',age:38,sex:'女'},
				  {id:'002 ',name:'周冬雨',age:19,sex:'女'},
				  {id:'003',name:'周杰伦',age:12,sex:'男'},
				  {id:'004',name: '温兆伦',age:27,sex:'男'} 
			   ]  
			 
		   },
			 computed:{
			 			 filPersons(){
			 				const arr=  this.persons.filter((p)=>{ //返回计算属性的值
			 					return p.name.indexOf(this.keyWord)!==-1  //返回过滤条件
			 					})
						// 判断一下是否需要排序
						if(this.sortType){ //如果 布尔值为0的话,不走
						arr.sort((p1,p2)=>{
							return this.sortType===1? p2.age-p1.age: p1.age-p2.age
							})
			 			 }
						 return arr
			 }
			 }
	   })
	 
	</script>
</html>

vm监测数据对象的原理

 

 

Object.defineProperty()语法说明

Object.defineProperty()的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性

Object.defineProperty(obj, prop, desc)
  1. obj 需要定义属性的当前对象
  2. prop 当前需要定义的属性名
  3. desc 属性描述符

 【参考】 深入浅出Object.defineProperty() - 简书


vue监测对象改变的原理 

修改数组的方法

①可以用vue提前包装好的这7个api

 

splice()方法 

 ②用vue.set(目标,属性/数组位置,值) 

或者  vm.$set(a,b,c)

 

 

 

 替换数组

 

 

 

vue核心原理总结:列表渲染、数据劫持


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等)添加属性

 

<title>总结数据监视</title>
<style>button {margin-top: 10px;}</style>
<script type="text/javascript" src="../js/vue.js"></script>

<div id="root">
  <h1>学生信息</h1>
  <button @click="student.age++">年龄+1岁</button> <br />
  <button @click="addSex">添加性别属性,默认值:男</button> <br />
  <button @click="student.sex = '未知' ">修改性别</button> <br />
  <button @click="addFriend">在列表首位添加一个朋友</button> <br />
  <button @click="updateFirstFriendName">修改第一个朋友的名字为:张三</button> <br />
  <button @click="addHobby">添加一个爱好</button> <br />
  <button @click="updateHobby">修改第一个爱好为:开车</button> <br />
  <button @click="removeSmoke">过滤掉爱好中的抽烟</button> <br />
  <h3>姓名:{{ student.name }}</h3>
  <h3>年龄:{{ student.age }}</h3>
  <h3 v-if="student.sex">性别:{{student.sex}}</h3>
  <h3>爱好:</h3>
  <ul>
    <li v-for="(h,index) in student.hobby" :key="index">{{ h }} </li>
  </ul>
  <h3>朋友们:</h3>
  <ul>
    <li v-for="(f,index) in student.friends" :key="index">{{ f.name }}--{{ f.age }}</li>
  </ul>
</div>

<script type="text/javascript">
  Vue.config.productionTip = false

  const vm = new Vue({
    el: '#root',
    data: {
      student: {
        name: 'tom',
        age: 18,
        hobby: ['抽烟', '喝酒', '烫头'],
        friends: [
          { name: 'jerry', age: 35 },
          { name: 'tony', age: 36 }
        ]
      }
    },
    methods: {
      addSex() {
        // Vue.set(this.student,'sex','男')
        this.$set(this.student, 'sex', '男')
      },
      addFriend() {
        this.student.friends.unshift({ name: 'jack', age: 70 })
      },
      updateFirstFriendName() {
        this.student.friends[0].name = '张三'
      },
      addHobby() {
        this.student.hobby.push('学习')
      },
      updateHobby() {
        // this.student.hobby.splice(0,1,'开车')
        // Vue.set(this.student.hobby,0,'开车')
        this.$set(this.student.hobby, 0, '开车')
      },
      removeSmoke() {
        this.student.hobby = this.student.hobby.filter((h) => {
          return h !== '抽烟'
        })
      }
    }
  })



 

举报

相关推荐

0 条评论