204 lines
4.9 KiB
Vue
204 lines
4.9 KiB
Vue
<template>
|
||
<!-- PC 大屏不支持自定义顶栏,留给微信拖拽区;标题写到系统导航栏 -->
|
||
<view v-if="!pcMode" class="tn">
|
||
<view class="tn-fixed" :class="'tn--' + mode" :style="barStyle">
|
||
<view class="tn-status" :style="statusStyle" />
|
||
<view class="tn-inner" :style="innerStyle">
|
||
<view class="tn-left" @tap="onBack">
|
||
<u-icon v-if="showBack" name="arrow-left" :color="text" size="20" />
|
||
</view>
|
||
<text class="tn-title" :style="{ color: text }">{{ title }}</text>
|
||
<view class="tn-right">
|
||
<slot name="right" />
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="tn-ph" :style="phStyle" />
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import { getActiveLayout, getActiveVars } from '@/utils/theme'
|
||
import { isPcWeixin } from '@/utils/device'
|
||
|
||
/**
|
||
* 自定义顶栏:色跟主题 token,形态跟 chrome.navbar
|
||
*/
|
||
export default {
|
||
name: 'ThemeNavbar',
|
||
props: {
|
||
title: { type: String, default: '' },
|
||
showBack: { type: Boolean, default: true },
|
||
},
|
||
data() {
|
||
return {
|
||
statusBarHeight: 20,
|
||
innerHeight: 44,
|
||
// 量不到胶囊时按常见胶囊宽度让开,避免右侧按钮被挡住
|
||
capsulePadRight: 96,
|
||
mode: 'solid',
|
||
surface: '#ffffff',
|
||
text: '#1C1917',
|
||
border: '#E7DFD3',
|
||
}
|
||
},
|
||
computed: {
|
||
pcMode() {
|
||
return isPcWeixin()
|
||
},
|
||
navHeight() {
|
||
return this.statusBarHeight + this.innerHeight
|
||
},
|
||
barStyle() {
|
||
return {
|
||
background: this.surface,
|
||
borderColor: this.border,
|
||
}
|
||
},
|
||
statusStyle() {
|
||
return {
|
||
height: this.statusBarHeight + 'px',
|
||
}
|
||
},
|
||
/** 占位跟固定栏同高,用像素避免 env(safe-area) 在安卓微信为 0 时切内容 */
|
||
phStyle() {
|
||
return {
|
||
height: this.navHeight + 'px',
|
||
width: '100%',
|
||
}
|
||
},
|
||
innerStyle() {
|
||
return {
|
||
height: this.innerHeight + 'px',
|
||
paddingRight: this.capsulePadRight + 'px',
|
||
}
|
||
},
|
||
},
|
||
watch: {
|
||
title: {
|
||
immediate: true,
|
||
handler(val) {
|
||
this.syncPcTitle(val)
|
||
},
|
||
},
|
||
},
|
||
created() {
|
||
this.measure()
|
||
this.pullTheme()
|
||
this.syncPcTitle(this.title)
|
||
},
|
||
mounted() {
|
||
// 部分机型 created 时 statusBarHeight 还是 0,挂载后再量一次
|
||
this.measure()
|
||
},
|
||
beforeUpdate() {
|
||
this.pullTheme()
|
||
},
|
||
methods: {
|
||
measure() {
|
||
try {
|
||
const sys = uni.getSystemInfoSync()
|
||
this.statusBarHeight = sys.statusBarHeight || 20
|
||
const menu = uni.getMenuButtonBoundingClientRect && uni.getMenuButtonBoundingClientRect()
|
||
if (menu && menu.height) {
|
||
this.innerHeight = (menu.top - this.statusBarHeight) * 2 + menu.height
|
||
const winW = Number(sys.windowWidth) || 375
|
||
this.capsulePadRight = Math.max(8, Math.round(winW - menu.left + 8))
|
||
}
|
||
} catch (err) {
|
||
this.statusBarHeight = 20
|
||
this.innerHeight = 44
|
||
}
|
||
},
|
||
pullTheme() {
|
||
const vars = getActiveVars() || {}
|
||
const chrome = ((getActiveLayout() || {}).chrome) || {}
|
||
this.mode = chrome.navbar || 'solid'
|
||
this.surface = vars['--color-surface'] || '#ffffff'
|
||
this.text = vars['--color-text'] || '#1C1917'
|
||
this.border = vars['--color-border'] || '#E7DFD3'
|
||
this.syncPcBarColor()
|
||
},
|
||
/** 系统导航栏底色跟主题表面色对齐,避免 PC 顶栏发灰 */
|
||
syncPcBarColor() {
|
||
if (!isPcWeixin()) return
|
||
const bg = this.surface || '#ffffff'
|
||
uni.setNavigationBarColor({
|
||
frontColor: '#000000',
|
||
backgroundColor: bg,
|
||
})
|
||
},
|
||
/** PC 走系统导航栏,动态标题(如编辑地址)要写过去 */
|
||
syncPcTitle(val) {
|
||
if (!isPcWeixin() || !val) return
|
||
uni.setNavigationBarTitle({ title: String(val) })
|
||
},
|
||
onBack() {
|
||
if (!this.showBack) return
|
||
const pages = getCurrentPages()
|
||
if (pages.length > 1) {
|
||
uni.navigateBack({ delta: 1 })
|
||
return
|
||
}
|
||
uni.switchTab({ url: '/pages/goods/index' })
|
||
},
|
||
},
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.tn {
|
||
display: block;
|
||
width: 100%;
|
||
}
|
||
.tn-ph {
|
||
display: block;
|
||
width: 100%;
|
||
overflow: hidden;
|
||
}
|
||
.tn-fixed {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 200;
|
||
}
|
||
.tn--line {
|
||
border-bottom: 1rpx solid;
|
||
}
|
||
.tn-inner {
|
||
display: flex;
|
||
align-items: center;
|
||
position: relative;
|
||
padding-left: 16rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
.tn-left {
|
||
width: 80rpx;
|
||
flex-shrink: 0;
|
||
z-index: 1;
|
||
}
|
||
.tn-right {
|
||
width: auto;
|
||
min-width: 80rpx;
|
||
flex-shrink: 0;
|
||
margin-left: auto;
|
||
z-index: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
}
|
||
.tn-title {
|
||
position: absolute;
|
||
left: 160rpx;
|
||
right: 160rpx;
|
||
text-align: center;
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
pointer-events: none;
|
||
}
|
||
</style>
|