<body>
<div id="app">
姓名:<input type="text" v-model="name">
div>
<script>
// ViewModel VM
const vm = new Vue({
el : '#app',
// Model M
data : {
name : 'zhangsan'
}
})
script>
body>
通过Vue实例都可以访问哪些属性?(通过vm都可以vm. 什么。)
vm.$el
可以获取到Vue实例所绑定的DOM元素,vm.$watch
可以用于监听数据的变化。vm._uid
表示Vue实例的唯一标识符,vm._isVue
用于标识该对象是否是Vue实例。vm.$delete
等。vm.$delete
方法用于删除对象的属性,并且会触发视图的更新。<body>
<div id="app">
<h1>{{msg}}h1>
div>
<script>
let dataObj = {
msg: "Hello Vue!",
};
const vm = new Vue({
el: "#app",
data: dataObj,
});
// 按说msg是dataObj对象的属性。
console.log("dataObj的msg", dataObj.msg);
// msg属性也可以通过vm来访问呢?
// 这是因为Vue框架底层使用了数据代理机制。
// 要想搞明白数据代理机制,必须有一个基础知识点要学会:Object.defineProperty()。
// console.log("vm的msg", vm.msg);
// 模拟Vue构造函数,无法直接用newVm.msg打印出
function myVue(obj) {
return obj
}
let newVm = new myVue({
el: "#app",
data: dataObj,
});
console.log(newVm.data.msg);
script>
body>
Object.defineProperty(给哪个对象新增属性, '新增的这个属性名叫啥', {给新增的属性设置相关的配置项key:value对})
Object.defineProperty(person, "age", { value: 30 });
就给 person
对象添加了 age
属性,并赋值为 30
。true
表示可以修改。false
表示不能修改。如 Object.defineProperty(person, "name", { value: "Tom", writable: false });
之后,person.name
的值就不能被修改了。true
表示该属性是可以遍历的。(可枚举的,可迭代的。)false
表示该属性是不可遍历的。例如 Object.defineProperty(person, "secret", { value: "Some secret", enumerable: false });
后,使用 for...in
循环遍历 person
对象时,secret
属性不会被遍历到。true
表示该属性是可以被删除的。false
表示该属性不可以被删除。如 Object.defineProperty(person, "id", { value: 1, configurable: false });
后,delete person.id
将不会成功。getter
方法被自动调用。getter
方法的返回值非常重要,这个返回值就代表读取的这个属性它的值。setter
方法被自动调用。setter
方法上是有一个参数的,这个参数可以接收传过来的值。setter
和 getter
的时候,value
和 writable
配置项都不能存在。<body>
<script>
// 这是一个普通的对象
let person = {};
// 临时变量
let temp;
// 给上面的phone对象新增一个color属性
Object.defineProperty(person, "name", {
//value : '章三',
//writable : true,
enumerable: false,
// true表示该属性是可以遍历的。(可枚举的,可迭代的。)
// false表示该属性是不可遍历的。
configurable: false,
// true表示该属性是可以被删除的。
// false表示该属性是不可以被删除的。
// getter方法配置项
get: function () {
console.log("getter方法执行了@@@");
//return '动态'
//return this.name //递归,死循环
return temp;
},
// setter方法配置项
set: function (val) {
console.log("setter方法执行了@@@", val);
//this.name = val //递归,死循环
temp = val;
},
});
script>
body>
通过访问 代理对象的属性 来间接访问 目标对象的属性。数据代理机制的实现需要依靠:Object.defineProperty()
方法。
注意:代理对象新增的这个属性的名字 和 目标对象的属性名要一致,这样我们访问代理对象属性,就像在访问目标对象的属性一样
<script>
// 目标对象
let target = {
name: "zhangsan",
};
// 代理对象
let proxy = {};
// 如果要实现数据代理机制的话,就需要给proxy新增一个name属性。
Object.defineProperty(proxy, "name", {
get() {
console.log("getter方法执行了@@@@");
// 间接访问目标对象的属性
return target.name;
},
set(val) {
target.name = val;
},
});
</script>
vm
这个Vue实例上可能会出现 _xxx 或 x x x 属性,而这个属性名可能会和 V u e 框架自身的属性名冲突。例如, V u e 框架已经使用了 ‘ xxx 属性, 而这个属性名可能会和Vue框架自身的属性名冲突。 例如,Vue框架已经使用了 ` xxx属性,而这个属性名可能会和Vue框架自身的属性名冲突。例如,Vue框架已经使用了‘el来表示绑定的DOM元素,如果用户定义的属性也叫
$el`,就会产生混淆和错误。<body>
<div id="app">
<h1>{{msg}}h1>
div>
<script>
const vm = new Vue({
el: "#app",
data: {
msg: "Hello Vue!",
_name: "zhangsan", //不会做数据代码,vm上看不到
$age: 20,//不会做数据代码,vm上看不到
},
});
script>
body>
简单实现 myvm.name==options.data.name
<script>
const myvm = new MyVue({
data: {
msg: "Hello Vue!",
name: "jackson",
age: 30,
},
});
</script>
数据代理js
// 实现数据代理,目的是读取 myvm.name == options.data.name
// 定义一个Vue类
class MyVue {
// 定义构造函数
// options 是一个对象{}
// options对象中有一个data配置项
constructor(options) {
Object.keys(options.data).forEach((propertyName, index) => {
Object.defineProperty(this, propertyName, {
get() {
// 读取对象的属性值 对象[变量]
return options.data[propertyName];
},
set(val) {
options.data[propertyName] = val;
},
});
});
}
}
在 vm
身上,有两个属性 $data
,_data
,这两个属性都指向Vue底层的真实的 data
对象,通过 $data
,_data
获取各属性值,是不会走数据代理机制的。
其中:_data
是框架内部使用的,可以看做是私有的;$data
,这是Vue框架对外公开的一个属性。
也就是说Vue框架会将 data
中的数据实时通过 Object.defineProperty
拷贝一份放在 $data
以及 _data
身上,供 vm
去使用。
_data
中的所有数据属性通过 Object.defineProperty
添加到 vm
实例上,并且提供了 getter
和 setter
方法,于是通过 vm
直接获取数据的时候就调用 getter
,获取 _data
中的值,当修改的时候调用 setter
修改 _data
中的值。这样,开发者在模板中直接使用数据时,实际上是通过 vm
实例访问到了 _data
中的数据。vm
上挂的属性就是 _data
中的数据代理,那么 {{vm._data.name}}
和 {{name}}
是等价的,{{vm._data.name='szk2'}}
和 {{name='szk2'}}
也是等价的。所以就是为了写代码的方便,在 {{}}
直接写数据,或者直接修改就能操作到 _data
中。例如,在模板中直接写 {{msg}}
就可以展示 _data
中 msg
的值,当 msg
的值发生变化时,视图会自动更新。data
加工了一下,变成 _data
,让每个属性有了 getter
和 setter
。vue通过监听者 observer
来监听 data
中的数据,通过 getter
和 setter
监听者里面的方法,监听数据的读取与修改,当修改属性的时候,setter
被调用,在 setter
方法中就会让订阅者执行重新解析模板的操作,从而改变了页面。例如,当用户在输入框中输入内容,修改了绑定的数据时,setter
方法会被触发,进而通知相关的订阅者(如视图更新函数),使得页面上的显示内容也随之更新。data
和加工之后的 data
有什么区别:原始的 data
只是一个普通的对象,其中的属性没有任何特殊的行为。而经过数据劫持处理后的 _data
,其属性具有了 getter
和 setter
方法,能够实现数据的响应式变化。vm
,vm
身上会有 _data
属性,_data
通过劫持 data
配置项,再通过 defineProperty
的 getter
和 setter
,得到的响应式的数据。把vue中的 data
数据拦截改写成具有 getter
和 setter
形式的 _data
,就是数据劫持。vm
中 _data
中的数据又通过数据代理(也是通过 defineProperty
的 getter
和 setter
实现),放置到 vm
身上,vm
可以通过 getter
方法,setter
方法直接使用 _data
中的数据,方便书写数据。data
,通过 Object.defineProperty
的 setter
和 getter
进行数据劫持,使得 data
改写为到 _data
(使得数据改写为响应式的数据,具有 getter
和 setter
);vm
进行数据代理,代理 _data
。