vue基础教学(7)

本文深入探讨了Vue实例与组件中data属性的使用区别,强调了组件data必须为函数的原因,防止数据污染。介绍了MVVM模型,以及如何通过数据代理实现响应式。同时,详细阐述了Vue的响应式原理,包括Object.defineProperty的set和get方法在数据劫持中的作用,并通过示例展示了Vue中更新深层对象属性的正确方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、实例和组件定义data的区别

vue实例的时候定义data属性既可以是一个对象,也可以是一个函数

const app = new Vue({
    el:"#app",
    // 对象格式
    data:{
        foo:"foo"
    },
    // 函数格式
    data(){
        return {
             foo:"foo"
        }
    }
})

组件中定义data属性,只能是一个函数

如果为组件data直接定义为一个对象

Vue.component('component1',{
    template:`<div>组件</div>`,
    data:{
        foo:"foo"
    }
})

则会得到警告信息

警告说明:返回的data应该是一个函数在每一个组件实例中

二、组件data定义函数与对象的区别

上面讲到组件data必须是一个函数,不知道大家有没有思考过这是为什么呢?

在我们定义好一个组件的时候,vue最终都会通过Vue.extend()构成组件实例

这里我们模仿组件构造函数,定义data属性,采用对象的形式

function Component(){
 
}
Component.prototype.data = {
	count : 0
}

 创建两个组件实例

const componentA = new Component()
const componentB = new Component()

修改componentA组件data属性的值,componentB中的值也发生了改变

console.log(componentB.data.count)  // 0
componentA.data.count = 1
console.log(componentB.data.count)  // 1

产生这样的原因这是两者共用了同一个内存地址,componentA修改的内容,同样对componentB产生了影响

如果我们采用函数的形式,则不会出现这种情况(函数返回的对象内存地址并不相同)

function Component(){
	this.data = this.data()
}
Component.prototype.data = function (){
    return {
   		count : 0
    }
}

修改componentA组件data属性的值,componentB中的值不受影响

console.log(componentB.data.count)  // 0
componentA.data.count = 1
console.log(componentB.data.count)  // 0

vue组件可能会有很多个实例,采用函数返回一个全新data形式,使每个实例对象的数据不会受到其他实例对象数据的污染

结论

  • 根实例对象data可以是对象也可以是函数(根实例是单例),不会产生数据污染情况
  • 组件实例对象data必须为函数,目的是为了防止多个组件实例对象之间共用一个data,产生数据污染。采用函数的形式,initData时会将其作为工厂函数都会返回全新data对象

案例:

<body>
		<div id="app">
           <cpn1></cpn1>
		   <cpn1></cpn1>
		   <cpn1></cpn1>
		   <hr />
		   <cpn2></cpn2>
		   <cpn2></cpn2>
		   <cpn2></cpn2>
		</div>
		<script src="vue.js"></script>
		<template id="cpn1">
			<div>
				<button type="button" @click="count++">+</button>
				<h2>{{count}}</h2>
				<button type="button" @click="count--">-</button>
			</div>
		</template>
		<template id="cpn2">
			<div>
				<button type="button" @click="count++">+</button>
				<h2>{{count}}</h2>
				<button type="button" @click="count--">-</button>
			</div>
		</template>
		<script>
			var obj = {
				count:0
			}
			const app = new Vue({
				el: "#app",
				data: {
				
				},
				methods: {
                 
				},
				components:{
					cpn1:{
						template:'#cpn1',
						data(){
							return obj
						}
					},
					cpn2:{
						template:'#cpn2',
						data(){
							return {count:0}
						}
					}
				}
			})
		</script>
	</body>

三、MVVM模型

MVVM表示的是 Model-View-ViewModel

  • Model:模型层,负责处理业务逻辑以及和服务器端进行交互
  • View:视图层:负责将数据模型转化为UI展示出来,可以简单的理解为HTML页面
  • ViewModel:视图模型层,用来连接Model和View,是Model和View之间的通信桥梁

案例:

<body>
		<div id="app">
            <h2>{{name}}</h2>
			<h2>{{age}}</h2>
		</div>
		<script src="vue.js"></script>
		<script>
			const vm = new Vue({
				el: "#app",
				data() {
					return {
						name:'张三',
						age:30
					}
				},
				methods: {
                 
				},
				computed:{
					
				}
			})
		</script>

四、数据代理

<body>
		<div id="app">
			我们是web2208班
		</div>
		<script>
			/* var a = {age:20}
		  var b = {height:30}
		  Object.defineProperty(b,'age',{
			  get(){
				  return a.age
			  },
			  set(val){
				  a.age = val
			  }
		  }) */

			/*  var data = {
				 msg:'张三',
				 age:40
			  }
			  var vm = {}
			  Object.defineProperty(vm,'msg',{
				  enumerable:true,
				  configurable:true,
				  get(){
					  return data.msg
				  },
				  set(newval){
					  data.msg = newval
					  document.querySelector('#app').textContent = newval
				  }
			  })
			  
			  vm.msg="Hello 响应式原理" */


			let data = {
				msg: 'Hello Vue',
				count: 0
			}
			let vm = {}
			
			function defineProperies(data){
				Object.keys(data).forEach(key=>{
					Object.defineProperty(vm,key,{
						enumerable:true,
						configurable:true,
						get(){
							return data[key]
						},
						set(newval){
							data[key] = newval
							document.querySelector('#app').textContent = newval
						}
					})
				})
			}
			defineProperies(data)
			vm.count="111111";
		</script>
	</body>

五、vue2的响应式原理

Vue的响应式原理是用Object.definePrototy()的set与get结合观察者模式进行数据劫持;

首先了解一下Object.definePrototy()的set与get;

在获取对象prototy的时候,会自动调用get方法,在修改时会自动调用set方法

VUE给data里所有的属性加上set,get这个过程就叫做Reactive化。
 

<body>
		<div id="app">
			<!-- <div @click="qq">
				{{isAgree.msg}}
			</div> 
			<div>
				{{isAgree.ww}}
			</div>
			<div>
				{{isAgree.qq}}
			</div> -->


			<h2 v-for="(item,index) in isAgree.web" :key="index">{{item}}</h2>
			<button @click="updateweb">点击</button>

		</div>
		<script src="vue.js"></script>
		<script>
			const app = new Vue({
				el: "#app",
				data() {
					return {
						isAgree: {
							msg: 'zhangsan',
							web: ['html', 'js']
						}

					}
				},
				methods: {
					qq() {
						/* this.isAgree.ww = 'list'
						console.log(this.isAgree.ww); */
						/* delete this.isAgree.msg
						console.log(this.isAgree.msg); */
						/* Vue.set(this.isAgree,'ww','list')
						this.$set(this.isAgree,'qq','2') */
						/* 	Vue.delete(this.isAgree, 'msg') */
						this.$delete(this.isAgree, 'msg')
					},
					updateweb(){
						this.isAgree.web[0] = 'lili'
						console.log(this.isAgree.web[0]);
					}
				},
				computed: {

				}
			})
		</script>
	</body>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值