refactor(privacy-popup): 重构隐私弹窗的国际化文案处理逻辑
修复了小程序启动早期Lang未完成初始化时$lang返回空串的问题,将文案计算移到弹窗前一次性执行,统一多平台的文案获取逻辑
This commit is contained in:
@@ -2,23 +2,23 @@
|
|||||||
<view>
|
<view>
|
||||||
<view class="privacy-mask" v-if="showPop">
|
<view class="privacy-mask" v-if="showPop">
|
||||||
<view class="privacy-wrap">
|
<view class="privacy-wrap">
|
||||||
<view class="privacy-title">{{ $lang('components.privacyPopup.title') }}</view>
|
<view class="privacy-title">{{ i18n.title }}</view>
|
||||||
<view class="privacy-desc">
|
<view class="privacy-desc">
|
||||||
{{ $lang('components.privacyPopup.descPrefix', { appName: appName }) }}
|
{{ i18n.descPrefix }}
|
||||||
<text class="privacy-link" @tap="openPrivacyContract">{{ privacyContractName }}</text>
|
<text class="privacy-link" @tap="openPrivacyContract">{{ i18n.privacyContractName }}</text>
|
||||||
<!-- #ifdef QUICKAPP-WEBVIEW || H5 || MP-HARMONY -->
|
<!-- #ifdef QUICKAPP-WEBVIEW || H5 || MP-HARMONY -->
|
||||||
<text class="privacy-link" @tap="openPrivacyService">{{ privacyServiceName }}</text>
|
<text class="privacy-link" @tap="openPrivacyService">{{ i18n.privacyServiceName }}</text>
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
{{ $lang('components.privacyPopup.descSuffix', { appName: appName }) }}
|
{{ i18n.descSuffix }}
|
||||||
</view>
|
</view>
|
||||||
<view class="privacy-button-flex">
|
<view class="privacy-button-flex">
|
||||||
<button class="privacy-button-btn bg-disagree" @tap="handleDisagree">{{ $lang('components.privacyPopup.disagreeBtn') }}</button>
|
<button class="privacy-button-btn bg-disagree" @tap="handleDisagree">{{ i18n.disagreeBtn }}</button>
|
||||||
<!-- #ifdef QUICKAPP-WEBVIEW || MP-WEIXIN -->
|
<!-- #ifdef QUICKAPP-WEBVIEW || MP-WEIXIN -->
|
||||||
<button id="agree-btn" class="privacy-button-btn bg-agree" open-type="agreePrivacyAuthorization"
|
<button id="agree-btn" class="privacy-button-btn bg-agree" open-type="agreePrivacyAuthorization"
|
||||||
@agreeprivacyauthorization="handleAgree">{{ $lang('components.privacyPopup.agreeBtn') }}</button>
|
@agreeprivacyauthorization="handleAgree">{{ i18n.agreeBtn }}</button>
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<!-- #ifdef H5 || MP-HARMONY -->
|
<!-- #ifdef H5 || MP-HARMONY -->
|
||||||
<button id="agree-btn" class="privacy-button-btn bg-agree" @tap="handleAgree">{{ $lang('components.privacyPopup.agreeBtn') }}</button>
|
<button id="agree-btn" class="privacy-button-btn bg-agree" @tap="handleAgree">{{ i18n.agreeBtn }}</button>
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -43,14 +43,23 @@ export default {
|
|||||||
showPop: false,
|
showPop: false,
|
||||||
privacyAuthorization: null,
|
privacyAuthorization: null,
|
||||||
privacyResolves: new Set(),
|
privacyResolves: new Set(),
|
||||||
|
// 平台提供的隐私协议名称(由 wx.getPrivacySetting 等异步设置)
|
||||||
privacyContractName: this.$lang('components.privacyPopup.defaultContractNameMp'),
|
// 弹窗前才参与计算 i18n.privacyContractName
|
||||||
appName: this.$lang('components.privacyPopup.defaultAppNameMp'),
|
platformContractName: '',
|
||||||
// #ifdef H5 || MP-HARMONY
|
// 弹窗文案: 在 popUp() 之前由 prepareI18n() 一次性计算
|
||||||
appName: this.$lang('components.privacyPopup.defaultAppNameH5'),
|
// 关键: 不在 data() 中调 $lang(避免 boot 未完成时缓存空串)
|
||||||
privacyContractName: this.$lang('components.privacyPopup.defaultContractNameH5'),
|
// 也不在 mounted/computed 中调(method/computed 响应式不稳定)
|
||||||
privacyServiceName: this.$lang('components.privacyPopup.defaultServiceNameH5'),
|
// 此时 Lang.boot() 必然已完成(PrivacyManager.show() 在 await boot() 后才执行)
|
||||||
// #endif
|
i18n: {
|
||||||
|
title: '',
|
||||||
|
descPrefix: '',
|
||||||
|
descSuffix: '',
|
||||||
|
privacyContractName: '',
|
||||||
|
privacyServiceName: '',
|
||||||
|
disagreeBtn: '',
|
||||||
|
agreeBtn: '',
|
||||||
|
disagreeTip: '',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -76,7 +85,7 @@ export default {
|
|||||||
// #ifdef MP-WEIXIN
|
// #ifdef MP-WEIXIN
|
||||||
wx.getPrivacySetting({
|
wx.getPrivacySetting({
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
this.privacyContractName = res.privacyContractName
|
this.platformContractName = res.privacyContractName || ''
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// #endif
|
// #endif
|
||||||
@@ -86,7 +95,7 @@ export default {
|
|||||||
has.getPrivacySetting({
|
has.getPrivacySetting({
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.privacyContractName) {
|
if (res.privacyContractName) {
|
||||||
this.privacyContractName = res.privacyContractName
|
this.platformContractName = res.privacyContractName
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -101,6 +110,57 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
/**
|
||||||
|
* 在弹窗前**一次性**计算所有 i18n 文案
|
||||||
|
* 关键修复: 微信小程序首次启动时, main.js 同步 $mount() 导致 data() 求值时
|
||||||
|
* Lang.boot() 尚未完成, $lang() 返回空串; 即使 boot 完成后 emit $forceUpdate,
|
||||||
|
* data 字段不会重新求值, computed 依赖追踪也可能被压缩器优化掉。
|
||||||
|
* 此方法在 popUp() 之前同步执行, 此时 Lang.boot() 必然已完成,
|
||||||
|
* 一次性把 i18n 字段填好, 模板只读 data 即可, 效果与 H5 一致。
|
||||||
|
*/
|
||||||
|
prepareI18n() {
|
||||||
|
const $lang = this.$lang.bind(this);
|
||||||
|
// 应用名称(按平台取值)
|
||||||
|
// #ifdef H5 || MP-HARMONY
|
||||||
|
const appName = $lang('components.privacyPopup.defaultAppNameH5');
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5 || MP-HARMONY
|
||||||
|
const appName = $lang('components.privacyPopup.defaultAppNameMp');
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// 隐私协议名称: 平台提供的优先, 否则回退 i18n 默认值
|
||||||
|
let privacyContractName;
|
||||||
|
if (this.platformContractName) {
|
||||||
|
privacyContractName = this.platformContractName;
|
||||||
|
} else {
|
||||||
|
// #ifdef H5 || MP-HARMONY
|
||||||
|
privacyContractName = $lang('components.privacyPopup.defaultContractNameH5');
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5 || MP-HARMONY
|
||||||
|
privacyContractName = $lang('components.privacyPopup.defaultContractNameMp');
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// 服务协议名称(仅 H5/鸿蒙端显示)
|
||||||
|
// #ifdef H5 || MP-HARMONY
|
||||||
|
const privacyServiceName = $lang('components.privacyPopup.defaultServiceNameH5');
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5 || MP-HARMONY
|
||||||
|
const privacyServiceName = '';
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
this.i18n = {
|
||||||
|
title: $lang('components.privacyPopup.title'),
|
||||||
|
descPrefix: $lang('components.privacyPopup.descPrefix', { appName }),
|
||||||
|
descSuffix: $lang('components.privacyPopup.descSuffix', { appName }),
|
||||||
|
privacyContractName,
|
||||||
|
privacyServiceName,
|
||||||
|
disagreeBtn: $lang('components.privacyPopup.disagreeBtn'),
|
||||||
|
agreeBtn: $lang('components.privacyPopup.agreeBtn'),
|
||||||
|
disagreeTip: $lang('components.privacyPopup.disagreeTip'),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接收全局隐私弹窗事件
|
* 接收全局隐私弹窗事件
|
||||||
* 由 App.vue → PrivacyManager.show() → uni.$emit('privacy:show') 触发
|
* 由 App.vue → PrivacyManager.show() → uni.$emit('privacy:show') 触发
|
||||||
@@ -295,7 +355,7 @@ export default {
|
|||||||
PrivacyManager.disagree()
|
PrivacyManager.disagree()
|
||||||
|
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
content: this.$lang('components.privacyPopup.disagreeTip'),
|
content: this.i18n.disagreeTip,
|
||||||
success: () => {
|
success: () => {
|
||||||
this.$emit('disagree')
|
this.$emit('disagree')
|
||||||
}
|
}
|
||||||
@@ -321,6 +381,10 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
popUp() {
|
popUp() {
|
||||||
|
// 弹窗前**一次性**计算所有 i18n 文案
|
||||||
|
// 此时 App.vue 已 await boot() + await PrivacyManager.show() 完成,
|
||||||
|
// Lang.boot() 必然已完成, $lang() 返回真实翻译(效果与 H5 一致)
|
||||||
|
this.prepareI18n()
|
||||||
this.showPop = true;
|
this.showPop = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user