refactor: 统一重构底部导航栏间距逻辑与显示规则
1. 新增全局计算属性统一处理底部导航栏显示判断与间距样式 2. 替换多个页面的手写底部间距逻辑为通用样式 3. 新增路由匹配工具函数,支持灵活配置导航栏显示范围 4. 优化底部导航组件的显示条件判断
This commit is contained in:
@@ -22,6 +22,57 @@ export default {
|
||||
tabBarList() {
|
||||
return this.$store.state.tabBarList;
|
||||
},
|
||||
shouldShowTabBar() {
|
||||
const tabBarList = this.$store.state.tabBarList;
|
||||
if (!tabBarList || !tabBarList.list) {
|
||||
return false;
|
||||
}
|
||||
const mode = tabBarList.page_visibility_mode;
|
||||
const routeList = tabBarList.page_routes || [];
|
||||
if (!mode || mode === 'all') {
|
||||
return true;
|
||||
}
|
||||
if (mode === 'none') {
|
||||
return false;
|
||||
}
|
||||
const pages = getCurrentPages();
|
||||
if (pages.length === 0) {
|
||||
return true;
|
||||
}
|
||||
const currentPage = pages[pages.length - 1];
|
||||
let currentRoute = '';
|
||||
if (currentPage.route) {
|
||||
currentRoute = currentPage.route;
|
||||
} else if (currentPage.$page && currentPage.$page.path) {
|
||||
currentRoute = currentPage.$page.path;
|
||||
}
|
||||
if (!currentRoute) {
|
||||
return true;
|
||||
}
|
||||
if (!currentRoute.startsWith('/')) {
|
||||
currentRoute = '/' + currentRoute;
|
||||
}
|
||||
const inList = this.$util && this.$util.isPageInRouteList
|
||||
? this.$util.isPageInRouteList(currentRoute, routeList)
|
||||
: false;
|
||||
if (mode === 'whitelist') {
|
||||
return inList;
|
||||
}
|
||||
if (mode === 'blacklist') {
|
||||
return !inList;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
tabBarPagePaddingStyle() {
|
||||
return this.$util.objToStyle({
|
||||
paddingBottom: this.shouldShowTabBar ? '112rpx' : '0'
|
||||
});
|
||||
},
|
||||
tabBarPaddingStyleValue() {
|
||||
return {
|
||||
paddingBottom: this.shouldShowTabBar ? '112rpx' : '0'
|
||||
};
|
||||
},
|
||||
siteInfo() {
|
||||
return this.$store.state.siteInfo;
|
||||
},
|
||||
|
||||
@@ -152,6 +152,66 @@ export const resolvePageUrl = (page_key, params = {}) => {
|
||||
return url;
|
||||
};
|
||||
|
||||
/**
|
||||
* 判断当前路由是否命中 page_routes 列表
|
||||
* 支持 3 种写法,可混合使用:
|
||||
* 1) PAGE_KEY_MAP 的 key → 如 "PAGE_INDEX"
|
||||
* 2) 实际页面路径 → 如 "/pages/index/index"
|
||||
* 3) 通配符路径 → 如 "/pages_tool/*" 或 "PAGE_ORDER_*"
|
||||
* @param {string} currentRoute 当前页面路径(会自动补 / 前缀)
|
||||
* @param {string[]} routeList 后台配置的 page_routes 数组
|
||||
* @returns {boolean} 是否命中
|
||||
*/
|
||||
export const isPageInRouteList = (currentRoute, routeList) => {
|
||||
if (!currentRoute || !routeList || !Array.isArray(routeList) || routeList.length === 0) {
|
||||
return false;
|
||||
}
|
||||
const route = currentRoute.startsWith('/') ? currentRoute : '/' + currentRoute;
|
||||
|
||||
for (const item of routeList) {
|
||||
if (!item || typeof item !== 'string') continue;
|
||||
const entry = item.trim();
|
||||
if (!entry) continue;
|
||||
|
||||
if (entry.endsWith('/*')) {
|
||||
const prefix = entry.slice(0, -1);
|
||||
if (route.startsWith(prefix)) return true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.endsWith('_*') && PAGE_KEY_MAP) {
|
||||
const keyPrefix = entry.slice(0, -1);
|
||||
const matchedPaths = [];
|
||||
for (const k of Object.keys(PAGE_KEY_MAP)) {
|
||||
if (k.startsWith(keyPrefix) && PAGE_KEY_MAP[k]) {
|
||||
matchedPaths.push(PAGE_KEY_MAP[k]);
|
||||
}
|
||||
}
|
||||
for (const p of matchedPaths) {
|
||||
const pn = p.startsWith('/') ? p : '/' + p;
|
||||
const dirPrefix = pn.substring(0, pn.lastIndexOf('/') + 1);
|
||||
if (route.startsWith(dirPrefix)) return true;
|
||||
if (route === pn) return true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PAGE_KEY_MAP && PAGE_KEY_MAP[entry]) {
|
||||
let mapped = PAGE_KEY_MAP[entry];
|
||||
mapped = mapped.startsWith('/') ? mapped : '/' + mapped;
|
||||
if (route === mapped) return true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.startsWith('/')) {
|
||||
if (route === entry) return true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 解析 link 对象得到最终可跳转的 URL
|
||||
* 优先级: page_key → wap_url → null
|
||||
@@ -343,6 +403,9 @@ export default {
|
||||
/** 根据 page_key + params 解析实际URL */
|
||||
resolvePageUrl,
|
||||
|
||||
/** 判断当前路由是否命中 page_routes 列表(支持 PAGE_KEY / 实际路径 / 通配符) */
|
||||
isPageInRouteList,
|
||||
|
||||
/** 解析 link 对象得到最终可跳转的 URL(优先级: page_key → wap_url) */
|
||||
resolveLinkUrl,
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view data-component-name="diy-bottom-nav" v-if="tabBarList && tabBarList.list">
|
||||
<view data-component-name="diy-bottom-nav" v-if="shouldShowTabBar">
|
||||
<view class="tab-bar" :style="{ backgroundColor: tabBarList.backgroundColor }">
|
||||
<view class="tabbar-border"></view>
|
||||
<view class="item" v-for="(item, index) in tabBarList.list" :key="item.id" @tap.stop="redirectTo(item.link)">
|
||||
@@ -110,7 +110,7 @@ export default {
|
||||
},
|
||||
packageEntryTab() {
|
||||
return this.$store.state.packageEntryTab;
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
cartChange: function (nval, oval) {
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
<view :class="['list-wrap', value.style]" :style="warpCss">
|
||||
<view :class="['item', value.ornament.type]" v-for="(item, index) in list" :key="index"
|
||||
:style="itemCss" @tap.stop="handlerClick(item)">
|
||||
<view class="merch-img">
|
||||
<view class="merch-img" @tap.stop="handlerClick(item)">
|
||||
<image class="cover-img" :src="$util.img(item.merch_image)" mode="widthFix"
|
||||
@error="imgError(index)" show-menu-by-longpress />
|
||||
</view>
|
||||
<view class="info-wrap">
|
||||
<text class="title">{{ item.merch_name }}</text>
|
||||
<text class="desc">{{ item.desc }}</text>
|
||||
<view class="read-wrap"></view>
|
||||
</view>
|
||||
<text class="title" @tap.stop="handlerClick(item)">{{ item.merch_name }}</text>
|
||||
<text class="desc">{{ item.desc }}</text>
|
||||
<view class="read-wrap"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -27,14 +27,16 @@
|
||||
<view class="merch-nav-item graphic" v-for="(item, index) in list" :key="index"
|
||||
:style="{ width: 100 / 4 + '%' }" @tap.stop="handlerClick(item)">
|
||||
<view class="graphic-img" v-if="value.mode != 'text'"
|
||||
:style="{ fontSize: value.imageSize * 2 + 'rpx', width: value.imageSize * 2 + 'rpx', height: value.imageSize * 2 + 'rpx' }">
|
||||
:style="{ fontSize: value.imageSize * 2 + 'rpx', width: value.imageSize * 2 + 'rpx', height: value.imageSize * 2 + 'rpx' }"
|
||||
@tap.stop="handlerClick(item)">
|
||||
<image
|
||||
:src="$util.img(item.merch_image) || $util.img('public/uniapp/default_img/goods.png')"
|
||||
mode="aspectFill" show-menu-by-longpress
|
||||
style="max-width: 80rpx; max-height: 80rpx; border-radius: 50rpx;" />
|
||||
</view>
|
||||
<text class="graphic-text"
|
||||
style="font-size: 28rpx; font-weight: normal; color: rgb(48, 49, 51);">
|
||||
style="font-size: 28rpx; font-weight: normal; color: rgb(48, 49, 51);"
|
||||
@tap.stop="handlerClick(item)">
|
||||
{{ item.merch_name }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
</view>
|
||||
|
||||
<!-- #ifdef MP -->
|
||||
<mescroll-uni ref="mescroll" @getData="getListData" top="176rpx" v-if="storeToken" :style="orderListPageStyle">
|
||||
<mescroll-uni ref="mescroll" @getData="getListData" top="176rpx" v-if="storeToken" :style="tabBarPagePaddingStyle">
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef MP -->
|
||||
<mescroll-uni ref="mescroll" @getData="getListData" top="196rpx" v-if="storeToken" :style="orderListPageStyle">
|
||||
<mescroll-uni ref="mescroll" @getData="getListData" top="196rpx" v-if="storeToken" :style="tabBarPagePaddingStyle">
|
||||
<!-- #endif -->
|
||||
<block slot="list">
|
||||
<view class="order-list" v-if="orderList.length > 0">
|
||||
@@ -448,11 +448,6 @@ export default {
|
||||
mpOrderList() {
|
||||
if (!this.orderList[this.status]) return;
|
||||
return this.orderList[this.status].list || [];
|
||||
},
|
||||
orderListPageStyle() {
|
||||
return this.$util.objToStyle({
|
||||
paddingBottom: this.tabBarList && this.tabBarList.list ? '112rpx' : '0'
|
||||
});
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view class="content" :style="themeColor">
|
||||
<mescroll-uni ref="mescroll" @getData="getGoodsList" :style="fenxiaoGoodsListPageStyle">
|
||||
<mescroll-uni ref="mescroll" @getData="getGoodsList" :style="tabBarPagePaddingStyle">
|
||||
<block slot="list">
|
||||
<view class="goods-list"
|
||||
:style="{ backgroundImage: 'url(' + $util.img('public/uniapp/fenxiao/promote/promote_bg.png') + ')' }">
|
||||
@@ -139,14 +139,7 @@ import list from './public/js/goods_list.js';
|
||||
import fenxiaoWords from 'common/js/fenxiao-words.js';
|
||||
|
||||
export default {
|
||||
mixins: [list, fenxiaoWords],
|
||||
computed: {
|
||||
fenxiaoGoodsListPageStyle() {
|
||||
return this.$util.objToStyle({
|
||||
paddingBottom: this.tabBarList && this.tabBarList.list ? '112rpx' : '0'
|
||||
});
|
||||
}
|
||||
}
|
||||
mixins: [list, fenxiaoWords]
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -581,7 +581,7 @@ export default {
|
||||
},
|
||||
fenxiaoIndexPageStyle() {
|
||||
const style = {
|
||||
paddingBottom: this.tabBarList && this.tabBarList.list ? '112rpx' : '0'
|
||||
...this.tabBarPaddingStyleValue
|
||||
};
|
||||
if (this.$util && this.$util.img) {
|
||||
style.background = 'url(' + this.$util.img('public/uniapp/fenxiao/index/commissionFission-background.png') + ')';
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
<mescroll-uni ref="mescroll" @getData="getData" top="90" class="member-point" :size="8" v-if="storeToken" :style="fenxiaoOrderPageStyle">
|
||||
<mescroll-uni ref="mescroll" @getData="getData" top="90" class="member-point" :size="8" v-if="storeToken" :style="tabBarPagePaddingStyle">
|
||||
<view class="goods_list" slot="list">
|
||||
<view class="order-list">
|
||||
<view class="order-item" v-for="(orderItem, orderIndex) in orderList" :key="orderIndex"
|
||||
@@ -134,13 +134,6 @@ export default {
|
||||
subMemberId: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
fenxiaoOrderPageStyle() {
|
||||
return this.$util.objToStyle({
|
||||
paddingBottom: this.tabBarList && this.tabBarList.list ? '112rpx' : '0'
|
||||
});
|
||||
}
|
||||
},
|
||||
mixins: [fenxiaoWords],
|
||||
onLoad(option) {
|
||||
if (option.type != undefined) this.selectId = option.type;
|
||||
|
||||
@@ -96,10 +96,9 @@
|
||||
},
|
||||
computed: {
|
||||
categoryPageStyle() {
|
||||
const hasTabBar = this.tabBarList && this.tabBarList.list;
|
||||
return this.$util.objToStyle({
|
||||
height: 'calc(100vh - 56px)',
|
||||
paddingBottom: hasTabBar ? '112rpx' : '0'
|
||||
...this.tabBarPaddingStyleValue
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<mescroll-uni top="180" @getData="getData" ref="mescroll" :size="10" :style="pointGoodsListPageStyle">
|
||||
<mescroll-uni top="180" @getData="getData" ref="mescroll" :size="10" :style="tabBarPagePaddingStyle">
|
||||
<block slot="list">
|
||||
<view class="list-wrap">
|
||||
<view class="goods-list double-column" v-if="goodsList.length">
|
||||
@@ -164,13 +164,6 @@ export default {
|
||||
point: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
pointGoodsListPageStyle() {
|
||||
return this.$util.objToStyle({
|
||||
paddingBottom: this.tabBarList && this.tabBarList.list ? '112rpx' : '0'
|
||||
});
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
this.categoryId = options.category_id || 0;
|
||||
this.keyword = options.keyword || '';
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<view class="point-navbar-block" :style="{ height: menuButtonBounding.bottom + 'px' }"></view>
|
||||
<!-- #endif -->
|
||||
|
||||
<scroll-view scroll-y="true" class="point-scroll-view" @scrolltolower="getData" :style="pointListPageStyle">
|
||||
<scroll-view scroll-y="true" class="point-scroll-view" @scrolltolower="getData" :style="tabBarPagePaddingStyle">
|
||||
<view class="point-wrap" :style="{ 'background-position-y': -menuButtonBounding.bottom + 'px' }">
|
||||
<view class="head-box">
|
||||
<view class="account-content">
|
||||
@@ -298,13 +298,6 @@ export default {
|
||||
newestGame: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
pointListPageStyle() {
|
||||
return this.$util.objToStyle({
|
||||
paddingBottom: this.tabBarList && this.tabBarList.list ? '112rpx' : '0'
|
||||
});
|
||||
}
|
||||
},
|
||||
onLoad(option) {
|
||||
setTimeout(() => {
|
||||
if (!this.addonIsExist.pointexchange) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view :style="themeColor">
|
||||
<mescroll-uni @getData="getData" ref="mescroll" :style="articleListPageStyle">
|
||||
<mescroll-uni @getData="getData" ref="mescroll" :style="tabBarPagePaddingStyle">
|
||||
<block slot="list">
|
||||
<view class="article-wrap" v-if="list.length">
|
||||
<ns-adv keyword="NS_ARTICLE" class-name="adv-wrap"></ns-adv>
|
||||
@@ -43,13 +43,6 @@ export default {
|
||||
list: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
articleListPageStyle() {
|
||||
return this.$util.objToStyle({
|
||||
paddingBottom: this.tabBarList && this.tabBarList.list ? '112rpx' : '0'
|
||||
});
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
this.setPublicShare();
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="about w100" :style="casesPageStyle">
|
||||
<view class="about w100" :style="tabBarPagePaddingStyle">
|
||||
<view class="list_cotact padding-top">
|
||||
<view class="container">
|
||||
<block v-for="(item, index) in dataList" :key="index">
|
||||
@@ -109,13 +109,6 @@ export default {
|
||||
video_url: ""
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
casesPageStyle() {
|
||||
return this.$util.objToStyle({
|
||||
paddingBottom: this.tabBarList && this.tabBarList.list ? '112rpx' : '0'
|
||||
});
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.init();
|
||||
},
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<text class="iconfont icon-sousuo3" @tap="search"></text>
|
||||
</view>
|
||||
</view>
|
||||
<mescroll-uni ref="mescroll" top="100" @getData="getData" :style="fileListPageStyle">
|
||||
<mescroll-uni ref="mescroll" top="100" @getData="getData" :style="tabBarPagePaddingStyle">
|
||||
<view slot="list">
|
||||
<block v-if="list.length > 0">
|
||||
<view class="article-wrap">
|
||||
@@ -54,13 +54,6 @@ export default {
|
||||
keyword: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fileListPageStyle() {
|
||||
return this.$util.objToStyle({
|
||||
paddingBottom: this.tabBarList && this.tabBarList.list ? '112rpx' : '0'
|
||||
});
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options.category_id > 0) {
|
||||
this.category_id = options.category_id
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view :data-theme="themeStyle">
|
||||
<mescroll-uni @getData="getBrandList" ref="mescroll" size="20" :style="brandPageStyle">
|
||||
<mescroll-uni @getData="getBrandList" ref="mescroll" size="20" :style="tabBarPagePaddingStyle">
|
||||
<block slot="list">
|
||||
<ns-adv keyword="NS_BRAND" class-name="adv-wrap"></ns-adv>
|
||||
<view class="brand-content" v-if="brandList.length > 0">
|
||||
@@ -34,13 +34,6 @@ export default {
|
||||
siteId: 0
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
brandPageStyle() {
|
||||
return this.$util.objToStyle({
|
||||
paddingBottom: this.tabBarList && this.tabBarList.list ? '112rpx' : '0'
|
||||
});
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options.site_id) this.siteId = options.site_id;
|
||||
},
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<mescroll-uni ref="mescroll" top="100" @getData="getMemberCouponList" :style="couponListPageStyle">
|
||||
<mescroll-uni ref="mescroll" top="100" @getData="getMemberCouponList" :style="tabBarPagePaddingStyle">
|
||||
<block slot="list">
|
||||
<view class="coupon-listone">
|
||||
<view class="item" v-for="(item, index) in list" :key="index" @click="liClick(item, index)"
|
||||
@@ -95,13 +95,6 @@ export default {
|
||||
mpShareData: null //小程序分享数据
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
couponListPageStyle() {
|
||||
return this.$util.objToStyle({
|
||||
paddingBottom: this.tabBarList && this.tabBarList.list ? '112rpx' : '0'
|
||||
});
|
||||
}
|
||||
},
|
||||
onLoad(option) {
|
||||
setTimeout(() => {
|
||||
if (!this.addonIsExist.coupon) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view :style="themeColor">
|
||||
<view class="content" :style="searchPageStyle">
|
||||
<view class="content" :style="tabBarPagePaddingStyle">
|
||||
<view class="cate-search">
|
||||
<view class="search-box" @click="search()" @tap.stop="search()">
|
||||
<input class="uni-input" maxlength="50" v-model="inputValue" confirm-type="search" @focus="inputFocus" focus @confirm="search()" @click="search()" @tap="search()" :placeholder="searchWords ? searchWords : ''" />
|
||||
@@ -62,13 +62,6 @@
|
||||
isAllHistory: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
searchPageStyle() {
|
||||
return this.$util.objToStyle({
|
||||
paddingBottom: this.tabBarList && this.tabBarList.list ? '112rpx' : '0'
|
||||
});
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options.keyword) this.inputValue = options.keyword;
|
||||
uni.getStorageSync('search') ? '' : uni.setStorageSync('search', []);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view :style="themeColor">
|
||||
<mescroll-uni @getData="getData" ref="mescroll" :style="noticeListPageStyle">
|
||||
<mescroll-uni @getData="getData" ref="mescroll" :style="tabBarPagePaddingStyle">
|
||||
<block slot="list">
|
||||
<view class="notice-list" v-if="dataList.length">
|
||||
<view class="notice-item" @click="jumpDetail(item.id)" v-for="(item, index) in dataList"
|
||||
@@ -37,13 +37,6 @@ export default {
|
||||
dataList: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
noticeListPageStyle() {
|
||||
return this.$util.objToStyle({
|
||||
paddingBottom: this.tabBarList && this.tabBarList.list ? '112rpx' : '0'
|
||||
});
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
this.setPublicShare();
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user