fix(dom): correctly bind context for auto-created templates in / and optimize traversal
This commit is contained in:
parent
b8652c357e
commit
9d14dbe233
@ -1,5 +1,10 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## v1.0.12 (2026-05-25)
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
- **上下文绑定**: 修复了在对非 `template` 节点使用 `$if` 或 `$each` 指令时,框架自动创建 `<template>` 会过早转移未初始化的父级上下文,并在脱离 DOM 树后跳过深度扫描,导致 `this` 指向丢失为自身 DOM 节点的严重 Bug。同时优化了向上寻找上下文的遍历路径,避免了双重循环的性能开销。
|
||||||
|
|
||||||
## v1.0.11 (2026-05-21)
|
## v1.0.11 (2026-05-21)
|
||||||
|
|
||||||
### 核心优化
|
### 核心优化
|
||||||
|
|||||||
21
dist/state.js
vendored
21
dist/state.js
vendored
@ -470,6 +470,18 @@ const _scanTree = (node, scanObj = {}) => {
|
|||||||
});
|
});
|
||||||
node._stTranslated = true;
|
node._stTranslated = true;
|
||||||
}
|
}
|
||||||
|
let resolvedThisObj = node._thisObj;
|
||||||
|
let resolvedRef = node._ref;
|
||||||
|
if (resolvedThisObj === void 0 || resolvedRef === void 0) {
|
||||||
|
let curr = node;
|
||||||
|
while (curr && (resolvedThisObj === void 0 || resolvedRef === void 0)) {
|
||||||
|
if (resolvedThisObj === void 0 && curr._thisObj !== void 0) resolvedThisObj = curr._thisObj;
|
||||||
|
if (resolvedRef === void 0 && curr._ref !== void 0) resolvedRef = { ...curr._ref };
|
||||||
|
curr = curr.parentNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resolvedThisObj === void 0) resolvedThisObj = scanObj.thisObj;
|
||||||
|
if (resolvedRef === void 0) resolvedRef = scanObj.extendVars;
|
||||||
if (node.tagName !== "TEMPLATE" && (node.hasAttribute("$if") || node.hasAttribute("$each") || node.hasAttribute("st-if") || node.hasAttribute("st-each"))) {
|
if (node.tagName !== "TEMPLATE" && (node.hasAttribute("$if") || node.hasAttribute("$each") || node.hasAttribute("st-if") || node.hasAttribute("st-each"))) {
|
||||||
const template = document.createElement("TEMPLATE");
|
const template = document.createElement("TEMPLATE");
|
||||||
const attrs = Array.from(node.attributes).filter((attr) => ["$if", "$each", "st-if", "st-each"].includes(attr.name) || (node.hasAttribute("$each") || node.hasAttribute("st-each")) && ["as", "index"].includes(attr.name));
|
const attrs = Array.from(node.attributes).filter((attr) => ["$if", "$each", "st-if", "st-each"].includes(attr.name) || (node.hasAttribute("$each") || node.hasAttribute("st-each")) && ["as", "index"].includes(attr.name));
|
||||||
@ -479,7 +491,9 @@ const _scanTree = (node, scanObj = {}) => {
|
|||||||
});
|
});
|
||||||
node.parentNode.insertBefore(template, node);
|
node.parentNode.insertBefore(template, node);
|
||||||
template.content.appendChild(node);
|
template.content.appendChild(node);
|
||||||
template._ref = node._ref;
|
template._ref = resolvedRef;
|
||||||
|
template._thisObj = resolvedThisObj;
|
||||||
|
_scanTree(template, scanObj);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (node.tagName === "TEMPLATE" && (node.hasAttribute("$if") || node.hasAttribute("st-if")) && (node.hasAttribute("$each") || node.hasAttribute("st-each"))) {
|
if (node.tagName === "TEMPLATE" && (node.hasAttribute("$if") || node.hasAttribute("st-if")) && (node.hasAttribute("$each") || node.hasAttribute("st-each"))) {
|
||||||
@ -496,7 +510,8 @@ const _scanTree = (node, scanObj = {}) => {
|
|||||||
}
|
}
|
||||||
Array.from(node.content.childNodes).forEach((child) => template.content.appendChild(child));
|
Array.from(node.content.childNodes).forEach((child) => template.content.appendChild(child));
|
||||||
node.content.appendChild(template);
|
node.content.appendChild(template);
|
||||||
template._ref = node._ref;
|
template._ref = resolvedRef;
|
||||||
|
template._thisObj = resolvedThisObj;
|
||||||
}
|
}
|
||||||
if (node.tagName === "IMG" && (node.hasAttribute("src") || node.hasAttribute("_src") || node.hasAttribute("$src"))) {
|
if (node.tagName === "IMG" && (node.hasAttribute("src") || node.hasAttribute("_src") || node.hasAttribute("$src"))) {
|
||||||
const imgNode = node;
|
const imgNode = node;
|
||||||
@ -526,7 +541,7 @@ const _scanTree = (node, scanObj = {}) => {
|
|||||||
Object.assign(node._ref, node._refExt);
|
Object.assign(node._ref, node._refExt);
|
||||||
}
|
}
|
||||||
if (scanObj.extendVars) Object.assign(node._ref, scanObj.extendVars);
|
if (scanObj.extendVars) Object.assign(node._ref, scanObj.extendVars);
|
||||||
_parseNode(node, scanObj);
|
_parseNode(node, { ...scanObj });
|
||||||
const nodes = [...node.childNodes || []];
|
const nodes = [...node.childNodes || []];
|
||||||
const nextScanObj = { thisObj: scanObj.thisObj, extendVars: { ...node._ref } };
|
const nextScanObj = { thisObj: scanObj.thisObj, extendVars: { ...node._ref } };
|
||||||
nodes.forEach((child) => {
|
nodes.forEach((child) => {
|
||||||
|
|||||||
2
dist/state.min.js
vendored
2
dist/state.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@web/state",
|
"name": "@web/state",
|
||||||
"version": "1.0.10",
|
"version": "1.0.12",
|
||||||
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/state.js",
|
"main": "dist/state.js",
|
||||||
"module": "dist/state.js",
|
"module": "dist/state.js",
|
||||||
|
|||||||
24
src/dom.js
24
src/dom.js
@ -309,13 +309,30 @@ export const _scanTree = (node, scanObj = {}) => {
|
|||||||
node._stTranslated = true;
|
node._stTranslated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let resolvedThisObj = node._thisObj;
|
||||||
|
let resolvedRef = node._ref;
|
||||||
|
|
||||||
|
if (resolvedThisObj === undefined || resolvedRef === undefined) {
|
||||||
|
let curr = node;
|
||||||
|
while (curr && (resolvedThisObj === undefined || resolvedRef === undefined)) {
|
||||||
|
if (resolvedThisObj === undefined && curr._thisObj !== undefined) resolvedThisObj = curr._thisObj;
|
||||||
|
if (resolvedRef === undefined && curr._ref !== undefined) resolvedRef = { ...curr._ref };
|
||||||
|
curr = curr.parentNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolvedThisObj === undefined) resolvedThisObj = scanObj.thisObj;
|
||||||
|
if (resolvedRef === undefined) resolvedRef = scanObj.extendVars;
|
||||||
|
|
||||||
if (node.tagName !== 'TEMPLATE' && (node.hasAttribute('$if') || node.hasAttribute('$each') || node.hasAttribute('st-if') || node.hasAttribute('st-each'))) {
|
if (node.tagName !== 'TEMPLATE' && (node.hasAttribute('$if') || node.hasAttribute('$each') || node.hasAttribute('st-if') || node.hasAttribute('st-each'))) {
|
||||||
const template = document.createElement('TEMPLATE');
|
const template = document.createElement('TEMPLATE');
|
||||||
const attrs = Array.from(node.attributes).filter(attr => ['$if', '$each', 'st-if', 'st-each'].includes(attr.name) || ((node.hasAttribute('$each') || node.hasAttribute('st-each')) && ['as', 'index'].includes(attr.name)));
|
const attrs = Array.from(node.attributes).filter(attr => ['$if', '$each', 'st-if', 'st-each'].includes(attr.name) || ((node.hasAttribute('$each') || node.hasAttribute('st-each')) && ['as', 'index'].includes(attr.name)));
|
||||||
attrs.forEach(attr => { template.setAttribute(attr.name, attr.value); node.removeAttribute(attr.name); });
|
attrs.forEach(attr => { template.setAttribute(attr.name, attr.value); node.removeAttribute(attr.name); });
|
||||||
node.parentNode.insertBefore(template, node);
|
node.parentNode.insertBefore(template, node);
|
||||||
template.content.appendChild(node);
|
template.content.appendChild(node);
|
||||||
template._ref = node._ref;
|
template._ref = resolvedRef;
|
||||||
|
template._thisObj = resolvedThisObj; // Crucial fix: Propagate context
|
||||||
|
_scanTree(template, scanObj);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (node.tagName === 'TEMPLATE' && (node.hasAttribute('$if') || node.hasAttribute('st-if')) && (node.hasAttribute('$each') || node.hasAttribute('st-each'))) {
|
if (node.tagName === 'TEMPLATE' && (node.hasAttribute('$if') || node.hasAttribute('st-if')) && (node.hasAttribute('$each') || node.hasAttribute('st-each'))) {
|
||||||
@ -329,7 +346,8 @@ export const _scanTree = (node, scanObj = {}) => {
|
|||||||
}
|
}
|
||||||
Array.from(node.content.childNodes).forEach(child => template.content.appendChild(child));
|
Array.from(node.content.childNodes).forEach(child => template.content.appendChild(child));
|
||||||
node.content.appendChild(template);
|
node.content.appendChild(template);
|
||||||
template._ref = node._ref;
|
template._ref = resolvedRef;
|
||||||
|
template._thisObj = resolvedThisObj; // Crucial fix: Propagate context
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.tagName === 'IMG' && (node.hasAttribute('src') || node.hasAttribute('_src') || node.hasAttribute('$src'))) {
|
if (node.tagName === 'IMG' && (node.hasAttribute('src') || node.hasAttribute('_src') || node.hasAttribute('$src'))) {
|
||||||
@ -362,7 +380,7 @@ export const _scanTree = (node, scanObj = {}) => {
|
|||||||
}
|
}
|
||||||
if (scanObj.extendVars) Object.assign(node._ref, scanObj.extendVars);
|
if (scanObj.extendVars) Object.assign(node._ref, scanObj.extendVars);
|
||||||
|
|
||||||
_parseNode(node, scanObj);
|
_parseNode(node, { ...scanObj });
|
||||||
|
|
||||||
const nodes = [...(node.childNodes || [])];
|
const nodes = [...(node.childNodes || [])];
|
||||||
const nextScanObj = { thisObj: scanObj.thisObj, extendVars: { ...node._ref } };
|
const nextScanObj = { thisObj: scanObj.thisObj, extendVars: { ...node._ref } };
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user