357 lines
6.7 KiB
Vue
357 lines
6.7 KiB
Vue
<template>
|
|
<view style="width: 100%;" :style="{ height: `calc(${data.statusBarHeight}px + 88rpx)` }">
|
|
<!-- <slot name="statusBar"></slot> -->
|
|
</view>
|
|
<view class="nav-bar-container" :style="{ backgroundColor: bgColor, zIndex: zIndex }">
|
|
<view class="status-placeholder" :style="{ height: `${data.statusBarHeight}px` }">
|
|
<slot name="statusBar"></slot>
|
|
</view>
|
|
<view style="width: 100%;height: 88rpx;" @click="openPopup">
|
|
<slot>
|
|
<uni-nav-bar backgroundColor="#00000000" class="nav-bar" :border="false" :title="title" v-bind="$attrs"
|
|
v-on="$attrs">
|
|
<template v-slot:left>
|
|
<view class="nav-bar-left">
|
|
<slot name="left">
|
|
<view class="left-icon" @click.stop="onBack">
|
|
<image class="nav-icon-back"
|
|
:src="`/static/image/nav-bar/back-${textColor == '#fff' || textColor == '#fffffff' ? 'white' : 'black'}.png`"
|
|
mode="">
|
|
</image>
|
|
</view>
|
|
</slot>
|
|
</view>
|
|
</template>
|
|
<view class="nav-bar-title w100 h100 flex-1" @click="openPopup" :style="{ color: textColor }">
|
|
<slot name="center">
|
|
{{ title }}
|
|
</slot>
|
|
</view>
|
|
<template v-slot:right>
|
|
<view class="nav-bar-right" @click.stop="onRightClick">
|
|
<slot name="right">
|
|
<view v-if="isRightIcon" class="right-icon">
|
|
<image class="nav-icon-more"
|
|
:src="`/static/image/nav-bar/more-${textColor == '#fff' || textColor == '#fffffff' ? 'white' : 'black'}.png`"
|
|
mode="">
|
|
</image>
|
|
</view>
|
|
<view v-if="isRightButton" class="right-button">
|
|
{{ rightButtonText }}
|
|
</view>
|
|
</slot>
|
|
</view>
|
|
</template>
|
|
</uni-nav-bar>
|
|
</slot>
|
|
</view>
|
|
|
|
|
|
<popup ref="topPopup">
|
|
<view class="button-group w100 flex-between flex-wrap">
|
|
<view class="button-box" v-for="(button, index) in buttonGroup" :key="index"
|
|
@click="buttonClick(button)">
|
|
<!-- 使用作用域插槽,允许父组件自定义按钮内容 -->
|
|
|
|
<!-- 默认渲染 -->
|
|
<view class="button flex-align-center flex-justify-center">
|
|
<slot name="button" :button="button" :index="index">
|
|
{{ button.name }}
|
|
<switch v-if="button.isSwitch" :checked="button.value" @change="buttonClick(button)"
|
|
style="transform: scale(0.7);"></switch>
|
|
</slot>
|
|
</view>
|
|
|
|
</view>
|
|
</view>
|
|
</popup>
|
|
|
|
|
|
<view class="tipLayer" :style="{ top: `${45 + data.statusBarHeight}px` }" v-if="isTipLayer && showTipLayer">
|
|
<view class="tipLayer-content">
|
|
<view class="title">
|
|
<slot name="tipLayer">点击此处<text>[{{ tipLayerText }}]</text></slot>
|
|
</view>
|
|
<image class="close" src="/static/image/common/tipLayer-close.png" mode="" @click="closeTipLayer">
|
|
</image>
|
|
<image class="triangleImg" src="/static/image/common/tipLayer-eye.png"></image>
|
|
</view>
|
|
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import popup from '../popup/popup.vue'
|
|
import {
|
|
onMounted,
|
|
reactive,
|
|
ref,
|
|
toRefs
|
|
} from 'vue'
|
|
|
|
const topPopup = ref()
|
|
|
|
// 定义组件属性
|
|
const props = defineProps({
|
|
bgColor: {
|
|
type: String,
|
|
default: '#fff'
|
|
},
|
|
textColor: {
|
|
type: String,
|
|
default: '#000'
|
|
},
|
|
title: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
buttonGroup: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
isRightIcon: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
isRightButton: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
rightButtonText: {
|
|
type: String,
|
|
default: '确定'
|
|
},
|
|
zIndex: {
|
|
type: Number,
|
|
default: 999
|
|
},
|
|
noBack: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
tipLayerText: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
isTipLayer: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
tipLayerType: {
|
|
type: String,
|
|
default: ''
|
|
}
|
|
})
|
|
|
|
// 定义事件
|
|
const emit = defineEmits(['back', 'right-click', 'button-click', 'refresh'])
|
|
|
|
const data = reactive({
|
|
statusBarHeight: 0,
|
|
showTipLayer: true,
|
|
})
|
|
|
|
let {
|
|
showTipLayer
|
|
} = toRefs(data)
|
|
|
|
|
|
onMounted(() => {
|
|
// 同步获取系统信息
|
|
const systemInfo = uni.getSystemInfoSync();
|
|
data.statusBarHeight = systemInfo.statusBarHeight || 0;
|
|
|
|
if (props.isTipLayer) {
|
|
if (uni.getStorageSync(props.tipLayerType) == props.tipLayerType) {
|
|
showTipLayer.value = false
|
|
}
|
|
}
|
|
|
|
})
|
|
|
|
const closeTipLayer = () => {
|
|
showTipLayer.value = false
|
|
uni.setStorageSync(props.tipLayerType, props.tipLayerType)
|
|
emit("refresh")
|
|
}
|
|
|
|
const openPopup = () => {
|
|
if (props.buttonGroup.length > 0) {
|
|
topPopup.value.open()
|
|
}
|
|
}
|
|
|
|
// 返回按钮点击事件
|
|
const onBack = () => {
|
|
emit('back')
|
|
// 默认返回上一页
|
|
if (props.noBack) return
|
|
uni.navigateBack()
|
|
}
|
|
|
|
// 右侧按钮点击事件
|
|
const onRightClick = () => {
|
|
emit('right-click')
|
|
}
|
|
|
|
|
|
const buttonClick = (button) => {
|
|
topPopup.value.close()
|
|
emit('button-click', button)
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
@import "/common/main.css";
|
|
|
|
.nav-bar-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
position: fixed !important;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
z-index: 999;
|
|
}
|
|
|
|
.nav-bar {
|
|
width: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.status-placeholder {
|
|
width: 100%;
|
|
}
|
|
|
|
::v-deep .uni-navbar__content {
|
|
width: 100%;
|
|
}
|
|
|
|
.nav-bar-left {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-start;
|
|
}
|
|
|
|
.nav-icon-back {
|
|
width: 24px;
|
|
height: 24px;
|
|
}
|
|
|
|
.nav-icon-more {
|
|
width: 26px;
|
|
height: 26px;
|
|
}
|
|
|
|
.nav-bar-title {
|
|
flex: 1;
|
|
margin: auto;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 17px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.nav-bar-right {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
.right-button {
|
|
font-size: 12px;
|
|
border-radius: 16px;
|
|
color: #fff;
|
|
text-align: center;
|
|
line-height: 30px;
|
|
height: 30px;
|
|
min-width: 60px;
|
|
background: linear-gradient(90deg, #187AFF 0%, #3295FC 100%);
|
|
}
|
|
|
|
.button-box {
|
|
width: calc(50% - 8rpx);
|
|
text-align: center;
|
|
margin-top: 16rpx;
|
|
}
|
|
|
|
.button {
|
|
border: 1px solid #E4E4E4;
|
|
border-radius: 8px;
|
|
height: 42px;
|
|
line-height: 42px;
|
|
font-size: 28rpx;
|
|
}
|
|
|
|
.tipLayer {
|
|
box-sizing: border-box;
|
|
min-width: 200px !important;
|
|
height: 48px;
|
|
background: #B8EDFE;
|
|
border-radius: 8px 8px 8px 8px;
|
|
position: fixed;
|
|
/* top: 115px; */
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
z-index: 999;
|
|
|
|
|
|
|
|
}
|
|
|
|
.tipLayer-content {
|
|
position: relative;
|
|
|
|
|
|
}
|
|
|
|
.title {
|
|
font-weight: 450;
|
|
font-size: 14px;
|
|
color: #268FFF;
|
|
line-height: 48px;
|
|
text-align: center;
|
|
|
|
text {
|
|
font-size: 14px;
|
|
font-weight: bold;
|
|
color: #006ADD;
|
|
}
|
|
|
|
::v-deep text {
|
|
font-size: 14px;
|
|
font-weight: bold;
|
|
color: #006ADD;
|
|
}
|
|
}
|
|
|
|
.triangleImg {
|
|
width: 111px;
|
|
height: 52px;
|
|
pointer-events: none;
|
|
position: absolute;
|
|
top: -23px;
|
|
left: calc(50% - 111px);
|
|
}
|
|
|
|
.triangle {
|
|
position: absolute;
|
|
top: -57px;
|
|
left: calc(50% - 40px);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.close {
|
|
position: absolute;
|
|
top: -5px;
|
|
right: -5px;
|
|
width: 18px;
|
|
height: 18px;
|
|
}
|
|
</style> |