vue 페이지 업데이트 패 치 구현 예제
구성 요소 페이지 렌 더 링 시 render 가 되 돌아 오 는 새 vnode(새 노드)와 구성 요소 인 스 턴 스 가 저 장 된 vnode(옛 노드)를 매개 변수 로 하여 patch 방법 을 호출 하여 DOM 을 업데이트 합 니 다.
두 노드 가 같 는 지 판단 하 다.
처리 과정 에서 노드 가 같 는 지 판단 해 야 한다.같은 노드 는 다음 과 같은 조건 을 만족 시 켜 야 한다.
function sameVnode (a, b) {// VNode
return (
a.key === b.key && // key
(
a.tag === b.tag && // tag
a.isComment === b.isComment && //
isDef(a.data) === isDef(b.data) && // data
sameInputType(a, b) // input type
)
)
}
patch 방법patch 판단 절 차 는 다음 과 같 습 니 다.
a)새 노드 가 비어 있 으 면 오래된 노드 가 존재 합 니 다(구성 요소 가 삭 제 될 때).오래된 노드 destroy 생명주기 함 수 를 호출 합 니 다.
b)오래된 노드 가 비어 있 으 면 새 노드 에 따라 DOM 을 만 듭 니 다.
c)기타(신 구 노드 가 모두 존재 한다 면)
function patch (oldVnode, vnode, hydrating, removeOnly) {
if (isUndef(vnode)) {
if (isDef(oldVnode)) { invokeDestroyHook(oldVnode); }
return
}
...
if (isUndef(oldVnode)) {
isInitialPatch = true;//
createElm(vnode, insertedVnodeQueue);
} else {
var isRealElement = isDef(oldVnode.nodeType);
if (!isRealElement && sameVnode(oldVnode, vnode)) {
patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null, removeOnly);
} else {
...
var oldElm = oldVnode.elm;
var parentElm = nodeOps.parentNode(oldElm);//
// create new node
createElm(
vnode,
insertedVnodeQueue,
oldElm._leaveCb ? null : parentElm,
nodeOps.nextSibling(oldElm)//
);
if (isDef(parentElm)) {
removeVnodes(parentElm, [oldVnode], 0, 0);// DOM
} else if (isDef(oldVnode.tag)) {
invokeDestroyHook(oldVnode);
}
}
}
invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch);
return vnode.elm
}
}
patchVnode 방법두 노드 가 동시에 patchVnode 방법 을 실행 합 니 다.각종 상황 을 처리 하기 전에 낡은 노드 의 elm 속성 값 을 새 노드 의 elm 속성 에 부여 하고 elm 를 일치 하 게 유지 합 니 다.
구체 적 인 절 차 는 다음 과 같다.
a)신 구 노드 가 완전히 같다 면(같은 oldVnode==vnode 참조)
function patchVnode (
oldVnode,
vnode,
insertedVnodeQueue,
ownerArray,
index,
removeOnly
) {
if (oldVnode === vnode) {
return
}
...
if (isUndef(vnode.text)) {
if (isDef(oldCh) && isDef(ch)) {
if (oldCh !== ch) { updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly); }
} else if (isDef(ch)) {
if (process.env.NODE_ENV !== 'production') {
checkDuplicateKeys(ch);
}
if (isDef(oldVnode.text)) { nodeOps.setTextContent(elm, ''); }
addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
} else if (isDef(oldCh)) {
removeVnodes(elm, oldCh, 0, oldCh.length - 1);
} else if (isDef(oldVnode.text)) {
nodeOps.setTextContent(elm, '');
}
} else if (oldVnode.text !== vnode.text) {
nodeOps.setTextContent(elm, vnode.text);
}
...
}
updateChildren 방법updateChildren 방법 은 같은 신 구 노드 의 하위 노드 를 처리 합 니 다.방법 은 다음 변 수 를 정의 합 니 다(updateChildren 의 노드 는 모두 하위 노드 를 표시 합 니 다).
var oldStartIdx = 0;//
var newStartIdx = 0;//
var oldEndIdx = oldCh.length - 1;//
var oldStartVnode = oldCh[0];//
var oldEndVnode = oldCh[oldEndIdx];//
var newEndIdx = newCh.length - 1;//
var newStartVnode = newCh[0];//
var newEndVnode = newCh[newEndIdx];//
var oldKeyToIdx, // key
idxInOld, // key
vnodeToMove, // key
refElm;// ( ) DOM
신 구 노드 의 비교 결과 에 따라 DOM 요 소 를 업데이트 합 니 다.이 과정 은 신 구 노드 의 순 서 를 바 꾸 지 않 습 니 다.번 호 는 처리 중인 노드 를 가리 키 는데 각각 신 구 노드 의 시작 과 끝 노드 이다.대비 과정 은 새로운 시작 노드 를 주도 로 하고 대비 방향 은 양측 에서 중간 으로 한다.우선 신 구 노드 의 시작 노드 와 끝 노드 를 비교 하고 새로운 시작 노드 와 같 고 처리 되 지 않 은 구 노드 를 찾 습 니 다.오래된 노드 가 모두 처리 되 었 을 때(오래된 시작 과 끝 번호 가 겹 친다)새 노드 가 처리 되 지 않 았 을 때 새 노드 DOM 요 소 를 추가 할 수 있 습 니 다.새 노드 가 모두 처 리 될 때(새 시작 과 끝 번호 가 겹 칠 때)오래된 노드 가 존재 할 수 있 으 면 오래된 노드 DOM 요 소 를 삭제 합 니 다.구체 적 인 절 차 는 다음 과 같다.
신 구 서브 노드 의 시작 번호 가 끝 번호 보다 크 지 않 을 때 다음 절 차 를 실행 합 니 다.
a)오래된 하위 노드 양쪽 에 노드 가 존재 한다 면
undefined
노드undefined
,oldStartVnode = oldCh[++oldStartIdx]
undefined
,oldEndVnode = oldCh[--oldEndIdx]
patchVNode
DOM 콘 텐 츠 업데이트oldStartVnode = oldCh[++oldStartIdx]
newStartVnode = newCh[++newStartIdx]
patchVNode
DOM 콘 텐 츠 업데이트oldEndVnode = oldCh[--oldEndIdx]
newEndVnode = newCh[--newEndIdx]
patchVNode
DOM 콘 텐 츠 업데이트oldStartVnode = oldCh[++oldStartIdx]
newEndVnode = newCh[--newEndIdx]
patchVNode
DOM 콘 텐 츠 업데이트oldEndVnode = oldCh[--oldEndIdx]
newStartVnode = newCh[++newStartIdx]
newStartVnode = newCh[++newStartIdx]
patchVode
oldCh[idxInOld] = undefined
newStartVnode = newCh[++newStartIdx]
newStartVnode = newCh[++newStartIdx]
a)오래된 노드 가 다 옮 겨 다 니 면
oldStartIdx > oldEndIdx
newStartIdx > newEndIdx
function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
var oldStartIdx = 0;//
var newStartIdx = 0;//
var oldEndIdx = oldCh.length - 1;//
var oldStartVnode = oldCh[0];//
var oldEndVnode = oldCh[oldEndIdx];//
var newEndIdx = newCh.length - 1;//
var newStartVnode = newCh[0];//
var newEndVnode = newCh[newEndIdx];//
var oldKeyToIdx, idxInOld, vnodeToMove, refElm;
...
while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
if (isUndef(oldStartVnode)) {
oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left
} else if (isUndef(oldEndVnode)) {
oldEndVnode = oldCh[--oldEndIdx];
} else if (sameVnode(oldStartVnode, newStartVnode)) {
patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);
oldStartVnode = oldCh[++oldStartIdx];
newStartVnode = newCh[++newStartIdx];
} else if (sameVnode(oldEndVnode, newEndVnode)) {
patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx);
oldEndVnode = oldCh[--oldEndIdx];
newEndVnode = newCh[--newEndIdx];
} else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx);
canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm));
oldStartVnode = oldCh[++oldStartIdx];
newEndVnode = newCh[--newEndIdx];
} else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);
canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
oldEndVnode = oldCh[--oldEndIdx];
newStartVnode = newCh[++newStartIdx];
} else {
if (isUndef(oldKeyToIdx)) { oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx); }// key
idxInOld = isDef(newStartVnode.key)
? oldKeyToIdx[newStartVnode.key]
: findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx);
if (isUndef(idxInOld)) { // New element
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);
} else {
vnodeToMove = oldCh[idxInOld];
if (sameVnode(vnodeToMove, newStartVnode)) {
patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);
oldCh[idxInOld] = undefined;
canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm);
} else {
// same key but different element. treat as new element
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);
}
}
newStartVnode = newCh[++newStartIdx];
}
}
if (oldStartIdx > oldEndIdx) {
refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm;
addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
} else if (newStartIdx > newEndIdx) {
removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
}
}
updateChildren 의 예제:1.왼쪽 은 신 구 노드 를 나타 내 고 노드 아래 에 표지 의 시작 과 끝 노드(즉 처리 중인 노드)를 나타 낸다.오른쪽 은 현재 DOM 을 표시 합 니 다.
2.새로운 노드 의 시작 과 끝 노드 는 구 노드 의 시작 과 끝 노드 가 서로 다 르 고 구 노드 에서 새로운 시작 노드(새 노드 f)와 같은 노드 를 찾 지 못 한다.
그래서 노드 f 의 DOM 을 만 들 고 오래된 시작 노드(오래된 노드 a)DOM 앞 에 추가 한 다음 에 새로운 시작 노드 번호 에 1 을 추가 하면 새로운 노드 f 가 처리 되 었 음 을 나타 내 고 현재 새로운 시작 노드 c 를 처리 하고 있 습 니 다.
3.새로운 노드 의 시작 과 끝 노드 는 구 노드 의 시작 과 끝 노드 와 서로 다 르 지만 구 노드 에서 새로운 시작 노드(노드 c)와 같은 노드 를 찾 습 니 다.
그래서 구 노드 c 의 DOM 을 구 시작 노드(구 노드 a)DOM 앞 에 추가 하고 구 노드 c 를 비 운 다음 에 새로운 시작 노드 번호 에 1 을 추가 하면 새 노드 c 가 처리 되 었 고 현재 새로운 시작 노드 e 를 처리 하고 있 음 을 나타 낸다.
4.새 시작 노드(새 노드 e)는 옛 끝 노드(옛 노드 e)와 같다.구 노드 e 의 DOM 내용 을 업데이트 하고 구 노드 e 의 DOM 을 구 시작 노드(구 노드 a)DOM 앞으로 이동 합 니 다.구 끝 노드 번 호 는 1 을 줄 이 고 새로운 시작 노드 는 1 을 더 하면 신 구 노드 e 가 처리 되 었 음 을 나타 냅 니 다.현재 처리 하고 있 는 것 은 새로운 시작 노드 g 와 구 끝 노드 d 입 니 다.
5.새 엔 딩 노드(새 노드 d)는 구 엔 딩 노드(구 노드 d)와 같다.오래된 노드 d 의 DOM 내용 만 업데이트 합 니 다.새로운 엔 딩 노드 의 번호 가 1 을 줄 이 고 낡은 엔 딩 노드 의 번호 가 1 을 줄 이 는 것 은 신 구 노드 d 가 처리 되 었 음 을 나타 낸다.현재 처리 하고 있 는 것 은 새로운 엔 딩 노드 g 와 낡은 엔 딩 노드 c 이다.낡은 노드 c 가 비어 있 기 때문에 낡은 끝 노드 는 b 이다.
6.새로운 노드 의 시작 과 끝 노드 는 구 노드 의 시작 과 끝 노드 가 서로 다 르 고 구 노드 에서 새로운 시작 노드(새 노드 g)와 같은 노드 를 찾 지 못 했다.
그래서 노드 g 의 DOM 을 만 들 고 오래된 시작 노드(오래된 노드 a)DOM 앞 에 추가 한 다음 에 새로운 시작 노드 번호 에 1 을 추가 하면 새로운 노드 g 가 처리 되 었 음 을 나타 내 고 현재 새로운 시작 노드 d 를 처리 하고 있 습 니 다.
7.새로운 시작 과 끝 노드 의 번호 가 겹 치기 때문에 새 노드 가 처리 되 었 고 처리 되 지 않 은 오래된 노드 가 존재 하면 처리 되 지 않 은 오래된 노드 DOM 을 제거 합 니 다.
8.끝,최종 DOM.
vue 페이지 업데이트 패 치 의 실현 예제 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 vue 업데이트 패 치 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Fastapi websocket 및 vue 3(Composition API)1부: FastAPI virtualenv 만들기(선택 사항) FastAPI 및 필요한 모든 것을 다음과 같이 설치하십시오. 생성main.py 파일 및 실행 - 브라우저에서 이 링크 열기http://127.0.0.1:...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.