一、实例和组件定义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>