이 글은 vue.js의 반응성 원리(코드 포함)에 대한 자세한 설명을 제공합니다. 이는 특정 참조 가치가 있으므로 도움이 필요한 친구에게 도움이 되기를 바랍니다.
저는 오래전부터 Anglejs를 접한 적이 있습니다. 그 당시 저는 이미 Anglejs가 더티 체크를 통해 데이터 모니터링과 페이지 업데이트 렌더링을 구현한다는 것을 알고 있었습니다. 그 후 vue.js를 접하게 되었는데, 당시 vue.js가 어떻게 데이터 업데이트를 모니터링하고 페이지를 다시 렌더링하는지 매우 궁금했습니다. 오늘은 vue.js 응답성의 원리를 단계별로 분석하고, 간단한 데모를 구현해보겠습니다.
먼저 몇 가지 기본 사항을 이해해 봅시다.
es5에는 객체 속성에 대한 getter 및 setter를 설정할 수 있는 Object.defineProperty API가 추가되어 사용자의 값 획득 및 객체 속성 할당을 탈취할 수 있습니다. 예를 들어 다음 코드는
const obj = { }; let val = 'cjg'; Object.defineProperty(obj, 'name', { get() { console.log('劫持了你的取值操作啦'); return val; }, set(newVal) { console.log('劫持了你的赋值操作啦'); val = newVal; } }); console.log(obj.name); obj.name = 'cwc'; console.log(obj.name);
Object.defineProperty를 통해 obj[name]의 값 획득 및 할당 작업을 하이재킹했기 때문에 여기에서 몇 가지 트릭을 수행할 수 있습니다. 예를 들어 obj[name]이 할당되면 작업을 수행할 수 있습니다. 값. 업데이트 페이지 작업을 트리거합니다.
게시-구독 패턴은 게시자와 구독자라는 두 가지 역할이 있는 가장 일반적인 디자인 패턴 중 하나입니다. 여러 구독자가 동일한 게시자의 이벤트를 구독할 수 있습니다. 이벤트가 발생하면 게시자는 이벤트를 구독한 모든 구독자에게 알립니다. 이해를 돕기 위해 예를 살펴보겠습니다.
class Dep { constructor() { this.subs = []; } // 增加订阅者 addSub(sub) { if (this.subs.indexOf(sub) < 0) { this.subs.push(sub); } } // 通知订阅者 notify() { this.subs.forEach((sub) => { sub.update(); }) } } const dep = new Dep(); const sub = { update() { console.log('sub1 update') } } const sub1 = { update() { console.log('sub2 update'); } } dep.addSub(sub); dep.addSub(sub1); dep.notify(); // 通知订阅者事件发生,触发他们的更新函数
Object.defineProperty와 게시-구독자 모델을 이해하고 나면 vue.js가 위 두 가지를 기반으로 데이터 모니터링을 구현한다는 것을 쉽게 상상할 수 있습니다.
vue.js는 먼저 Object.defineProperty를 사용하여 모니터링할 데이터의 getter 및 setter를 하이재킹합니다. 데이터의 속성이 할당/검색되면 vue.js는 이를 감지하고 그에 따라 처리할 수 있습니다.
구독-게시 모델을 통해 객체의 각 속성에 대해 게시자를 만들 수 있습니다. 다른 구독자가 이 속성에 의존하면 구독자가 게시자의 대기열에 추가됩니다. Object.defineProperty의 데이터 하이재킹을 사용하여 속성의 setter가 호출되면 속성 게시자는 모든 구독자에게 업데이트된 콘텐츠를 알립니다.
다음으로 구현해 보겠습니다(자세한 내용은 노트 참조).
class Observer { constructor(data) { // 如果不是对象,则返回 if (!data || typeof data !== 'object') { return; } this.data = data; this.walk(); } // 对传入的数据进行数据劫持 walk() { for (let key in this.data) { this.defineReactive(this.data, key, this.data[key]); } } // 创建当前属性的一个发布实例,使用Object.defineProperty来对当前属性进行数据劫持。 defineReactive(obj, key, val) { // 创建当前属性的发布者 const dep = new Dep(); /* * 递归对子属性的值进行数据劫持,比如说对以下数据 * let data = { * name: 'cjg', * obj: { * name: 'zht', * age: 22, * obj: { * name: 'cjg', * age: 22, * } * }, * }; * 我们先对data最外层的name和obj进行数据劫持,之后再对obj对象的子属性obj.name,obj.age, obj.obj进行数据劫持,层层递归下去,直到所有的数据都完成了数据劫持工作。 */ new Observer(val); Object.defineProperty(obj, key, { get() { // 若当前有对该属性的依赖项,则将其加入到发布者的订阅者队列里 if (Dep.target) { dep.addSub(Dep.target); } return val; }, set(newVal) { if (val === newVal) { return; } val = newVal; new Observer(newVal); dep.notify(); } }) } } // 发布者,将依赖该属性的watcher都加入subs数组,当该属性改变的时候,则调用所有依赖该属性的watcher的更新函数,触发更新。 class Dep { constructor() { this.subs = []; } addSub(sub) { if (this.subs.indexOf(sub) < 0) { this.subs.push(sub); } } notify() { this.subs.forEach((sub) => { sub.update(); }) } } Dep.target = null; // 观察者 class Watcher { /** *Creates an instance of Watcher. * @param {*} vm * @param {*} keys * @param {*} updateCb * @memberof Watcher */ constructor(vm, keys, updateCb) { this.vm = vm; this.keys = keys; this.updateCb = updateCb; this.value = null; this.get(); } // 根据vm和keys获取到最新的观察值 get() { Dep.target = this; const keys = this.keys.split('.'); let value = this.vm; keys.forEach(_key => { value = value[_key]; }); this.value = value; Dep.target = null; return this.value; } update() { const oldValue = this.value; const newValue = this.get(); if (oldValue !== newValue) { this.updateCb(oldValue, newValue); } } } let data = { name: 'cjg', obj: { name: 'zht', }, }; new Observer(data); // 监听data对象的name属性,当data.name发现变化的时候,触发cb函数 new Watcher(data, 'name', (oldValue, newValue) => { console.log(oldValue, newValue); }) data.name = 'zht'; // 监听data对象的obj.name属性,当data.obj.name发现变化的时候,触发cb函数 new Watcher(data, 'obj.name', (oldValue, newValue) => { console.log(oldValue, newValue); }) data.obj.name = 'cwc'; data.obj.name = 'dmh';
이로써 간단한 반응형 데이터 모니터링이 완료됩니다. 물론 이것은 vue.js의 응답성 원칙을 설명하기 위한 간단한 데모일 뿐입니다. 실제 vue.js 소스 코드는 다른 많은 로직이 추가되기 때문에 더욱 복잡해집니다.
위 내용은 vue.js 응답성 원칙에 대한 자세한 설명(코드 포함)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!