356 lines
9.6 KiB
Vue
356 lines
9.6 KiB
Vue
<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>
|