You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

250 lines
5.9 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="tui-navigation-bar"
:class="{ 'tui-bar-line': opacity > 0.85 && splitLine, 'tui-navbar-fixed': isFixed, 'tui-backdrop__filter': backdropFilter && dropDownOpacity > 0 }"
:style="{ height: height + 'px', backgroundColor: `rgba(${background},${opacity})`, opacity: dropDownOpacity, zIndex: isFixed ? zIndex : 'auto' }">
<view class="tui-status-bar" :style="{ height: statusBarHeight + 'px' }" v-if="isImmersive"></view>
<view class="tui-navigation_bar-title"
:style="{ opacity: transparent || opacity >= maxOpacity ? 1 : opacity, color: color, paddingTop: top - statusBarHeight + 'px' }"
v-if="title && !isCustom">
{{ title }}
</view>
<slot></slot>
</view>
</template>
<script>
export default {
name: 'tuiNavigationBar',
emits: ['init', 'change'],
props: {
//NavigationBar标题
title: {
type: String,
default: ''
},
//NavigationBar标题颜色
color: {
type: String,
default: '#333'
},
//NavigationBar背景颜色,不支持rgb
backgroundColor: {
type: String,
default: '#fff'
},
//是否需要分割线
splitLine: {
type: Boolean,
default: false
},
//是否设置不透明度
isOpacity: {
type: Boolean,
default: true
},
//不透明度最大值 0-1
maxOpacity: {
type: [Number, String],
default: 1
},
//背景透明 【设置该属性则背景透明只出现内容isOpacity和maxOpacity失效】
transparent: {
type: Boolean,
default: false
},
//滚动条滚动距离
scrollTop: {
type: [Number, String],
default: 0
},
/*
isOpacity 为true时生效
opacity=scrollTop /windowWidth * scrollRatio
*/
scrollRatio: {
type: [Number, String],
default: 0.3
},
//是否自定义header内容
isCustom: {
type: Boolean,
default: false
},
//是否沉浸式
isImmersive: {
type: Boolean,
default: true
},
isFixed: {
type: Boolean,
default: true
},
//是否开启高斯模糊效果[仅在支持的浏览器有效果]
backdropFilter: {
type: Boolean,
default: false
},
//下拉隐藏NavigationBar主要针对有回弹效果ios端
dropDownHide: {
type: Boolean,
default: false
},
//z-index设置
zIndex: {
type: [Number, String],
default: 9998
}
},
watch: {
scrollTop(newValue, oldValue) {
if (this.isOpacity && !this.transparent) {
this.opacityChange();
}
},
backgroundColor(val) {
if (val) {
this.background = this.hexToRgb(val);
}
}
},
data() {
return {
width: 375, //header宽度
left: 375, //小程序端 左侧距胶囊按钮距离
height: 44, //header高度
top: 0,
scrollH: 1, //滚动总高度,计算opacity
opacity: 1, //0-1
statusBarHeight: 0, //状态栏高度
background: '255,255,255', //header背景色
dropDownOpacity: 1
};
},
created() {
this.dropDownOpacity = this.backdropFilter && 0;
this.opacity = this.isOpacity || this.transparent ? 0 : this.maxOpacity;
this.background = this.hexToRgb(this.backgroundColor);
let obj = {};
// #ifdef MP-WEIXIN
obj = wx.getMenuButtonBoundingClientRect();
// #endif
// #ifdef MP-BAIDU
obj = swan.getMenuButtonBoundingClientRect();
// #endif
// #ifdef MP-ALIPAY
my.hideAddToDesktopMenu();
// #endif
uni.getSystemInfo({
success: res => {
this.statusBarHeight = res.statusBarHeight;
this.width = res.windowWidth;
this.left = obj.left || res.windowWidth;
if (this.isImmersive) {
this.height = obj.top ? obj.top + obj.height + 8 : res.statusBarHeight + 44;
}
this.scrollH = res.windowWidth * this.scrollRatio;
this.top = obj.top ? obj.top + (obj.height - 32) / 2 : res.statusBarHeight + 6;
this.$emit('init', {
width: this.width,
height: this.height,
left: this.left,
top: this.top,
statusBarHeight: this.statusBarHeight,
opacity: this.opacity,
windowHeight: res.windowHeight
});
}
});
},
methods: {
hexToRgb(hex) {
let rgb = '255,255,255';
if (hex && ~hex.indexOf('#')) {
if (hex.length === 4) {
let text = hex.substring(1, 4);
hex = '#' + text + text;
}
let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
if (result) {
rgb = `${parseInt(result[1], 16)},${parseInt(result[2], 16)},${parseInt(result[3], 16)}`;
}
}
return rgb;
},
opacityChange() {
if (this.dropDownHide) {
if (this.scrollTop < 0) {
if (this.dropDownOpacity > 0) {
this.dropDownOpacity = 1 - Math.abs(this.scrollTop) / 30;
}
} else {
this.dropDownOpacity = 1;
}
}
let scroll = this.scrollTop <= 1 ? 0 : this.scrollTop;
let opacity = scroll / this.scrollH;
if ((this.opacity >= this.maxOpacity && opacity >= this.maxOpacity) || (this.opacity == 0 && opacity ==
0)) {
return;
}
this.opacity = opacity > this.maxOpacity ? this.maxOpacity : opacity;
if (this.backdropFilter) {
this.dropDownOpacity = this.opacity >= this.maxOpacity ? 1 : this.opacity;
}
this.$emit('change', {
opacity: this.opacity
});
}
}
};
</script>
<style scoped>
.tui-navigation-bar {
width: 100%;
transition: opacity 0.4s;
}
.tui-backdrop__filter {
/* Safari for macOS & iOS */
-webkit-backdrop-filter: blur(15px);
/* Google Chrome */
backdrop-filter: blur(15px);
}
.tui-navbar-fixed {
position: fixed;
left: 0;
top: 0;
}
.tui-status-bar {
width: 100%;
}
.tui-navigation_bar-title {
width: 100%;
font-size: 17px;
line-height: 17px;
/* #ifndef APP-PLUS */
font-weight: 500;
/* #endif */
height: 32px;
display: flex;
align-items: center;
justify-content: center;
}
.tui-bar-line::after {
content: '';
position: absolute;
border-bottom: 1rpx solid #eaeef1;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
bottom: 0;
right: 0;
left: 0;
}
</style>