yunshangxie/tuniao-ui/components/tn-nav-bar/tn-nav-bar.vue

356 lines
9.6 KiB
Vue
Raw Permalink Normal View History

2023-12-25 17:56:30 +08:00
<template>
<view
class="tn-custom-nav-bar-class tn-custom-nav-bar"
:style="[navBarStyle]"
>
<view
class="tn-custom-nav-bar__bar"
:class="[barClass]"
:style="[barStyle]"
>
<view v-if="isBack">
<view v-if="customBack">
<view
:style="{
width: customBackStyleInfo.width + 'px',
height: customBackStyleInfo.height + 'px',
marginLeft: customBackStyleInfo.left + 'px'
}"
>
<slot name="back"></slot>
</view>
</view>
<view v-else class="tn-custom-nav-bar__bar__action" @tap="handlerBack">
<text class="tn-custom-nav-bar__bar__action--nav-back" :class="[`tn-icon-${backIcon}`]"></text>
<text class="tn-custom-nav-bar__bar__action--nav-back-text" v-if="backTitle">{{ backTitle }}</text>
</view>
</view>
<view class="tn-custom-nav-bar__bar__content" :style="[contentStyle]">
<slot></slot>
</view>
<view>
<slot name="right"></slot>
</view>
</view>
</view>
</template>
<script>
import componentsColorMixin from '../../libs/mixin/components_color.js'
export default {
name: 'tn-nav-bar',
mixins: [componentsColorMixin],
props: {
// 层级
zIndex: {
type: Number,
default: 0
},
// 导航栏的高度
height: {
type: Number,
default: 0
},
// 高度单位
unit: {
type: String,
default: 'px'
},
// 是否显示返回按钮
isBack: {
type: Boolean,
default: true
},
// 返回按钮的图标
backIcon: {
type: String,
default: 'left'
},
// 返回按钮旁显示的文字
backTitle: {
type: String,
default: '返回'
},
// 透明状态栏
alpha: {
type: Boolean,
default: false
},
// 是否固定在顶部
fixed: {
type: Boolean,
default: true
},
// 是否显示底部阴影
bottomShadow: {
type: Boolean,
default: true
},
// 是否自定义返回按钮
customBack: {
type: Boolean,
default: false
},
// 返回前回调
beforeBack: {
type: Function,
default: null
}
},
computed: {
navBarStyle() {
let style = {}
style.height = this.height === 0 ? this.customBarHeight + this.unit : this.height + this.unit
if (this.fixed) {
style.position = 'fixed'
}
style.zIndex = this.elZIndex
return style
},
barClass() {
let clazz = ''
if (this.backgroundColorClass) {
clazz += ` ${this.backgroundColorClass}`
}
if (this.fontColorClass) {
clazz += `${this.fontColorClass}`
}
if (this.fixed) {
clazz += ' tn-custom-nav-bar__bar--fixed'
}
if (this.alpha) {
clazz += ' tn-custom-nav-bar__bar--alpha'
}
if (this.bottomShadow) {
clazz += ' tn-custom-nav-bar__bar--bottom-shadow'
}
return clazz
},
barStyle() {
let style = {}
style.height = this.height === 0 ? this.customBarHeight + this.unit : this.height + this.unit
if (this.fixed) {
style.paddingTop = this.statusBarHeight + 'px'
}
if(!this.backgroundColorClass) {
style.backgroundColor = this.backgroundColor !== '' ? this.backgroundColor : '#FFFFFF'
}
if (!this.fontColorClass && this.fontColor) {
style.color= this.fontColor
}
style.zIndex = this.elZIndex
return style
},
contentStyle() {
let style = {}
style.top = this.fixed ? this.statusBarHeight + 'px' : '0px'
style.height = this.height === 0 ? (this.customBarHeight - this.statusBarHeight) + this.unit : this.height + this.unit
style.lineHeight = style.height
if (this.isBack) {
if (this.customBack) {
const width = (this.customBackStyleInfo.width + this.customBackStyleInfo.left) * 2
style.width = `calc(100% - ${width}px)`
} else {
style.width = 'calc(100% - 340rpx)'
}
} else {
style.width = '100%'
}
return style
},
elZIndex() {
return this.zIndex ? this.zIndex : this.$tn.zIndex.navbar
}
},
data() {
return {
// 状态栏的高度
statusBarHeight: 0,
// 自定义导航栏的高度
customBarHeight: 0,
// 自定义返回按钮时,返回容器的宽高边距信息
customBackStyleInfo: {
width: 86,
height: 32,
left: 15
}
}
},
mounted() {
// 获取vuex中的自定义顶栏的高度
this.updateNavBarInfo()
},
created() {
// 获取胶囊信息
// #ifdef MP-WEIXIN
let custom = wx.getMenuButtonBoundingClientRect()
this.customBackStyleInfo.width = custom.width
this.customBackStyleInfo.height = custom.height
this.customBackStyleInfo.left = uni.upx2px(750) - custom.right
// #endif
},
methods: {
// 更新导航栏的高度
async updateNavBarInfo() {
// 获取vuex中的自定义顶栏的高度
let customBarHeight = this.vuex_custom_bar_height
let statusBarHeight = this.vuex_status_bar_height
// 如果获取失败则重新获取
if (!customBarHeight) {
try {
const navBarInfo = await this.$tn.updateCustomBar()
customBarHeight = navBarInfo.customBarHeight
statusBarHeight = navBarInfo.statusBarHeight
} catch(e) {
setTimeout(() => {
this.updateNavBarInfo()
}, 10)
return
}
}
// 更新vuex中的导航栏信息
this && this.$tn.vuex('vuex_status_bar_height', statusBarHeight)
this && this.$tn.vuex('vuex_custom_bar_height', customBarHeight)
this.customBarHeight = customBarHeight
this.statusBarHeight = statusBarHeight
},
// 处理返回事件
async handlerBack() {
if (this.beforeBack && typeof(this.beforeBack) === 'function') {
// 执行回调,同时传入索引当作参数
// 在微信,支付宝等环境(H5正常)会导致父组件定义的函数体中的this变成子组件的this
// 通过bind()方法绑定父组件的this让this的this为父组件的上下文
let beforeBack = this.beforeBack.bind(this.$tn.$parent.call(this))()
// 判断是否返回了Promise
if (!!beforeBack && typeof beforeBack.then === 'function') {
await beforeBack.then(res => {
// Promise返回成功
this.navBack()
}).catch(err => {})
} else if (beforeBack === true) {
this.navBack()
}
} else {
this.navBack()
}
},
// 返回上一页
navBack() {
// 通过判断当前页面的页面栈信息,是否有上一页进行返回,如果没有则跳转到首页
const pages = getCurrentPages()
if (pages && pages.length > 0) {
const firstPage = pages[0]
if (pages.length == 1 && (!firstPage.route || firstPage.route != 'pages/index/index')) {
uni.reLaunch({
url: '/pages/index/index'
})
} else {
uni.navigateBack({
delta: 1
})
}
} else {
uni.reLaunch({
url: '/pages/index/index'
})
}
}
}
}
</script>
<style lang="scss" scoped>
.tn-custom-nav-bar {
display: block;
position: relative;
&__bar {
display: flex;
position: relative;
align-items: center;
min-height: 100rpx;
justify-content: space-between;
min-height: 0px;
/* #ifdef MP-WEIXIN */
padding-right: 220rpx;
/* #endif */
/* #ifdef MP-ALIPAY */
padding-right: 150rpx;
/* #endif */
box-shadow: 0rpx 0rpx 0rpx;
z-index: 9999;
&--fixed {
position: fixed;
width: 100%;
top: 0;
}
&--alpha {
background: transparent !important;
box-shadow: none !important;
}
&--bottom-shadow {
box-shadow: 0rpx 0rpx 80rpx 0rpx rgba(0, 0, 0, 0.05);
}
&__action {
display: flex;
align-items: center;
height: 100%;
justify-content: center;
max-width: 100%;
&--nav-back {
/* position: absolute; */
/* top: 50%; */
/* left: 20rpx; */
/* margin-top: -15rpx; */
// width: 25rpx;
// height: 25rpx;
margin-left: 20rpx;
font-size: 38rpx;
line-height: 100%;
// border-width: 0 0 4rpx 4rpx;
// border-color: #000000;
// border-style: solid;
// transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
}
&--nav-back-text {
margin-left: 10rpx;
}
}
&__content {
position: absolute;
text-align: center;
left: 0;
right: 0;
bottom: 0;
margin: auto;
font-size: 32rpx;
cursor: none;
// pointer-events: none;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
}
</style>