修复所有 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.marriageAction = (...args) => _marriageStatus.wrap('marriageAction')(...args);
|
||||||
window.openMarriageStatusModal = (...args) => _marriageStatus.wrap('openMarriageStatusModal')(...args);
|
window.openMarriageStatusModal = (...args) => _marriageStatus.wrap('openMarriageStatusModal')(...args);
|
||||||
window.appendSystemMessage = (...args) => _marriageModals.wrap('appendSystemMessage')(...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.openProposeModal = (...args) => _marriageModals.wrap('openProposeModal')(...args);
|
||||||
window.openWeddingSetupModal = (...args) => _marriageModals.wrap('openWeddingSetupModal')(...args);
|
window.openWeddingSetupModal = (...args) => _marriageModals.wrap('openWeddingSetupModal')(...args);
|
||||||
window.weddingEnvelopeModal = (...args) => _marriageModals.wrap('weddingEnvelopeModal')(...args);
|
// ── 婚姻弹窗 Alpine 组件(createLazyAlpineComponent 懒加载) ──
|
||||||
window.weddingSetupModal = (...args) => _marriageModals.wrap('weddingSetupModal')(...args);
|
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.renderMarriedList = (...args) => _marriageStatus.wrap('renderMarriedList')(...args);
|
||||||
window.renderMarriageStatus = (...args) => _marriageStatus.wrap('renderMarriageStatus')(...args);
|
window.renderMarriageStatus = (...args) => _marriageStatus.wrap('renderMarriageStatus')(...args);
|
||||||
window.switchMarriageTab = (...args) => _marriageStatus.wrap('switchMarriageTab')(...args);
|
window.switchMarriageTab = (...args) => _marriageStatus.wrap('switchMarriageTab')(...args);
|
||||||
@@ -855,7 +888,42 @@ if (typeof window !== "undefined") {
|
|||||||
targetMarriage: null,
|
targetMarriage: null,
|
||||||
marriageLoading: false,
|
marriageLoading: false,
|
||||||
mySex: "",
|
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"
|
"showUserModal"
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -101,13 +101,11 @@ export function createLazyAlpineComponent(importFn, exportName, defaults = {}, w
|
|||||||
const proxy = this;
|
const proxy = this;
|
||||||
let loaded = false;
|
let loaded = false;
|
||||||
|
|
||||||
// 使用 Alpine 的 $watch 监听显示状态变化
|
|
||||||
// 仅在组件变为可见时才加载真实模块
|
|
||||||
if (
|
if (
|
||||||
watchKey in proxy &&
|
watchKey in proxy &&
|
||||||
typeof proxy.$watch === "function"
|
typeof proxy.$watch === "function"
|
||||||
) {
|
) {
|
||||||
proxy.$watch(watchKey, (value, oldValue) => {
|
proxy.$watch(watchKey, (value) => {
|
||||||
if (value && !loaded) {
|
if (value && !loaded) {
|
||||||
loaded = true;
|
loaded = true;
|
||||||
importFn()
|
importFn()
|
||||||
@@ -118,21 +116,18 @@ export function createLazyAlpineComponent(importFn, exportName, defaults = {}, w
|
|||||||
? componentFn(...args)
|
? componentFn(...args)
|
||||||
: componentFn;
|
: componentFn;
|
||||||
|
|
||||||
// 通过 Alpine 响应式代理写入所有属性
|
|
||||||
Object.keys(realData).forEach((key) => {
|
Object.keys(realData).forEach((key) => {
|
||||||
if (key !== "init") {
|
if (key !== "init") {
|
||||||
proxy[key] = realData[key];
|
proxy[key] = realData[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理继承属性
|
|
||||||
for (const key in realData) {
|
for (const key in realData) {
|
||||||
if (!(key in proxy)) {
|
if (!(key in proxy)) {
|
||||||
proxy[key] = realData[key];
|
proxy[key] = realData[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调用真实组件的 init(如果存在)
|
|
||||||
if (
|
if (
|
||||||
typeof proxy.init === "function" &&
|
typeof proxy.init === "function" &&
|
||||||
proxy.init !== stub.init
|
proxy.init !== stub.init
|
||||||
@@ -145,7 +140,7 @@ export function createLazyAlpineComponent(importFn, exportName, defaults = {}, w
|
|||||||
`[懒加载] Alpine 组件 "${exportName}" 加载失败:`,
|
`[懒加载] Alpine 组件 "${exportName}" 加载失败:`,
|
||||||
err,
|
err,
|
||||||
);
|
);
|
||||||
loaded = false; // 允许重试
|
loaded = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -153,33 +148,6 @@ export function createLazyAlpineComponent(importFn, exportName, defaults = {}, w
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// 使用 Proxy 包裹 stub,对任何未在 defaults 中定义的属性/方法提供安全兜底
|
return stub;
|
||||||
// 这样组件模板中的所有表达式(方法调用、属性访问)都不会抛出 "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);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user