Vue 양 방향 데이터 바 인 딩 원리 분석
7179 단어 Vue양 방향 바 인 딩
Vue.데이터 납치 와 게시 자-구독 자 모드 를 결합 하 는 방식 으로 Object.defineProperty()를 통 해 각 속성의 setter 와 getter 를 납치 하고 데이터 가 변동 할 때 구독 자 에 게 메 시 지 를 발표 하여 해당 함수 의 리 셋 을 촉발 합 니 다.
사고의 방향 을 정리 하 다.
mvvm 의 양 방향 연결 을 실현 하려 면 다음 과 같은 몇 가 지 를 실현 해 야 합 니 다.
1.데이터 감청 기 Observer 를 실현 하여 대상 의 모든 속성 을 감청 할 수 있 고 변화 가 발생 하면 최신 값 을 받 아 구독 자 에 게 알 릴 수 있 습 니 다.
2.해석 기 Compile 을 실현 하고 모든 하위 요소 노드 의 명령 을 스 캔 하고 해석 하 며 템 플 릿 명령 에 따라 데 이 터 를 교체 하고 보기 와 해당 하 는 리 셋 함 수 를 초기 화 합 니 다.
3.Watcher 를 실현 하고 Observer 와 Compile 의 다리 로 서 속성 변동 알림 을 구독 할 수 있 으 며 명령 에 연 결 된 리 셋 함 수 를 실행 하여 보 기 를 업데이트 할 수 있 습 니 다.
4.mvvm 의 입구,상기 3 자 통합
흐름 도 는 다음 과 같다.
분포 실현
1. MVVM.js
function MVVM(options) {
this.$options = options || {};
var data = this._data = this.$options.data;
var me = this;
//
// vm.xxx -> vm._data.xxx
Object.keys(data).forEach(function(key) {
me._proxyData(key);
});
//
// Object.defineProperty
this._initComputed();
observe(data, this);
this.$compile = new Compile(options.el || document.body, this)
}
MVVM.prototype = {
$watch: function(key, cb, options) {
new Watcher(this, key, cb);
}
}
MVVM 입구 파일,Observer/copile/Watcher 세 가 지 를 통합 하여 데이터 변화->보기 업데이트;보기 변화->데이터 변 경 된 양 방향 바 인 딩 효과(갈고리 함 수 를 결합 하여 Vue 생명주기 의 각 단계 의 작용 을 이해한다)2. Observer.js
function Observer(data) {
Object.keys(data).forEach(function() {
defineReactive(data, key, data[key]);
});
}
function defineReactive (data, key, val) {
var dep = new Dep();
var childObj = observe(val);
Object.defineProperty(data, key, {
enumerable: true, //
configurable: false, // define
get: function() {
if (Dep.target) {
dep.depend();
}
return val;
},
set: function(newVal) {
if (newVal === val) {
return;
}
val = newVal;
// object ,
childObj = observe(newVal);
//
dep.notify();
}
});
}
모니터링 이 필요 한 대상 의 모든 속성 을 재 귀적 으로 옮 겨 다 니 며 Object.defineProperty 를 통 해 setter 와 getter 를 설정 합 니 다.새로운 속성 값 을 설정 할 때 해당 setter 를 터치 하여 구독 자 에 게 알 립 니 다.
function Dep() {
this.id = uid++;
this.subs = [];
}
Dep.prototype = {
addSub: function(sub) {
this.subs.push(sub);
},
depend: function() {
Dep.target.addDep(this);
},
notify: function() {
this.subs.forEach(function(sub) {
sub.update();
});
}
};
구독 자 모드,각 속성 은 하나의 Dep 를 유지 하고 자신의 구독 자(즉 watcher)를 기록 하 며 notify 는 모든 구독 자 에 게 해당 하 는 update 방법 을 실행 하고 보 기 를 업데이트 하 라 고 알려 줍 니 다.3. Compile.js
Compile 은 두 가지 일 을 했다.
1.템 플 릿 명령 을 해석 하고 변 수 를 교체 하 며 렌 더 링 보 기 를 초기 화 합 니 다.
2.watcher 를 생 성하 고 리 셋 함 수 를 등록 하 며 감청 데 이 터 를 추가 하 는 구독 자,데이터 변동 시 보 기 를 업데이트 합 니 다.
분석 절 차 는 다음 과 같다.
1.DOM 을 문서 조각 fragment 로 변환 하여 조회 효율 향상
2.모든 요소 노드 와 하위 노드 를 옮 겨 다 니 며 해당 하 는 명령 렌 더 링 함수 렌 더 링 을 호출 하고 해당 하 는 명령 업데이트 함수 로 바 인 딩 합 니 다.
3.fragment 를 실제 DOM 에 추가
요소 옮 겨 다 니 기
function compileElement (el) {
var childNodes = el.childNodes,
me = this;
[].slice.call(childNodes).forEach(function(node) {
var text = node.textContent;
var reg = /\{\{(.*)\}\}/;
//
if (me.isElementNode(node)) {
me.compile(node);
// {{}}
} else if (me.isTextNode(node) && reg.test(text)) {
me.compileText(node, RegExp.$1);
}
//
if (node.childNodes && node.childNodes.length) {
me.compileElement(node);
}
});
}
컴 파일 요소 노드
compile: function(node) {
var nodeAttrs = node.attributes,
me = this;
[].slice.call(nodeAttrs).forEach(function(attr) {
// v-xxx
// <span v-html="content"></span>
var attrName = attr.name; // v-html
if (me.isDirective(attrName)) {
var exp = attr.value; // content
var dir = attrName.substring(2);
//
if (me.isEventDirective(dir)) {
compileUtil.eventHandler(node, me.$vm, exp, dir);
//
} else {
compileUtil[dir] && compileUtil[dir](node, me.$vm, exp);
}
node.removeAttribute(attrName);
}
});
}
명령 처리 및 업데이트 함수
var compileUtil = {
html: function(node, vm, exp) {
this.bind(node, vm, exp, 'html');
},
bind: function(node, vm, exp, dir) {
var updaterFn = updater[dir + 'Updater'];
//
updaterFn && updaterFn(node, this._getVMVal(vm, exp));
// Watcher,
new Watcher(vm, exp, function(value, oldValue) {
//
updaterFn && updaterFn(node, value, oldValue);
});
},
}
var Updater = {
htmlUpdater: function(node, value) {
node.innerHTML = typeof value == 'undefined' ? '' : value;
}
}
4. Watcher.jsWatcher 는 Observer 와 Compile 간 통신 의 다리 로 서 속성 변화 구독 자로 서 다음 과 같은 일 을 했 습 니 다.
1.자신 예화 시 속성 구독 기 집합 dep 에 자신 추가
2.자신 에 게 update 방법 이 필요 합 니 다.
3.dep.notice 를 호출 할 때 watcher 는 자신의 update 를 호출 하여 Compile 에서 정의 하 는 리 셋 을 실행 합 니 다.
function Watcher(vm, expOrFn, cb) {
this.cb = cb;
this.vm = vm;
this.expOrFn = expOrFn;
this.value = this.get();
}
Watcher.prototype = {
update: function() {
this.run();
},
run: function() {
var value = this.get();
var oldVal = this.value;
if (value !== oldVal) {
this.value = value;
this.cb.call(this.vm, value, oldVal);
}
},
get: function() {
Dep.target = this;
var value = this.getter.call(this.vm, this.vm);
Dep.target = null;
return value;
}
};
여기 서 주의해 야 할 점 은 워 치 를 예화 할 때 get 방법 을 호출 하고 Dep.target=curInstance 를 통 해 속성 값 을 얻 은 getter 방법 을 강제로 촉발 하여 속성의 구독 기 에 현재 워 치 인 스 턴 스 를 추가 하 는 것 입 니 다.작은 매듭
양 방향 바 인 딩 의 원 리 는 간단 합 니 다.데이터 납 치 를 통 해 새로운 속성 치 를 설정 할 때 구독 자 를 통 해 보 기 를 업데이트 합 니 다.명령 을 컴 파일 하고 변 수 를 교체 하 며 업데이트 함 수 를 구독 자 에 게 연결 합 니 다.이벤트 바 인 딩 에 대응 하여 addEventListener 를 호출 하여 감청 합 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Vue Render 함수로 DOM 노드 코드 인스턴스 만들기render에서createElement 함수를 사용하여 DOM 노드를 만드는 것은 직관적이지 않지만 일부 독립 구성 요소의 디자인에서 특수한 수요를 충족시킬 수 있습니다.간단한 렌더링 예는 다음과 같습니다. 또한 v...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.