修复所有 Alpine 组件表达式报错
彻底移除 Proxy/has 陷阱方案,改用显式方法存根: - userCardComponent 补充 35 个方法存根 - marriage-modals 8 个组件改用 createLazyAlpineComponent - weddingSetup/weddingEnvelope 等 Modal 均正确包装 控制台现在应该没有任何 Alpine Expression Error
This commit is contained in:
@@ -769,16 +769,49 @@ if (typeof window !== "undefined") {
|
||||
window.marriageAction = (...args) => _marriageStatus.wrap('marriageAction')(...args);
|
||||
window.openMarriageStatusModal = (...args) => _marriageStatus.wrap('openMarriageStatusModal')(...args);
|
||||
window.appendSystemMessage = (...args) => _marriageModals.wrap('appendSystemMessage')(...args);
|
||||
window.divorceConfirmModal = (...args) => _marriageModals.wrap('divorceConfirmModal')(...args);
|
||||
window.divorceRequestModal = (...args) => _marriageModals.wrap('divorceRequestModal')(...args);
|
||||
window.marriageAcceptedModal = (...args) => _marriageModals.wrap('marriageAcceptedModal')(...args);
|
||||
window.marriageDivorcedModal = (...args) => _marriageModals.wrap('marriageDivorcedModal')(...args);
|
||||
window.marriageIncomingModal = (...args) => _marriageModals.wrap('marriageIncomingModal')(...args);
|
||||
window.marriageProposeModal = (...args) => _marriageModals.wrap('marriageProposeModal')(...args);
|
||||
window.openProposeModal = (...args) => _marriageModals.wrap('openProposeModal')(...args);
|
||||
window.openWeddingSetupModal = (...args) => _marriageModals.wrap('openWeddingSetupModal')(...args);
|
||||
window.weddingEnvelopeModal = (...args) => _marriageModals.wrap('weddingEnvelopeModal')(...args);
|
||||
window.weddingSetupModal = (...args) => _marriageModals.wrap('weddingSetupModal')(...args);
|
||||
// ── 婚姻弹窗 Alpine 组件(createLazyAlpineComponent 懒加载) ──
|
||||
window.marriageProposeModal = createLazyAlpineComponent(
|
||||
() => import("./chat-room/marriage-modals.js"),
|
||||
"marriageProposeModal",
|
||||
{ show: false, targetUsername: "", error: "", loading: false, rings: [], selectedRing: null, selectedTier: null, tiers: [], selectedTierId: null, canAfford: false, sending: false, doPropose: () => {} }
|
||||
);
|
||||
window.marriageIncomingModal = createLazyAlpineComponent(
|
||||
() => import("./chat-room/marriage-modals.js"),
|
||||
"marriageIncomingModal",
|
||||
{ show: false }
|
||||
);
|
||||
window.marriageAcceptedModal = createLazyAlpineComponent(
|
||||
() => import("./chat-room/marriage-modals.js"),
|
||||
"marriageAcceptedModal",
|
||||
{ show: false }
|
||||
);
|
||||
window.marriageDivorcedModal = createLazyAlpineComponent(
|
||||
() => import("./chat-room/marriage-modals.js"),
|
||||
"marriageDivorcedModal",
|
||||
{ show: false }
|
||||
);
|
||||
window.divorceConfirmModal = createLazyAlpineComponent(
|
||||
() => import("./chat-room/marriage-modals.js"),
|
||||
"divorceConfirmModal",
|
||||
{ show: false }
|
||||
);
|
||||
window.divorceRequestModal = createLazyAlpineComponent(
|
||||
() => import("./chat-room/marriage-modals.js"),
|
||||
"divorceRequestModal",
|
||||
{ show: false }
|
||||
);
|
||||
window.weddingSetupModal = createLazyAlpineComponent(
|
||||
() => import("./chat-room/marriage-modals.js"),
|
||||
"weddingSetupModal",
|
||||
{ show: false }
|
||||
);
|
||||
window.weddingEnvelopeModal = createLazyAlpineComponent(
|
||||
() => import("./chat-room/marriage-modals.js"),
|
||||
"weddingEnvelopeModal",
|
||||
{ show: false }
|
||||
);
|
||||
window.renderMarriedList = (...args) => _marriageStatus.wrap('renderMarriedList')(...args);
|
||||
window.renderMarriageStatus = (...args) => _marriageStatus.wrap('renderMarriageStatus')(...args);
|
||||
window.switchMarriageTab = (...args) => _marriageStatus.wrap('switchMarriageTab')(...args);
|
||||
@@ -855,7 +888,42 @@ if (typeof window !== "undefined") {
|
||||
targetMarriage: null,
|
||||
marriageLoading: false,
|
||||
mySex: "",
|
||||
assetCache: [],
|
||||
// 方法存根(防止 Alpine with(scope) 表达式找不到方法而报错)
|
||||
hasPositionPermission: () => false,
|
||||
canManageTargetByDuty: () => false,
|
||||
assetValueLabel: () => "",
|
||||
canRevealAssetValue: () => false,
|
||||
displayAssetValue: () => "",
|
||||
assetValueTitle: () => "",
|
||||
assetValueStyle: () => "",
|
||||
revealAssetValue: () => {},
|
||||
displayBankBalance: () => "",
|
||||
bankBalanceTitle: () => "",
|
||||
bankBalanceStyle: () => "",
|
||||
revealBankBalance: () => {},
|
||||
toggleFriend: () => {},
|
||||
handleConfirmDivorce: () => {},
|
||||
doDivorce: () => {},
|
||||
fetchUser: () => {},
|
||||
_loadPositions: () => {},
|
||||
doAppoint: () => {},
|
||||
doRevoke: () => {},
|
||||
kickUser: () => {},
|
||||
muteUser: () => {},
|
||||
warnUser: () => {},
|
||||
banUser: () => {},
|
||||
banIpUser: () => {},
|
||||
loadWhispers: () => {},
|
||||
sendAnnounce: () => {},
|
||||
sendGift: () => {},
|
||||
toggleGiftPanel: () => {},
|
||||
toggleGiftGoldPanel: () => {},
|
||||
sendGiftGold: () => {},
|
||||
sendReward: () => {},
|
||||
_headers: () => ({}),
|
||||
$alert: (...args) => window.chatDialog?.alert(...args),
|
||||
$confirm: (...args) => window.chatDialog?.confirm(...args),
|
||||
$prompt: (...args) => window.chatDialog?.prompt(...args),
|
||||
},
|
||||
"showUserModal"
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user