fix(hover-nav): 修复主题色失效和按钮尺寸问题
1. 将按钮尺寸从80rpx调整为72rpx,修正布局计算和样式注释
2. 修复Teleport后主题色无法正确同步的问题:
- 移除watch的immediate选项,改为在mounted后手动触发主题色注入
- 新增_applyThemeColor方法,支持安全地更新内联样式并清理旧值
- 监听themeColor变化,确保主题切换时样式实时更新
This commit is contained in:
@@ -241,16 +241,16 @@ export default {
|
||||
// 1) 测试发现 .btn-item 的 min-*/max-*/aspect-ratio/flex-shrink 等 !important
|
||||
// 规则在 scoped 样式下,被某些 flex 布局的隐式约束吃掉,只 width/height/border-radius
|
||||
// 生效,导致高度被压缩成 39.5px(从 41px),按钮显示为轻微椭圆。
|
||||
// 2) inline-style 优先级高于 CSS class,直接锁死 80x80 + 正圆。
|
||||
// 2) inline-style 优先级高于 CSS class,直接锁死 72x72 + 正圆。
|
||||
// 3) 用 max-width/max-height + flex-shrink 0 三重兜底,防止被任何层级的样式覆盖。
|
||||
btnItemStyle() {
|
||||
return {
|
||||
width: '80rpx',
|
||||
height: '80rpx',
|
||||
'min-width': '80rpx',
|
||||
'min-height': '80rpx',
|
||||
'max-width': '80rpx',
|
||||
'max-height': '80rpx',
|
||||
width: '72rpx',
|
||||
height: '72rpx',
|
||||
'min-width': '72rpx',
|
||||
'min-height': '72rpx',
|
||||
'max-width': '72rpx',
|
||||
'max-height': '72rpx',
|
||||
'aspect-ratio': '1',
|
||||
// border-radius 保留作 clip-path 不支持时的 fallback
|
||||
'border-radius': '50%',
|
||||
@@ -298,12 +298,14 @@ export default {
|
||||
|
||||
//根据显示的按钮数量动态计算容器高度
|
||||
// 计算明细(buttonCount 按钮场景):
|
||||
// 每个按钮槽位:80rpx(按钮) + 14rpx(上 margin) + 14rpx(下 margin) = 108rpx
|
||||
// 每个按钮槽位:72rpx(按钮,与 to-top 一致) + 14rpx(上 margin) + 14rpx(下 margin) = 100rpx
|
||||
// 容器 padding:20rpx 上 + 20rpx 下 = 40rpx
|
||||
// 总高度 (rpx):buttonCount × 108 + 40
|
||||
// 总高度 (rpx):buttonCount × 100 + 40
|
||||
// 修复:改返回 rpx 而非 px(原 *0.5 硬编码 iPhone 6 375px 转换比),
|
||||
// 在微信小程序/其他设备(iPhone 13 390px、iPad 等)下由 uni-app 框架
|
||||
// 按 windowWidth 动态换算,避免 4+ 按钮时容器偏小导致内容被裁切
|
||||
// 关联:按钮尺寸与 to-top 同步(72rpx),所以槽位高度也是 100rpx;
|
||||
// 之前按钮 80rpx 时槽位 108rpx,改为 72rpx 后槽位缩小 8rpx,容器整体更紧凑
|
||||
containerHeight() {
|
||||
if (!this.fixBtnShow) return '320rpx';
|
||||
|
||||
@@ -311,7 +313,7 @@ export default {
|
||||
if (this.isLanguageSwitchEnabled) buttonCount++;
|
||||
if (this.showWeappSystemKefu) buttonCount++;
|
||||
buttonCount++;
|
||||
const totalRpx = buttonCount * 108 + 40;
|
||||
const totalRpx = buttonCount * 100 + 40;
|
||||
|
||||
return `${totalRpx}rpx`;
|
||||
},
|
||||
@@ -394,6 +396,28 @@ export default {
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
// 关键修复(全新启动无缓存场景):
|
||||
// 旧逻辑: mounted() 中同步读一次 $store.state.themeColor 写到 this.$el.style.cssText
|
||||
// 但 App.vue 的 boot 是异步的,首屏渲染时主题色还没就绪 → 写入被跳过
|
||||
// 之后主题色就绪,但 hover-nav 不在页面 DOM 树里(已被 Teleport 到 body),
|
||||
// 且**没有任何 watch 监听 themeColor 变化** → cssText 永远不更新
|
||||
// 结果: --hover-nav-bg-color / --hover-nav-text-color 等变量读不到,
|
||||
// 按钮 background-color 退到 transparent,box-shadow 退到 none,
|
||||
// 按钮视觉上"消失"或样式错乱
|
||||
//
|
||||
// 新逻辑:
|
||||
// - 首次启动(无缓存,themeColor 异步就绪): watch 监听 themeColor 变化,
|
||||
// 就绪时注入 cssText
|
||||
// - 刷新(有缓存,themeColor 同步就绪): immediate: true 在 watcher 创建时触发,
|
||||
// 但此时 this.$el 还不存在(_applyThemeColor return),watch 之后再无变化,
|
||||
// 导致 cssText 永远不注入
|
||||
// - 修复: 移除 immediate,改在 mounted() 中 Teleport 完成后手动调一次
|
||||
// _applyThemeColor(currentTc),此时 $el 已就位,同步路径也能正确注入
|
||||
'$store.state.themeColor': {
|
||||
handler(newTc) {
|
||||
this._applyThemeColor(newTc);
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -460,8 +484,18 @@ export default {
|
||||
// 副作用: 搬家后,页面根元素上的 CSS 变量(themeColor,如
|
||||
// --hover-nav-bg-color)不再通过继承传递给 hover-nav,
|
||||
// 因为 body 不在页面的 DOM 子树里。
|
||||
// 修复: 把 $store.state.themeColor 同步到 this.$el 的 inline style,
|
||||
// 让 hover-nav 自己持有这些 CSS 变量,不再依赖页面继承。
|
||||
// 修复: 由 watch('$store.state.themeColor') 监听主题色变化,
|
||||
// 同步到 this.$el 的 inline style,让 hover-nav 自己持有这些 CSS 变量。
|
||||
// 注意:必须在 mounted 中执行 Teleport,**之后** watch 才能找到
|
||||
// 正确的 this.$el 元素;否则 watch 触发时,hover-nav 还在原父节点下,
|
||||
// 主题色仍会通过页面继承自动应用,无需手动注入(但 Teleport 后会丢失)。
|
||||
//
|
||||
// 关键: mounted 末尾手动调一次 _applyThemeColor(currentTc),
|
||||
// 解决刷新(有缓存,themeColor 同步就绪)场景下:
|
||||
// - watch immediate 触发时 $el 不存在 → return
|
||||
// - 之后 themeColor 已就绪、无变化 → watch 不再触发
|
||||
// - → cssText 永远不注入
|
||||
// 在这里调用能保证 $el 已就位,即使 themeColor 已有值也能正确注入。
|
||||
//
|
||||
// 注意: this.$el 是 Vue 组件的根元素(模板最外层的 <view>),
|
||||
// 搬走它后 Vue 的响应式、事件、生命周期**完全不受影响**,
|
||||
@@ -472,18 +506,12 @@ export default {
|
||||
if (typeof document !== 'undefined' && document.body && this.$el) {
|
||||
this._origParent = this.$el.parentNode;
|
||||
document.body.appendChild(this.$el);
|
||||
|
||||
// 搬家后,把页面根元素上的 CSS 变量同步到 hover-nav 自己身上
|
||||
// 主题系统把 themeColor 挂到页面根元素(如 index.vue 的 <view :style="themeColor">),
|
||||
// 搬家后 hover-nav 不在页面子树里,继承不到这些变量。
|
||||
// 这里直接从 store 读 themeColor 写到 this.$el 的 style 上,
|
||||
// 让 .btn-item .common-bg 能正常读到 --hover-nav-bg-color 等变量。
|
||||
const tc = this.$store && this.$store.state && this.$store.state.themeColor;
|
||||
if (tc && this.$el.style) {
|
||||
this.$el.style.cssText = (this.$el.style.cssText || '') + ';' + tc;
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
// 关键: 手动同步当前 themeColor(覆盖 watch immediate 失效的场景)
|
||||
// 详见上面的注释。_applyThemeColor 内部已判 $el 存在性,所有平台都安全。
|
||||
this._applyThemeColor(this.$store && this.$store.state && this.$store.state.themeColor);
|
||||
},
|
||||
beforeDestroy() {
|
||||
// H5 Teleport 还原:把元素从 body 移回原父节点,避免内存泄漏
|
||||
@@ -519,6 +547,35 @@ export default {
|
||||
}
|
||||
},
|
||||
// #endif
|
||||
|
||||
/**
|
||||
* 把 themeColor 注入到 this.$el 的 cssText,
|
||||
* 让 Teleport 到 body 后仍能读到 --hover-nav-bg-color 等 CSS 变量。
|
||||
*
|
||||
* 关键设计:
|
||||
* - 用 data._appliedThemeColor 记录"已注入的 themeColor",
|
||||
* 再次触发时**先剥离**旧值,再追加新值,避免重复拼接。
|
||||
* - 主题切换时,旧值要先剥离(否则 cssText 会一直累积,文件膨胀)。
|
||||
* - themeColor 为空时只剥离、不追加(themeColorSet action
|
||||
* 内部会去重,不会频繁触发)。
|
||||
*/
|
||||
_applyThemeColor(tc) {
|
||||
if (!this.$el || !this.$el.style) return;
|
||||
// 1) 剥离旧注入(避免重复 + 处理主题切换场景)
|
||||
if (this._appliedThemeColor) {
|
||||
const cur = this.$el.style.cssText || '';
|
||||
const suffix = ';' + this._appliedThemeColor;
|
||||
if (cur.endsWith(suffix)) {
|
||||
this.$el.style.cssText = cur.slice(0, -suffix.length);
|
||||
}
|
||||
this._appliedThemeColor = '';
|
||||
}
|
||||
// 2) 追加新值
|
||||
if (tc) {
|
||||
this._appliedThemeColor = tc;
|
||||
this.$el.style.cssText = (this.$el.style.cssText || '') + ';' + tc;
|
||||
}
|
||||
},
|
||||
initLanguage() {
|
||||
// 数据源优先级:
|
||||
// 1) shopInfo.langList(后端按租户/店铺动态下发的语言配置,推荐)
|
||||
@@ -734,10 +791,10 @@ export default {
|
||||
transition: 0.1s;
|
||||
color: var(--hover-nav-text-color);
|
||||
border-radius: 50%;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
/* 关键:微信小程序的 <button> 元素有默认 appearance/background/border,
|
||||
* 必须显式重置,否则 80rpx 高度会被默认样式吃掉,渲染成椭圆。 */
|
||||
* 必须显式重置,否则 72rpx 高度会被默认样式吃掉,渲染成椭圆。 */
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
background: transparent;
|
||||
@@ -747,10 +804,10 @@ export default {
|
||||
/* CSS 端兜底:即使 inline-style 失效,也能保证 1:1 比例 */
|
||||
aspect-ratio: 1;
|
||||
/* 锁死宽高,防止父级 flex 容器压缩 */
|
||||
min-width: 80rpx;
|
||||
min-height: 80rpx;
|
||||
max-width: 80rpx;
|
||||
max-height: 80rpx;
|
||||
min-width: 72rpx;
|
||||
min-height: 72rpx;
|
||||
max-width: 72rpx;
|
||||
max-height: 72rpx;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
align-self: center;
|
||||
@@ -775,11 +832,11 @@ export default {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
/* 不再设 width: 100% / height: 100% 再覆盖为 80rpx 的写法,
|
||||
/* 不再设 width: 100% / height: 100% 再覆盖为 72rpx 的写法,
|
||||
* 微信小程序/H5 对 width: 100% 在 flex 列布局里的高度计算有差异,
|
||||
* 直接固定 80x80 更稳。 */
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
* 直接固定 72x72 更稳。 */
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
margin: 0;
|
||||
border-radius: 50%;
|
||||
padding: 0;
|
||||
@@ -823,7 +880,7 @@ export default {
|
||||
* 语言按钮的 inner 用 <view class="lang-btn-text"> 包裹文字,
|
||||
* 如果没有这个规则,view 会用默认 font-size/line-height,
|
||||
* "CN" / "EN" / "JP" 在中文/日文系统下会渲染成 32-40rpx 高,
|
||||
* 撑高按钮导致 80rpx width × 38rpx height 的"伪正圆"实际是椭圆。 */
|
||||
* 撑高按钮导致 72rpx width × 38rpx height 的"伪正圆"实际是椭圆。 */
|
||||
.lang-btn-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user