fix(state): 修复 Select 绑定时序(by AI)

This commit is contained in:
Star 2026-07-13 21:46:53 +08:00
parent ea96c4ef22
commit ad2a60e745
5 changed files with 21 additions and 4 deletions

View File

@ -1,5 +1,10 @@
# CHANGELOG
## v1.0.25 (2026-07-13)
### 修复
- **Select 双向绑定时序**: 延后绑定值回写,确保模板动态生成选项时保留状态中的目标值,而非被浏览器默认选项覆盖。
## v1.0.23 (2026-07-06)
### 修复

2
dist/state.js vendored
View File

@ -451,7 +451,7 @@
} else if (node.type === "radio") {
if (node.checked !== (node.value === String(result ?? ""))) node.checked = node.value === String(result ?? "");
} else if ("value" in node && node.type !== "file") {
Promise.resolve().then(() => {
setTimeout(() => {
if (node.value !== String(result ?? "")) node.value = result;
});
} else if (node.isContentEditable) {

2
dist/state.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -280,7 +280,10 @@ export function _updateBinding(binding) {
} else if (node.type === 'radio') {
if (node.checked !== (node.value === String(result ?? ''))) node.checked = (node.value === String(result ?? ''));
} else if ('value' in node && node.type !== 'file') {
Promise.resolve().then(() => { if (node.value !== String(result ?? '')) node.value = result; });
// A select may receive its bound value before template-rendered
// options exist. Run after the current render turn so adding options
// cannot replace the model value with the browser's default option.
setTimeout(() => { if (node.value !== String(result ?? '')) node.value = result; });
} else if (node.isContentEditable) {
if (node.innerHTML !== String(result ?? '')) node.innerHTML = result;
}

View File

@ -62,7 +62,16 @@ window.testDom = async function() {
input.dispatchEvent(new Event('input'));
if (state.val !== '') throw new Error('$bind must preserve an empty text value');
// 6. Double evaluation ($$ prefix)
// 6. A select bound before its template-rendered options must retain the
// model value instead of writing the browser-selected default back.
document.body.innerHTML = '<select id="test-select" $bind="state.selected"><template $each="state.options"><option $text="item" $value="item"></option></template></select>';
state.selected = 'second';
state.options = ['first', 'second'];
__unsafeRefreshState(document.documentElement);
await wait();
if ($('#test-select').value !== 'second' || state.selected !== 'second') throw new Error('$bind select must retain its value after rendering options');
// 7. Double evaluation ($$ prefix)
console.log('Testing double evaluation ($$)...');
document.body.innerHTML = `
<div id="double-eval-root">