素材巴巴 > 程序开发 >

vue数据劫持 ajax,vue数据双向绑定原理-observer

程序开发 2023-09-10 08:45:39

vue数据双向绑定原理, 和简单的实现

b1e06502fe3a78b52502ddac800dcd3e.png

vue 数据双向绑定原理, 和简单的实现

去他喵的底层原理, 框架内核, 老夫写代码只用 Jquery 。

个人觉得, 不论是否 是长期与之交集, 还是应该看下核心的东西. 多多了解高人是如何实现的 , 这样才能学到更多的知识, 才能成长进步.  倘若某天被人问起, 某种框架 内裤, 其实现原理, 那么只能是一脸懵逼了..

实现数据绑定的做法有大致如下几种:发布者-订阅者模式(backbone.js)

脏值检查(angular.js)

数据劫持(vue.js)

vue.js则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

假如写过 C# winform 自定义控件的, 我想更好理解之后的逻辑和实现原理

在 C# 中 当控件的某个属性发生了变化, 就刷新视图priveate int a ;

public int A

{

get { return a; }

set { if(a!=value){a = value; Invalidate(); } }

}

# 当a的值发生变化, 就重绘视图

再来看看Object.defineProperty(obj, prop, descriptor)  方法

Object.defineProperty()  方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。obj需要被操作的目标对象

prop目标对象需要定义或修改的属性的名称。

descriptor将被定义或修改的属性的描述符

descriptorconfigurable当且仅当该属性的configurable为true时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为false。

enumerable当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中。默认为false。 数据描述符同时具有以下可选键值:

value该属性对应的值。可以是任何有效的JavaScript值(数值,对象,函数等)。默认为undefined。

writable当且仅当该属性的writable为true时,该属性才能被赋值运算符改变。默认为false。 存取描述符同时具有以下可选键值:

get一个给属性提供getter的方法,如果没有getter则为undefined。该方法返回值被用作属性值。默认为undefined。

set一个给属性提供setter的方法,如果没有setter则为undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为undefined。

先来实现一个简单数据劫持var A = {};

var a = "";

Object.defineProperty(A, "a", {

set: function (value) {

a = value;

},

get: function () {

return "My name is " + a;

},

});

A.a = "chuchur";

console.log(A.a); // My name is chuchur

不光是这么简单, 来看下 vue 的代码

{{word}}

change model

var vm = new Vue({

el: "#app",

data: {

word: "Hello World!",

},

methods: {

sayHi: function () {

this.word = "Hi, everybody!";

},

},

});

已经实现的简单的数据劫持, 那么有多个属性, 就要实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,还需要一个订阅器Dep来收集这些属性的变动来通知订阅者

元素节点的v-model,v-on:click, 就需要实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数

最后实现一个订阅者Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图

大概的流程图如下:

4605d636e189e53a639f9b84b68ec3c9.png

实现 Observer

将需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化// observe

function observe(data) {

if (data && typeof data === "object") {

// 取出所有属性遍历

Object.keys(data).forEach(function (key) {

defineReactive(data, key, data[key]);

});

}

return;

}

function defineReactive(data, key, val) {

observe(val); // 监听子属性

Object.defineProperty(data, key, {

enumerable: true, // 可枚举

configurable: false, // 不能再define

get: function () {

return val;

},

set: function (value) {

console.log("监听到值变化了: ", val, "==>", value);

val = value;

},

});

}

var A = {

fristName: "chuchur",

age: 29,

};

observe(A);

A.fristName = "nana"; //监听到值变化了: chuchur ==> nana

A.age = 30; //监听到值变化了: 29 ==> 30

这样就实现了多个属性的监听, 接下来就是实现订阅器Dep, 当这些属性变化的时候, 触发通知 notify, 告诉执行订阅者 执行更新函数//Dep

function Dep() {

this.subs = [];

}

Dep.prototype = {

addSub: function (sub) {

this.subs.push(sub);

},

notify: function () {

this.subs.forEach(function (sub) {

sub.update();

});

},

};

把订阅器植入到监听器里function defineReactive(data, key, val) {

var dep = new Dep()

observe(val); //监听子属性

Object.defineProperty(data, key, {

set: function(value) {

dep.notify() //发出通知, 我被改变了

}

});

}

至此, 简陋的 监听器就实现完成了, 接下来继续完成Watcher.


标签:

素材巴巴 Copyright © 2013-2021 http://www.sucaibaba.com/. Some Rights Reserved. 备案号:备案中。