Vue.js 소스 코드 분석의 사용자 정의 명령 상세 설명
핵심 기능 인 기본 내 장 된 명령(v-model 과 v-show)을 제외 하고 Vue 도 사용자 정의 명령 을 등록 할 수 있 습 니 다.
홈 페이지 에 소 개 된 추상 적 이 고 커 보 입 니 다.저 는 개인 적 으로 사용자 정의 명령 에 대한 이 해 를 가지 고 있 습 니 다.사용자 정의 명령 이 일부 DOM 요소 나 구성 요소 에 작용 할 때 이 요 소 는 첫 번 째 렌 더 링,부모 노드 에 삽입,업데이트,풀 때 특정한 작업 을 수행 할 수 있 습 니 다(갈고리 함수().
사용자 정의 명령 은 두 가지 등록 방식 이 있 습 니 다.하 나 는 전역 등록 입 니 다.Vue.directive(명령 명,설정 매개 변수)를 사용 하여 등록 합 니 다.등록 후 모든 Vue 인 스 턴 스 를 사용 할 수 있 습 니 다.다른 하 나 는 부분 등록 입 니 다.Vue 인 스 턴 스 를 만 들 때 directives 속성 을 통 해 부분 지 시 를 만 듭 니 다.부분 사용자 정의 명령 은 현재 Vue 인 스 턴 스 에서 만 사용 할 수 있 습 니 다.
사용자 정의 명령 은 다음 갈고리 함 수 를 연결 할 수 있 습 니 다.
・bind ;한 번 만 호출 합 니 다.요소 가 DOM 노드 로 렌 더 링 된 후 directives 모듈 의 초기 화 작업 을 수행 할 때 호출 합 니 다.여기 서 한꺼번에 초기 화 설정 을 할 수 있 습 니 다.
・inserted ;바 인 딩 요소 가 부모 노드 에 삽 입 될 때 호출 합 니 다.(부모 노드 만 존재 하지만 문서 에 삽 입 된 것 은 아 닙 니 다.)
・update ;구성 요소 의 VNode 업데이트 시 호출 되 지만 하위 VNode 업데이트 전에 발생 할 수 있 습 니 다.명령 의 값 이 바 뀌 었 을 수도 있 고 없 을 수도 있 습 니 다.
・componentUpdated ;명령 이 있 는 구성 요소 의 VNode 와 하위 VNode 를 모두 업데이트 해서 호출 합 니 다.
・unbind ;한 번 만 호출 하고 명령 과 요 소 를 풀 때 호출 합 니 다.
각 갈고리 함 수 는 엘(대응 하 는 DOM 노드 참조),binding(명령 에 대한 확장 정보,대상),vnode(이 노드 에 대응 하 는 가상 VN 오),oldVnode(이전 VNode,update 와 componentUpdated 갈고리 에서 만 사용 가능)등 네 개의 매개 변 수 를 가 질 수 있 습 니 다.
bid 갈고리 함수 가 실 행 될 때 이 DOM 요 소 는 렌 더 링 되 었 으 나 부모 요소 에 삽입 되 지 않 았 습 니 다.예 를 들 어:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="vue.js"></script>
</head>
<body>
<div id="d"><input type="" name="" v-focus></div>
<script>
Vue.directive('focus', {
bind:function(el){console.log(el.parentElement);}, //
inserted: function (el) {console.log(el.parentElement);el.focus()} // ,
})
var app = new Vue({el:"#d"})
</script>
</body>
</html>
출력 은 다음 과 같 습 니 다:input 요소 가 자동 으로 초점 을 얻 는 것 을 볼 수 있 습 니 다.콘 솔 출력 은 다음 과 같 습 니 다.
bid()갈고리 에 있어 서 부모 노드 는 가 져 올 수 없습니다.Vue 내부 에서 bid()갈 고 리 를 실행 한 후에 야 현재 요 소 를 부모 요소 의 하위 노드 에 삽입 할 수 있 기 때 문 입 니 다.
소스 코드 분석
템 플 릿 을 분석 하여 DOM 을 AST 대상 으로 변환 할 때 processAtts()함 수 를 실행 합 니 다.다음 과 같 습 니 다.
function processAttrs (el) { // Vue
var list = el.attrsList;
var i, l, name, rawName, value, modifiers, isProp;
for (i = 0, l = list.length; i < l; i++) { //
name = rawName = list[i].name;
value = list[i].value;
if (dirRE.test(name)) { // v-、@ : , Vue
// mark element as dynamic
el.hasBindings = true;
// modifiers
modifiers = parseModifiers(name);
if (modifiers) {
name = name.replace(modifierRE, '');
}
if (bindRE.test(name)) { // v-bind //bindRD /^:|^v-bind:/ , v-bind
/*v-bind */
} else if (onRE.test(name)) { // v-on
/*v-on */
} else { // normal directives
name = name.replace(dirRE, ''); // , v-show show
// parse arg
var argMatch = name.match(argRE);
var arg = argMatch && argMatch[1];
if (arg) {
name = name.slice(0, -(arg.length + 1));
}
addDirective(el, name, rawName, value, arg, modifiers); // addDirective el directives
if ("development" !== 'production' && name === 'model') {
checkForAliasModel(el, value);
}
}
} else {
/* Vue */
}
}
}
addDirective 는 AST 대상 에 directives 속성 을 추가 하여 명령 정 보 를 저장 합 니 다.다음 과 같 습 니 다.
function addDirective ( // 6561 , el AST directives ,
el,
name,
rawName,
value,
arg,
modifiers
) {
(el.directives || (el.directives = [])).push({ name: name, rawName: rawName, value: value, arg: arg, modifiers: modifiers });
el.plain = false;
}
예 에서 p 요소 가 여기에 실 행 될 때 대응 하 는 AST 대상 은 다음 과 같 습 니 다.다음은 generate 에서 rendre 함 수 를 생 성 할 때 genDirectives()함 수 를 실행 하여 AST 를 render 함수 로 변환 합 니 다.다음 과 같 습 니 다.
with(this){return _c('div',{attrs:{"id":"d"}},[_c('input',{directives:[{name:"focus",rawName:"v-focus"}],attrs:{"type":"","name":""}})])}
마지막 으로 렌 더 링 이 완료 되면 directives 모듈 의 create 갈고리 함 수 를 실행 합 니 다.다음 과 같 습 니 다.
var directives = { // 6173 directives
create: updateDirectives, // DOM
update: updateDirectives,
destroy: function unbindDirectives (vnode) {
updateDirectives(vnode, emptyNode);
}
}
function updateDirectives (oldVnode, vnode) { // 6181 oldVnode: Vnode, vnode: VNode
if (oldVnode.data.directives || vnode.data.directives) {
_update(oldVnode, vnode);
}
}
_update 는 명령 을 초기 화하 고 업데이트 하 는 것 입 니 다.다음 과 같 습 니 다.
function _update (oldVnode, vnode) { // 6187 /
var isCreate = oldVnode === emptyNode; //
var isDestroy = vnode === emptyNode;
var oldDirs = normalizeDirectives$1(oldVnode.data.directives, oldVnode.context);
var newDirs = normalizeDirectives$1(vnode.data.directives, vnode.context); // normalizeDirectives$1()
var dirsWithInsert = [];
var dirsWithPostpatch = [];
var key, oldDir, dir;
for (key in newDirs) { // newDirs
oldDir = oldDirs[key]; //oldVnode key
dir = newDirs[key]; //vnode key
if (!oldDir) { // oldDir ,
// new directive, bind
callHook$1(dir, 'bind', vnode, oldVnode); // callHook$1() , 2 bind, v-focus bind
if (dir.def && dir.def.inserted) { // inserted
dirsWithInsert.push(dir); // dirsWithInsert
}
} else {
// existing directive, update
dir.oldValue = oldDir.value;
callHook$1(dir, 'update', vnode, oldVnode);
if (dir.def && dir.def.componentUpdated) {
dirsWithPostpatch.push(dir);
}
}
}
if (dirsWithInsert.length) { // dirsWithInsert ( inserted )
var callInsert = function () { // callInsert , dirsWithInsert
for (var i = 0; i < dirsWithInsert.length; i++) {
callHook$1(dirsWithInsert[i], 'inserted', vnode, oldVnode);
}
};
if (isCreate) { //
mergeVNodeHook(vnode, 'insert', callInsert); // mergeVNodeHook()
} else {
callInsert();
}
}
if (dirsWithPostpatch.length) {
mergeVNodeHook(vnode, 'postpatch', function () {
for (var i = 0; i < dirsWithPostpatch.length; i++) {
callHook$1(dirsWithPostpatch[i], 'componentUpdated', vnode, oldVnode);
}
});
}
if (!isCreate) {
for (key in oldDirs) {
if (!newDirs[key]) {
// no longer present, unbind
callHook$1(oldDirs[key], 'unbind', oldVnode, oldVnode, isDestroy);
}
}
}
}
저자:대사 막 QQ:29269969bind 갈고리 함수 에 있어 서 는 직접 실 행 됩 니 다.inserted 갈고리 함수 에 대해 서 는 함 수 를 dirs Withinert 배열 에 저장 하고 callInsert 함 수 를 정의 합 니 다.이 함수 내 부 는 역할 영역 을 통 해 dirs Withinert 변 수 를 방문 하고 이 변 수 를 옮 겨 다 니 며 각 inserted 갈고리 함 수 를 순서대로 실행 합 니 다.
mergeVNodeHook()갈고리 함수 의 역할 은 insert 를 하나의 hooks 속성 으로 대응 하 는 Vnode 의 data 에 저장 하 는 것 입 니 다.이 Vnode 가 부모 노드 에 삽입 되면 이 hooks 를 호출 합 니 다.다음 과 같 습 니 다.
function mergeVNodeHook (def, hookKey, hook) { // 2074 VNode def: VNode hookKey:( , :insert) hook:
if (def instanceof VNode) { // def VNode
def = def.data.hook || (def.data.hook = {}); // VNode.data.hook, VNode.data.hook : VNode.data.hook 。
}
var invoker;
var oldHook = def[hookKey];
function wrappedHook () {
hook.apply(this, arguments); // hook
// important: remove merged hook to ensure it's called only once
// and prevent memory leak
remove(invoker.fns, wrappedHook); // wrappedHook invoker.fns remove ,
}
if (isUndef(oldHook)) { // oldHook , hookKey
// no existing hook
invoker = createFnInvoker([wrappedHook]); // createFnInvoker() ,
} else {
/* istanbul ignore if */
if (isDef(oldHook.fns) && isTrue(oldHook.merged)) {
// already a merged invoker
invoker = oldHook;
invoker.fns.push(wrappedHook);
} else {
// existing plain hook
invoker = createFnInvoker([oldHook, wrappedHook]);
}
}
invoker.merged = true;
def[hookKey] = invoker; // def hookKey invoker
}
createFnInvoker 는 v-on 명령 에 대응 하 는 그 함수 입 니 다.같은 API 를 사 용 했 습 니 다.실행 이 끝 난 후에 invoker 를 input 에 대응 하 는 VNode.data.hook 에 삽입 합 니 다.다음 과 같 습 니 다.마지막 으로 이 VNode 가 부모 노드 에 삽입 되면 invokeCreate Hooks()함 수 를 실행 합 니 다.이 함 수 는 VNode.hook.insert 를 옮 겨 다 니 며 각 함 수 를 순서대로 실행 합 니 다.또한 우리 가 정의 한 inserted 갈고리 함수 도 실 행 됩 니 다.
총결산
Vue.js 소스 코드 분석 에 관 한 사용자 정의 명령 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 Vue.js 사용자 정의 명령 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Vue.js + Google Places: 여러 입력 필드 자동 완성경우에 따라 두 개 이상의 입력 필드에 장소 자동 완성 기능을 추가할 수 있습니다. 일반적인 예는 두 위치 사이의 이동 거리를 찾는 것입니다. 이 경우 사용자는 자동 완성 기능이 활성화된 두 개의 입력 필드를 갖게 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.