chore :悬浮按钮自定义
This commit is contained in:
@@ -172,7 +172,7 @@ function getLangShortCode(langValue, customMap) {
|
|||||||
// 切回首页时按钮突然上/下跳。缓存上次算出的避让值, 让所有页面位置恒定。
|
// 切回首页时按钮突然上/下跳。缓存上次算出的避让值, 让所有页面位置恒定。
|
||||||
let cachedAvoidBottom = null;
|
let cachedAvoidBottom = null;
|
||||||
|
|
||||||
// H5 端需要隐藏悬浮按钮的页面路由(仅 H5, 微信小程序保持显示)
|
// 需要隐藏悬浮按钮的页面路由(全平台生效: H5 + 小程序)
|
||||||
// /pages_goods/category 商品分类
|
// /pages_goods/category 商品分类
|
||||||
// /pages_tool/contact/contact 电子名片(名片)
|
// /pages_tool/contact/contact 电子名片(名片)
|
||||||
const H5_HIDDEN_ROUTES = [
|
const H5_HIDDEN_ROUTES = [
|
||||||
@@ -271,19 +271,14 @@ export default {
|
|||||||
fbConfig() {
|
fbConfig() {
|
||||||
return (this.$store && this.$store.state && this.$store.state.floatingButtonConfig) || null;
|
return (this.$store && this.$store.state && this.$store.state.floatingButtonConfig) || null;
|
||||||
},
|
},
|
||||||
// H5 端在指定页面隐藏悬浮按钮(商品分类 / 电子名片)
|
// 指定页面隐藏悬浮按钮(商品分类 / 电子名片), 全平台生效
|
||||||
h5HiddenOnRoute() {
|
hiddenOnRoute() {
|
||||||
// #ifdef H5
|
|
||||||
const r = this.currentRoute;
|
const r = this.currentRoute;
|
||||||
return H5_HIDDEN_ROUTES.some((p) => r === p || r.indexOf(p + '/') === 0);
|
return H5_HIDDEN_ROUTES.some((p) => r === p || r.indexOf(p + '/') === 0);
|
||||||
// #endif
|
|
||||||
// #ifndef H5
|
|
||||||
return false;
|
|
||||||
// #endif
|
|
||||||
},
|
},
|
||||||
// 总开关 + 强制隐藏 + 页面范围 判定结果
|
// 总开关 + 强制隐藏 + 页面范围 判定结果
|
||||||
fbVisible() {
|
fbVisible() {
|
||||||
if (this.h5HiddenOnRoute) return false; // H5 指定页面直接隐藏
|
if (this.hiddenOnRoute) return false; // 指定页面直接隐藏
|
||||||
return shouldShowOnPage(this.fbConfig, this.currentRoute, true);
|
return shouldShowOnPage(this.fbConfig, this.currentRoute, true);
|
||||||
},
|
},
|
||||||
// 最终要渲染的按钮 (已按 button_order 排序 + 显隐过滤); null = 用老行为
|
// 最终要渲染的按钮 (已按 button_order 排序 + 显隐过滤); null = 用老行为
|
||||||
@@ -430,20 +425,35 @@ export default {
|
|||||||
containerBottom() {
|
containerBottom() {
|
||||||
const space = 18;
|
const space = 18;
|
||||||
const base = this.layoutTopBottom + this.layoutTopSize + space;
|
const base = this.layoutTopBottom + this.layoutTopSize + space;
|
||||||
// 避让公告栏(diy-notice 跑马灯): 把悬浮按钮整体放到公告栏"正下方",
|
// 避让公告栏(diy-notice 跑马灯): 把悬浮按钮整体放到公告栏"正下方"。
|
||||||
// 按钮 top 紧贴公告栏底边之下,互不遮挡。公告栏是页面流/固定底部的 DIY
|
// 关键:用「文档坐标」而非「视口坐标」算 bottom ——
|
||||||
// 组件,位置与高度动态,这里用实时测量的视口坐标计算其底边距视口底部的距离。
|
// 公告栏随页面内容滚动, 其视口坐标(rect.bottom)随滚动变化;
|
||||||
|
// 若直接 (winH - rect.bottom) 算, 滚动时按钮会跟着公告栏上下移动。
|
||||||
|
// 这里把 rect 加上当前滚动距离得到"公告栏在文档中的底边",
|
||||||
|
// 再算 (winH - 文档底边): 该值与滚动无关, 按钮固定在"页面顶部时公告栏正下方",
|
||||||
|
// 滚动时按钮静止(公告栏自行滚走), 不再来回滑动。
|
||||||
const rect = this.noticeRect;
|
const rect = this.noticeRect;
|
||||||
let target = null;
|
let target = null;
|
||||||
if (rect && this.winW > 0 && this.winH > 0 && rect.bottom > 0 && rect.top < this.winH) {
|
if (rect && this.winW > 0 && this.winH > 0 && rect.bottom > 0 && rect.top < this.winH) {
|
||||||
|
// 当前滚动距离(H5: window.pageYOffset; 小程序无 window 时回退 0)
|
||||||
|
let scrollY = 0;
|
||||||
|
try {
|
||||||
|
if (typeof window !== 'undefined' && 'pageYOffset' in window) {
|
||||||
|
scrollY = window.pageYOffset || 0;
|
||||||
|
} else if (typeof document !== 'undefined' && document.documentElement) {
|
||||||
|
scrollY = document.documentElement.scrollTop || 0;
|
||||||
|
}
|
||||||
|
} catch (e) { scrollY = 0; }
|
||||||
const scaleInv = 750 / this.winW; // px → 设计稿 rpx
|
const scaleInv = 750 / this.winW; // px → 设计稿 rpx
|
||||||
const gap = 12; // 按钮与公告栏之间的间距(设计稿 rpx)
|
const gap = 12; // 按钮与公告栏之间的间距(设计稿 rpx)
|
||||||
const distFromBottom = (this.winH - rect.bottom) * scaleInv; // 公告栏底边距视口底部
|
// 公告栏底边在文档中的坐标 = 视口坐标 + 滚动距离(滚动无关, 恒定)
|
||||||
// 按钮 bottom = 公告栏底边距 + 间距 - 按钮自身高度 → 按钮 top 落在公告栏底边下方 gap 处
|
const docBottom = rect.bottom + scrollY;
|
||||||
|
const distFromBottom = (this.winH - docBottom) * scaleInv;
|
||||||
|
// 按钮 bottom = 文档底边距视口底部 + 间距 - 按钮自身高度
|
||||||
const below = distFromBottom - gap - this.containerHeightNum;
|
const below = distFromBottom - gap - this.containerHeightNum;
|
||||||
if (Number.isFinite(below)) {
|
if (Number.isFinite(below)) {
|
||||||
target = Math.max(0, below);
|
target = Math.max(0, below);
|
||||||
cachedAvoidBottom = target; // 缓存: 跨页面/重挂载复用, 保证位置恒定不跳动
|
cachedAvoidBottom = target; // 缓存: 跨页面/重挂载复用, 位置恒定
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 无公告栏的页面(如分类页)复用上一次算出的避让值, 使悬浮按钮在所有页面位置一致
|
// 无公告栏的页面(如分类页)复用上一次算出的避让值, 使悬浮按钮在所有页面位置一致
|
||||||
@@ -634,9 +644,10 @@ export default {
|
|||||||
setTimeout(() => this.measureNotice(), 800),
|
setTimeout(() => this.measureNotice(), 800),
|
||||||
];
|
];
|
||||||
// #ifdef H5
|
// #ifdef H5
|
||||||
// 只在挂载时测量一次公告栏位置, 算出固定的 bottom 后:
|
// 不再监听 scroll: containerBottom 已改用「文档坐标」(视口坐标 + 滚动距离)计算,
|
||||||
// - 不监听 scroll —— 否则每次滚动都重测并重算 containerBottom, 按钮会上下跳动
|
// 得到与滚动无关的恒定 bottom —— 按钮固定在"页面顶部时公告栏正下方",
|
||||||
// - 仅监听 resize(旋转/尺寸变化,极少触发), 让按钮在视口尺寸变化时重新避让
|
// 滚动时按钮静止、公告栏自行滚走, 不再来回滑动。
|
||||||
|
// 仅监听 resize(旋转/尺寸变化), 让按钮在视口尺寸变化时重新避让一次。
|
||||||
this._scrollHandler = this._onScroll.bind(this);
|
this._scrollHandler = this._onScroll.bind(this);
|
||||||
window.addEventListener('resize', this._scrollHandler);
|
window.addEventListener('resize', this._scrollHandler);
|
||||||
// #endif
|
// #endif
|
||||||
@@ -784,6 +795,10 @@ export default {
|
|||||||
'min-height': s,
|
'min-height': s,
|
||||||
'max-width': s,
|
'max-width': s,
|
||||||
'max-height': s,
|
'max-height': s,
|
||||||
|
// 内部图标(.iconfont/.icox)通过该变量跟随按钮尺寸:
|
||||||
|
// 图标盒子里原本锁死 72rpx, 按钮调大后图标仍 72rpx,
|
||||||
|
// 又因列 flex 横轴默认贴左 → 图标偏在按钮左上角
|
||||||
|
'--btn-size': s,
|
||||||
'aspect-ratio': '1',
|
'aspect-ratio': '1',
|
||||||
// border-radius 保留作 clip-path 不支持时的 fallback
|
// border-radius 保留作 clip-path 不支持时的 fallback
|
||||||
'border-radius': '50%',
|
'border-radius': '50%',
|
||||||
@@ -1117,6 +1132,9 @@ export default {
|
|||||||
.btn-item {
|
.btn-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
/* 横向居中: 列布局下横轴是 align-items, 固定宽度的子元素
|
||||||
|
* (如锁死尺寸的 .iconfont 图标盒)默认贴左, 必须显式居中 */
|
||||||
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
@@ -1182,11 +1200,11 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
/* 不再设 width: 100% / height: 100% 再覆盖为 72rpx 的写法,
|
/* 尺寸跟随所在按钮: 按钮内联样式写入 --btn-size(=按钮实际尺寸),
|
||||||
* 微信小程序/H5 对 width: 100% 在 flex 列布局里的高度计算有差异,
|
* 图标盒不再锁死 72rpx —— 否则按钮调大后图标偏小且贴左上。
|
||||||
* 直接固定 72x72 更稳。 */
|
* 72rpx 兜底 = 按钮未走 btnItemStyle 内联样式时的默认尺寸。 */
|
||||||
width: 72rpx;
|
width: var(--btn-size, 72rpx);
|
||||||
height: 72rpx;
|
height: var(--btn-size, 72rpx);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user