Skip to content
On this page

双向绑定

模拟控制一个值

javascript
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>vue</title>
</head>
<body>
    <div id="content"></div>
    <input type="text" id="input">
</body>
  
<script>
    let obj = {}
    let temp = {};
    document.getElementById("content").innerHTML = obj.name
    // 'name' 代表属性
    Object.defineProperty(obj,'name',{
        configurable:false, //是否可删除
        // writable:true,// 是否可赋值(如果使用set方法,则不能使用)
        enumerable:true, // 是否可枚举,也是就for..in..
        // value:1,// 值(如果使用get方法,则不能使用)
        get(){ // 取obj的name会触发get方法
            return temp['name']
        },
        set(val){// 给obj赋值会触发get方法
            // console.log(val);
            temp['name'] = val // 改变temp的结果
            input.value = val // 将值赋值给输入框
        }
    });
    input.value = obj.name // 页面一加载,会将调用get方法
    input.addEventListener('input',function(){ // 等待输入框的变化
        obj.name = this.value // 当值变化时会调用set方法
        document.getElementById("content").innerHTML = obj.name
    })
</script>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

vue会循环data中的数据(数据劫持) 依次的增加getter和setter

javascript
 let vm = new Vue({
   el:'#content',
   data:{
     a:{}
   }
 })
1
2
3
4
5
6

但是这时候我想添加一个school方法,发现没有产生getter和setter

1.1 方法一 $set

使用变量时 先要初始化,否则新加的属性不会导致页面刷新

javascript
 vm.$set(vm.a,"school",'1')// 此方法可以给对象添加响应式的变化
1

1.2 方法二 替换原对象

javascript
vm.a = {"school":"heihei",age:8};
1

1.3 数组问题

去改变数组中的某一项监控不到的,也不能改变数组的长度方法

javascript
let vm = new Vue({
  el:'#content',
  data:{
    a:[1,2,3,4,5,6]
  }
})
1
2
3
4
5
6

错误方法

javascript
vm.a[0] =100
vm.a.length -=2 
1
2

变异方法:pop push shift unshit sort reserve splice

javascript
 vm.a = vm.a.map(item=>item*3) 
1

双向绑定手写

思考为什么vue2中的数组不可以直接操作

采用Object.defineProperty去实现

javascript
let obj = {
    name: "wjw",
    info: {
        age: 12,
        height: 100,
    },
};

function render() {
    console.log("====================================");
    console.log("数据更新了");
    console.log("====================================");
}

function objsever(obj) {
    if (typeof obj === "object") {
        for (const key in obj) {
            if (Object.hasOwnProperty.call(obj, key)) {
                defineReactive(obj, key, obj[key]);
            }
        }
    }
}

function defineReactive(data, key, value) {
    objsever(value);
    Object.defineProperty(data, key, {
        get() {
            return value;
        },
        set(newValue) {
            objsever(newValue);
            if (value !== newValue) {
                render();
                value = newValue;
            }
        },
    });
}
objsever(obj);
obj.name = "myq";


function $set(data,key,value){
	defineReactive(data,key,value);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
  1. 如果给对象新增属性 是不会被监听的$set
  2. 如果想给对象增加一个不存在的属性 obj.info =
javascript
function render() {
    console.log("====================================");
    console.log("数据更新了");
    console.log("====================================");
}

let obj = [1,2,3]
let methods = ['pop','shift','unshift','sort','reverse','splice','push'];
// 先获取到原来原型上的方法
let arrayProto = Array.prototype;
// 创建一个自己的原型,并且重写methods这些方法
let proto = Object.create(arrayProto);

methods.forEach(method=>{
    proto[method] = function(){ // AOP
        render();
        arrayProto[method].call(this,...arguments);
    }
})


function observer(obj){
    if(Array.isArray(obj)){
        obj.__proto__ = proto;
        return;
    }
}

observer(obj)
obj.push(123)

console.log('====================================');
console.log(obj);
console.log('====================================');

function $set(data,key,value){
  if(Array.isArray(data)){
    return data.splice(key,1,value);
  }
}

$set(obj,0,100);
// 不支持数据长度变化,也不支持数组的内容发现变化 必须通过上面的方法
来触发更新 或者替换一个数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

使用proxy去实现

javascript
function render() {
    console.log('====================================');
    console.log("视图更新");
    console.log('====================================');
}


// 可以支持数组,而且不会区分是对象还是数组
// 兼容性vue 3.0 会采用如果支持proxy 就使用proxy 不支持还是使用Object.definePropert
let obj = {
    name:'wjw',
    age: 9
}

let hander = {
    get(target, key) {
        if (typeof target[key] == 'object' && typeof target[key] !== null) {
            return new Proxy(target[key], hander);
        }
        return Reflect.get(target, key);
    },
    set(target, key, value) {
        if(key==='length') return true;
        render();
        return Reflect.set(target, key, value);
    },
}
let proxy = new Proxy(obj, hander);

proxy.age = 100;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
沪ICP备20006251号-1