修复所有 Alpine 组件表达式报错

彻底移除 Proxy/has 陷阱方案,改用显式方法存根:
- userCardComponent 补充 35 个方法存根
- marriage-modals 8 个组件改用 createLazyAlpineComponent
- weddingSetup/weddingEnvelope 等 Modal 均正确包装
控制台现在应该没有任何 Alpine Expression Error
This commit is contained in:
pllx
2026-04-28 09:42:18 +08:00
parent e50502d8f6
commit 1c067e452b
2 changed files with 80 additions and 44 deletions
+3 -35
View File
@@ -101,13 +101,11 @@ export function createLazyAlpineComponent(importFn, exportName, defaults = {}, w
const proxy = this;
let loaded = false;
// 使用 Alpine 的 $watch 监听显示状态变化
// 仅在组件变为可见时才加载真实模块
if (
watchKey in proxy &&
typeof proxy.$watch === "function"
) {
proxy.$watch(watchKey, (value, oldValue) => {
proxy.$watch(watchKey, (value) => {
if (value && !loaded) {
loaded = true;
importFn()
@@ -118,21 +116,18 @@ export function createLazyAlpineComponent(importFn, exportName, defaults = {}, w
? componentFn(...args)
: componentFn;
// 通过 Alpine 响应式代理写入所有属性
Object.keys(realData).forEach((key) => {
if (key !== "init") {
proxy[key] = realData[key];
}
});
// 处理继承属性
for (const key in realData) {
if (!(key in proxy)) {
proxy[key] = realData[key];
}
}
// 调用真实组件的 init(如果存在)
if (
typeof proxy.init === "function" &&
proxy.init !== stub.init
@@ -145,7 +140,7 @@ export function createLazyAlpineComponent(importFn, exportName, defaults = {}, w
`[懒加载] Alpine 组件 "${exportName}" 加载失败:`,
err,
);
loaded = false; // 允许重试
loaded = false;
});
}
});
@@ -153,33 +148,6 @@ export function createLazyAlpineComponent(importFn, exportName, defaults = {}, w
},
};
// 使用 Proxy 包裹 stub,对任何未在 defaults 中定义的属性/方法提供安全兜底
// 这样组件模板中的所有表达式(方法调用、属性访问)都不会抛出 "not defined" 错误
return new Proxy(stub, {
get(target, prop, receiver) {
// 已存在的属性直接返回
if (prop in target) {
return Reflect.get(target, prop, receiver);
}
// 对于未定义的属性/方法,返回一个安全的、支持调用的兜底值
// - 作为值访问(如 targetMarriage?.status: 返回 '',保证 .status 不报错
// - 作为方法调用(如 displayAssetValue('exp_num'): 返回空字符串
const fallback = () => "";
return fallback;
},
// Alpine 使用 with(scope) 求值表达式,with 用 has (in 操作符) 判断属性是否存在
// 如果没有 has 陷阱,with 认为属性不存在 → 跳到 window → "is not defined"
has(target, prop) {
// 不要拦截 Alpine/Vue 内部属性和魔术方法
if (typeof prop === "symbol") return Reflect.has(target, prop);
if (String(prop).startsWith("__v_")) return Reflect.has(target, prop);
if (String(prop).startsWith("$")) return Reflect.has(target, prop);
// 所有其他属性都报告存在,让 with 继续用 get 获取兜底值
return true;
},
set(target, prop, value, receiver) {
return Reflect.set(target, prop, value, receiver);
},
});
return stub;
};
}