首页 > 其他分享 >Vue 2x 系列之(十三)Vue监测数据的原理

Vue 2x 系列之(十三)Vue监测数据的原理

时间:2024-02-28 12:59:16浏览次数:23  
标签:监测数据 Vue name 2x vm set 数组 data

Vue监测数据的原理

思路:举例 ==》 监测对象数据原理 ==》 Vue.set() ==》 监测数组数据原理 ==》 说明前面例子中的现象

Vue监测数据改变的原理

Vue底层监测data中数据改变的原理和watch中监测数据的原理是一致的,watch是Vue提供给我们用于自行监视数据变化的配置项

1. 更新时的一个问题

<body>
	<!-- 准备好一个容器-->
	<div id="root">
		<h2>人员列表</h2>
		<input type="button" value="更新马冬梅的信息" @click="updateMei"/>
		<ul>
			<li v-for="(p,index) of persons" :key="index">
				{{p.name}}-{{p.age}}-{{p.sex}}
			</li>
		</ul>
	</div>

	<script type="text/javascript">
		Vue.config.productionTip = false
		
		//用computed实现
		const vm =  new Vue({
			el:'#root',
			data:{
				persons:[
					{id:'001',name:'马冬梅',age:19,sex:'女'},
					{id:'002',name:'周冬雨',age:25,sex:'女'},
					{id:'003',name:'周杰伦',age:21,sex:'男'},
					{id:'004',name:'温兆伦',age:22,sex:'男'}
				]
			},
			methods: {
				updateMei() {
					// 逐个字段修改值Vue可以监测到数据变化
					// this.persons[0].name = '马老师';
					// this.persons[0].age = 50;
					// this.persons[0].sex = '男'
					
					// 一次修改整行信息Vue并未监测到数据变化
					this.persons[0] = {id:'001',name:'马老师',age:50,sex:'男'}
				}
			}
		}) 
	</script>
</body>

2. Vue监测对象数据的原理

回顾数据代理

响应式:数据变了页面也会相应的更新

Vue监测对象数据的原理:setter

name一改,setter就被调用,页面中的模板就重新解析,就会生成新的虚拟DOM,然后就是新旧虚拟DOM对比,更新页面

3. 模拟一个数据监测

<body>
	<script type="text/javascript" >

		let data = {
			name:'尚硅谷',
			address:'北京',
		}

		//创建一个监视的实例对象,用于监视data中属性的变化
		const obs = new Observer(data)		
		console.log(obs)	

		//准备一个vm实例对象
		let vm = {}
		vm._data = data = obs


		// Observer:一个构造函数,用于创建监视的实例对象
		// 这里的obj就是传入的data
		function Observer(obj){
			//汇总对象中所有的属性形成一个数组
			const keys = Object.keys(obj)
			//遍历,这里的k就是obj中的每一个key【name、address】
             //加工data:把data中的每一组key、value都形成了getter、setter的写法【有了这一步就可以做响应式了】
			keys.forEach((k)=>{
				// 这里的this就是Observer的实例对象,也就是上面的obs
				Object.defineProperty(this,k,{
					get(){
						// 这里的obj永远是创建实例时传入的data引用,即使后面data的引用变了,obj的指向也不会变
						console.log(obj)
						return obj[k]
					},
					set(val){
						console.log(`${k}被改了,我要去解析模板,生成虚拟DOM.....我要开始忙了`)
						obj[k] = val
					}
				})
			})
		}
	</script>
</body>

相对于我们自己写的数据监测来说,Vue能够对多层次data进行监测,而在上面的例子里我们只监测了第一层,而且Vue对_data做了数据代理,能够更方便的修改_data中的数据

4. Vue.set()方法

实现了在data中动态添加数据的功能

读取对象里面不存在的属性 【如果是直接读取了Vue身上不存在的属性【data里没有的属性】就会报错】,不会报错,值是undefined,Vue中undefined是不会直接显示在页面上的

判断一个属性的值是否为undefined与判断true、false逻辑相同,false包含了undefined

向vm._data中通过vm._data.key = value的方式直接添加的数据并不是响应式数据,因为没有对应的setter

如果想要动态添加的数据也支持响应式,可以使用Vue.set()

Vue.set(target, key, val):

target:往谁的身上追加一个属性

key:属性名

val:属性值

注:vm.$set()功能同Vue.set()

Vue.set()的局限性:只能给data中的某一个对象【响应式对象】动态添加属性,而不能给data【根数据对象】/vm实例对象动态添加属性;除此之外,如果模板中需要展示动态增加的数据,模板中是需要事先准备好结构的,应用场景有限

官网:https://v2.cn.vuejs.org/v2/api/#Vue-set

如果要给App组件中data里的一个对象X添加属性,而App组件已经将这个对象X传给了子组件,子组件中也是可以通过vm.$set()给这个对象X中动态添加属性的。

// App组件中的data里有一个列表
data(){
  return {
  	todoList: [{id:'1',name:'ka'},{id:'2',name:'ha'}]
  }
}

// App将这列表以props的方式传给了子组件List
<List :todoList="todoList"></List>

// List组件又将列表中的每一项传给了自己的子组件Item
<Item 
      v-for="todo in todoList" 
      :key="todo.id" 
      :thingid="todo.id" 
      :thingtitle="todo.title"
      :isdel="todo.isDel"
      :todo="todo"
      :getIsSelected="getIsSelected"
      :del="del"
></Item>

// Item就可以通过$set()这个API为列表的每一项动态添加属性
// 这里的todo就是由父组件List组件传递过来的,也就是App组件中data里todoList列表的每一项
edit(todo){
  // 这里的this是vc,也就是Item组件的实例对象
  console.log(this)
  this.$set(todo, 'isEdit', false)
}

5. Vue监测数组数据的原理

通过索引值修改数组中的某一个元素,Vue是监测不到的,Vue监测数组数据并不是通过setter实现的

同时,数组中也没有索引对应的getter和setter

数组中能够引起数组自身改变的几个API【数组调了这几个API,原数组就变了】:

push、pop、shift、unshift、splice、sort、reverse

这几个方法称为数组的变更方法

在Vue中,对于数组数据,只有调用了上述七个能够引起数组改变的API,Vue才能够监测到变化

第1节例子的代码如下

<body>
	<!-- 准备好一个容器-->
	<div id="root">
		<h2>人员列表</h2>
		<input type="button" value="更新马冬梅的信息" @click="updateMei"/>
		<ul>
			<li v-for="(p,index) of persons" :key="index">
				{{p.name}}-{{p.age}}-{{p.sex}}
			</li>
		</ul>
	</div>

	<script type="text/javascript">
		Vue.config.productionTip = false
		
		//用computed实现
		const vm =  new Vue({
			el:'#root',
			data:{
				persons:[
					{id:'001',name:'马冬梅',age:19,sex:'女'},
					{id:'002',name:'周冬雨',age:25,sex:'女'},
					{id:'003',name:'周杰伦',age:21,sex:'男'},
					{id:'004',name:'温兆伦',age:22,sex:'男'}
				]
			},
			methods: {
				updateMei() {
					// 逐个字段修改值Vue可以监测到数据变化
					// this.persons[0].name = '马老师';
					// this.persons[0].age = 50;
					// this.persons[0].sex = '男'
					
					// 一次修改整行信息Vue并未监测到数据变化
					this.persons[0] = {id:'001',name:'马老师',age:50,sex:'男'}
				}
			}
		}) 
	</script>
</body>

直接通过索引修改数组的元素Vue是监测不到的,只能通过调用固定的七个API改变数组,Vue才能够监测到

Vue中是如何监测到我们调用了上述七个API的?

包装

Vue对数组数据进行了包装,数组数据调用的七个API已经不是Array原型对象身上的API了,所以Vue能够监测到我们调用了这几个API

Vue对数组的监测是靠包装数组身上常用的修改数组的方法【数组的变更方法】实现的

Vue包装后的API做了两件事:

  1. 调用Array原型对象身上对应的API
  2. 重新解析模板,引起页面变化

官方网站:https://v2.cn.vuejs.org/v2/guide/list.html#数组更新检测

如果data中某个数组的元素都是对象,通过数组的变更方法给该数组添加对象元素时,Vue会为每个对象创建getter和setter,保证新增加的数组内的对象元素也是响应式的

如果不想通过数组的变更方法改变数组,同时还向让Vue监测到数组元素的变化,可以通过Vue.set()/vm.$set()实现

6. 总结

Vue监视数据的原理:
	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()
	
	特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象【vm._data】 添加属性!!!

数据劫持:为data中的每一个属性增加了对应的getter和setter,属性值读取/改变时,必须先经过getter和setter,增加getter和setter的这个动作就叫做数据劫持。

标签:监测数据,Vue,name,2x,vm,set,数组,data
From: https://www.cnblogs.com/wzzzj/p/18039951

相关文章

  • Vue 2x 系列之(十二)列表渲染
    列表渲染1.v-for指令v-for指令: 1.用于展示列表数据 2.语法:v-for="(item,index)inxxx":key="yyy" 3.可遍历:数组(用的最多)、对象、字符串(用的很少)、指定次数(用的很少)<body> <!--准备好一个容器--> <divid="root"> <!--遍历数组--> <h2>人员列表(......
  • Vue 2x 系列之(十一)条件渲染
    条件渲染符合某些条件,就给你渲染某些东西;不符合条件,要渲染的东西就不会显示原生可以通过display:none;、visibility:hidden;、opacity:0;几种方式实现v-if和v-else-if、v-else需要作为一组指令使用,中间不允许被打断,v-else是不需要加表达式的只能配合v-if使用,不能配合v-show......
  • Vue 2x 系列之(十)绑定样式
    绑定样式1.class样式绑定样式: 1.class样式【不变的样式写在class、style中,变化的样式写在:class中,最终的样式为三者的并集】 写法:class="xxx"xxx可以是字符串、对象、数组。 字符串写法适用于:类名不确定,要动态获取。 对象写法适用于:要绑定多个样式,个数......
  • Vue 2x 系列之(九)监视和侦听属性
    监视/侦听属性【watch】用于监视某一个属性的变化监视属性watch: 1.当被监视的属性变化时,回调函数【handler()】自动调用,进行相关操作 2.监视的属性必须存在,才能进行监视!!【监视不存在的属性不会报错】 3.配置监视的两种写法: (1).newVue时传入watch配置 (2).通过vm.......
  • Vue 2x 系列之(八)计算属性
    计算属性【computed】1.姓名案例1.1{{}}插值语法版本<body> <divid="root"> 姓:<inputtype="text"v-model="firstName"/> 名:<inputtype="text"v-model="lastName"/> <hr/> 全名:{{firstNa......
  • Vue 2x 系列之(七)事件处理
    事件处理1.事件的基本使用模板只能用到对应Vue实例中的数据和方法,像这里的showInfo,模板中是调不到的所有被Vue管理的函数【methods对象中的函数】不能写成箭头函数,只能写成普通函数,否则,函数中的this就不再是Vue实例,而是Window对象只有配置在data中的内容才会做数据代理和数......
  • Vue 2x 系列之(六)数据代理
    数据代理1.Object.defineProperty【ES6中的知识点】用于给一个对象添加/定义属性,可以对追加的属性进行很多高级的限制【比如控制属性是否可以枚举、修改、删除】Object.defineProperty方法在Vue中的应用数据劫持数据代理计算属性Object.defineProperty方法的几个参数:给......
  • Vue 2x 系列之(五)理解MVVM
    理解MVVMMVVM模型 1.M:模型(Model):data中的数据 2.V:视图(View):模板代码 3.VM:视图模型(ViewModel):Vue实例观察发现: 1.data中所有的属性,最后都出现在了vm身上。 2.vm身上所有的属性及Vue原型上所有属性,在Vue模板中都可以直接使用。把开发人员从繁琐的DOM......
  • Vue 2x 系列之(四)数据绑定
    数据绑定Vue中有2种数据绑定的方式: 1.单向绑定(v-bind):数据只能从data流向页面。 2.双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。【通俗:数据变,页面变;页面变,数据变】 备注: 1.双向绑定一般都应用在表单类【输入类,有value属性的标签才可以用,因为v-mode......
  • Vue 2x 系列之(三)模板语法
    模板语法容器里的代码被称为【Vue模板】,模板语法就是指模板的代码中可以写哪些Vue语法【类似:{{name}}】插值语法:把指定的值放在指定的位置。插值语法往往用于指定标签体内容。指令语法:Vue指令所在的属性值会作为JavaScript表达式执行v-bind:用于给标签中的任意一个属性动态的......