1. add packageEntryTab state and mutation in vuex store 2. extract and track current/previous page's matching tab entry 3. update package entry tab state via store commit instead of local variable 4. optimize tab url parsing by stripping query parameters
370 lines
9.9 KiB
Vue
370 lines
9.9 KiB
Vue
<template>
|
|
<view data-component-name="diy-bottom-nav" v-if="tabBarList && tabBarList.list">
|
|
<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)">
|
|
<view class="bd">
|
|
<block v-if="item.link.wap_url == '/pages_goods/cart'">
|
|
<view class="icon" v-if="tabBarList.type == 1 || tabBarList.type == 2"
|
|
:animation="cartAnimation" id="tabbarCart">
|
|
<block v-if="verify(item.link)">
|
|
<image v-if="item.selected_icon_type == 'img'"
|
|
:src="$util.img(item.selectedIconPath)" />
|
|
<diy-icon v-if="item.selected_icon_type == 'icon'" :icon="item.selectedIconPath"
|
|
:value="item.selected_style ? item.selected_style : null"></diy-icon>
|
|
</block>
|
|
<block v-else>
|
|
<image v-if="item.icon_type == 'img'" :src="$util.img(item.iconPath)" />
|
|
<diy-icon v-if="item.icon_type == 'icon'" :icon="item.iconPath"
|
|
:value="item.style ? item.style : null"></diy-icon>
|
|
</block>
|
|
<view class="cart-count-mark font-size-activity-tag"
|
|
:class="{ max: item.link.wap_url == '/pages_goods/cart' && cartNumber > 99 }"
|
|
:style="{ background: 'var(--price-color)' }" v-if="cartNumber > 0">
|
|
{{ cartNumber > 99 ? '99+' : cartNumber }}
|
|
</view>
|
|
</view>
|
|
</block>
|
|
<block v-else>
|
|
<view class="icon" v-if="tabBarList.type == 1 || tabBarList.type == 2">
|
|
<block v-if="verify(item.link)">
|
|
<image v-if="item.selected_icon_type == 'img'"
|
|
:src="$util.img(item.selectedIconPath)" />
|
|
<diy-icon v-if="item.selected_icon_type == 'icon'" :icon="item.selectedIconPath"
|
|
:value="item.selected_style ? item.selected_style : null"></diy-icon>
|
|
</block>
|
|
<block v-else>
|
|
<image v-if="item.icon_type == 'img'" :src="$util.img(item.iconPath)" />
|
|
<diy-icon v-if="item.icon_type == 'icon'" :icon="item.iconPath"
|
|
:value="item.style ? item.style : null"></diy-icon>
|
|
</block>
|
|
</view>
|
|
</block>
|
|
<view class="label"
|
|
v-if="(tabBarList.type == 1 || tabBarList.type == 3) && tabBarList.theme == 'diy'"
|
|
:style="{ color: verify(item.link) ? tabBarList.textHoverColor : tabBarList.textColor }">
|
|
{{ lang == 'en-us' ? item.en_text : item.text }}
|
|
</view>
|
|
<view class="label"
|
|
v-if="(tabBarList.type == 1 || tabBarList.type == 3) && tabBarList.theme == 'default'"
|
|
:style="{ color: verify(item.link) ? 'var(--base-color)' : '#333333' }">
|
|
{{ lang == 'en-us' ? item.en_text : item.text }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<!-- 解决fixed定位后底部导航栏塌陷问题 -->
|
|
<view class="tab-bar-placeholder"></view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import { adaptSubpackageUrl, checkTabBarActive, decodeEntity } from '@/common/js/util.js'
|
|
import DiyMinx from './minx.js'
|
|
// 底部导航栏
|
|
export default {
|
|
name: 'diy-bottom-nav',
|
|
props: {
|
|
value: {
|
|
type: Object
|
|
},
|
|
name: {
|
|
type: String,
|
|
default: ''
|
|
}
|
|
},
|
|
mixins: [DiyMinx],
|
|
data() {
|
|
return {
|
|
lang: uni.getStorageSync("lang"),
|
|
currentRoute: '', //当前页面路径
|
|
jumpFlag: true, //是否可以跳转,防止重复点击
|
|
cartAnimation: {}
|
|
};
|
|
},
|
|
mounted() {
|
|
this.updateCurrentRoute();
|
|
this.$nextTick(() => {
|
|
if (!this.$store.state.cartPosition) {
|
|
let query = uni.createSelectorQuery().in(this);
|
|
query.select('#tabbarCart')
|
|
.boundingClientRect(data => {
|
|
if (data) this.$store.commit('setCartPosition', data);
|
|
}).exec();
|
|
|
|
query.select('.tab-bar')
|
|
.boundingClientRect(data => {
|
|
if (data) this.$store.commit('setTabBarHeight', data.height +
|
|
'px');
|
|
}).exec();
|
|
}
|
|
});
|
|
// 监听页面显示事件,更新当前路由
|
|
this.$on('hook:onShow', () => {
|
|
this.updateCurrentRoute();
|
|
});
|
|
},
|
|
computed: {
|
|
cartChange() {
|
|
return this.$store.state.cartChange;
|
|
},
|
|
packageEntryTab() {
|
|
return this.$store.state.packageEntryTab;
|
|
}
|
|
},
|
|
watch: {
|
|
cartChange: function (nval, oval) {
|
|
if (nval > oval) {
|
|
let animation = uni.createAnimation({
|
|
duration: 200,
|
|
timingFunction: 'ease'
|
|
});
|
|
animation.scale(1.2).step();
|
|
this.cartAnimation = animation.export();
|
|
setTimeout(() => {
|
|
animation.scale(1).step();
|
|
this.cartAnimation = animation.export();
|
|
}, 300);
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
// 更新当前路由
|
|
updateCurrentRoute() {
|
|
let currentPages = getCurrentPages();
|
|
let currentPage = currentPages[currentPages.length - 1];
|
|
if (currentPage && currentPage.route) {
|
|
const newRoute = currentPage.route;
|
|
const newRouteParts = newRoute.split('/');
|
|
|
|
if (this.tabBarList && this.tabBarList.list) {
|
|
const tabUrls = this.tabBarList.list
|
|
.filter(item => item.link && item.link.wap_url)
|
|
.map(item => adaptSubpackageUrl(item.link.wap_url).split('?')[0]);
|
|
|
|
let currentMatchingTab = null;
|
|
for (const tabUrl of tabUrls) {
|
|
const tabParts = tabUrl.split('/');
|
|
if (tabParts[2] === newRouteParts[2] && tabParts[1] === newRouteParts[1]) {
|
|
currentMatchingTab = tabUrl;
|
|
break;
|
|
}
|
|
}
|
|
|
|
let entryTab = null;
|
|
if (currentMatchingTab) {
|
|
entryTab = currentMatchingTab;
|
|
} else {
|
|
const prevPage = currentPages[currentPages.length - 2];
|
|
if (prevPage && prevPage.route) {
|
|
const prevRouteParts = prevPage.route.split('/');
|
|
for (const tabUrl of tabUrls) {
|
|
const tabParts = tabUrl.split('/');
|
|
if (tabParts[2] === prevRouteParts[2] && tabParts[1] === prevRouteParts[1]) {
|
|
entryTab = tabUrl;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (entryTab) {
|
|
const updatedEntryTab = { ...this.packageEntryTab, [newRouteParts[1]]: entryTab };
|
|
this.$store.commit('setPackageEntryTab', updatedEntryTab);
|
|
}
|
|
}
|
|
|
|
this.currentRoute = newRoute;
|
|
}
|
|
},
|
|
redirectTo(link) {
|
|
this.$emit('callback');
|
|
|
|
if (link && link.wap_url) {
|
|
const decodedUrl = decodeEntity(link.wap_url);
|
|
const adaptedUrl = adaptSubpackageUrl(decodedUrl);
|
|
const urlParts = adaptedUrl.split('/');
|
|
|
|
if (urlParts.length >= 2 && urlParts[1]) {
|
|
const updatedEntryTab = { ...this.packageEntryTab, [urlParts[1]]: adaptedUrl };
|
|
this.$store.commit('setPackageEntryTab', updatedEntryTab);
|
|
}
|
|
}
|
|
|
|
this.$util.diyRedirectTo(link);
|
|
},
|
|
verify(link) {
|
|
if (link == null || link == '' || !link.wap_url) return false;
|
|
|
|
let currentPages = getCurrentPages();
|
|
let currentPage = currentPages[currentPages.length - 1];
|
|
let currentPageRoute = currentPage && currentPage.route ? '/' + currentPage.route : '';
|
|
let linkUrl = link.wap_url;
|
|
|
|
if (linkUrl === this.$util.INDEX_PAGE_URL && this.name === 'DIY_VIEW_INDEX') {
|
|
return true;
|
|
}
|
|
|
|
// 使用通用的 checkTabBarActive 函数来判断 tab 高亮状态
|
|
return checkTabBarActive(linkUrl, currentPageRoute, this.tabBarList, this.packageEntryTab);
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.placeholder {
|
|
height: 112rpx;
|
|
|
|
&.bluge {
|
|
height: 180rpx;
|
|
}
|
|
}
|
|
|
|
.safe-area {
|
|
padding-bottom: 0;
|
|
padding-bottom: constant(safe-area-inset-bottom);
|
|
padding-bottom: env(safe-area-inset-bottom);
|
|
}
|
|
|
|
.tab-bar {
|
|
background-color: #fff;
|
|
box-sizing: border-box;
|
|
position: fixed;
|
|
left: 0;
|
|
bottom: 0;
|
|
width: 100%;
|
|
z-index: 998;
|
|
display: flex;
|
|
border-top: 2rpx solid #f5f5f5;
|
|
padding-bottom: 0;
|
|
padding-bottom: constant(safe-area-inset-bottom);
|
|
padding-bottom: env(safe-area-inset-bottom);
|
|
|
|
.tabbar-border {
|
|
background-color: rgba(255, 255, 255, 0.329412);
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
width: 100%;
|
|
height: 2rpx;
|
|
-webkit-transform: scaleY(0.5);
|
|
transform: scaleY(0.5);
|
|
}
|
|
|
|
.item {
|
|
display: flex;
|
|
align-items: center;
|
|
-webkit-box-orient: vertical;
|
|
-webkit-box-direction: normal;
|
|
flex: 1;
|
|
flex-direction: column;
|
|
padding-bottom: 10rpx;
|
|
box-sizing: border-box;
|
|
|
|
.bd {
|
|
position: relative;
|
|
height: 100rpx;
|
|
flex-direction: column;
|
|
text-align: center;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
|
|
.icon {
|
|
position: relative;
|
|
display: inline-block;
|
|
margin-top: 10rpx;
|
|
width: 40rpx;
|
|
height: 40rpx;
|
|
font-size: 40rpx;
|
|
line-height: 40rpx;
|
|
|
|
image {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
>view {
|
|
height: inherit;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.bar-icon {
|
|
font-size: 42rpx;
|
|
}
|
|
}
|
|
|
|
.label {
|
|
position: relative;
|
|
text-align: center;
|
|
font-size: 24rpx;
|
|
line-height: 1;
|
|
margin-top: 12rpx;
|
|
}
|
|
}
|
|
|
|
&.bulge {
|
|
.bd {
|
|
position: relative;
|
|
height: 100rpx;
|
|
flex-direction: column;
|
|
text-align: center;
|
|
|
|
.icon {
|
|
margin-top: -60rpx;
|
|
margin-bottom: 4rpx;
|
|
border-radius: 50%;
|
|
width: 100rpx;
|
|
height: 102rpx;
|
|
padding: 10rpx;
|
|
border-top: 2rpx solid #f5f5f5;
|
|
background-color: #fff;
|
|
box-sizing: border-box;
|
|
|
|
image {
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 50%;
|
|
}
|
|
}
|
|
|
|
.label {
|
|
position: relative;
|
|
text-align: center;
|
|
font-size: 24rpx;
|
|
height: 40rpx;
|
|
line-height: 40rpx;
|
|
}
|
|
}
|
|
}
|
|
|
|
.cart-count-mark {
|
|
position: absolute;
|
|
top: -8rpx;
|
|
right: -18rpx;
|
|
width: 24rpx;
|
|
height: 24rpx !important;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
color: #fff;
|
|
padding: 6rpx;
|
|
border-radius: 50%;
|
|
z-index: 99;
|
|
|
|
&.max {
|
|
width: 40rpx;
|
|
border-radius: 24rpx;
|
|
right: -28rpx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.tab-bar-placeholder {
|
|
padding-bottom: calc(constant(safe-area-inset-bottom) + 112rpx);
|
|
padding-bottom: calc(env(safe-area-inset-bottom) + 112rpx);
|
|
}
|
|
</style> |