绩效考核手机版
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

300 lines
9.6 KiB

3 years ago
<template>
<view :class="custom_class">
<view v-if="fixed && !immersive" class="s-nav-bar__placeholder" :style="{ height: nav_height + 'px' }"></view>
<view class="s-nav-bar" :class="nav_class" :style="nav_style">
<view class="s-nav-bar__background" :style="background_style"></view>
<view v-if="statusBar" class="s-nav-bar__status-bar" :style="status_bar_style"></view>
<view class="s-nav-bar__container" :style="container_style">
<slot>
<view class="s-nav-bar__content">
<view class="s-nav-bar__left">
<slot name="left">
<view v-if="back" class="s-nav-bar__back" @click="handleBack">
<slot name="back">
<s-button
type="text"
size="custom"
:icon="backIcon"
:icon-size="$addUnit(backIconSize, 'px')"
custom-class="s-nav-bar__back-btn"
:custom-style="backStyle"
>
<view v-if="$isDef(backText)">{{ backText }}</view>
</s-button>
</slot>
</view>
</slot>
</view>
<view class="s-nav-bar__center">
<slot name="center">
<view class="s-nav-bar__title" :class="title_class" :style="title_style">
<slot name="title">
<text v-if="$isDef(title)" class="s-nav-bar__title-text s-ellipsis">{{ title }}</text>
</slot>
</view>
</slot>
</view>
<view class="s-nav-bar__right">
<slot name="right" />
</view>
</view>
</slot>
</view>
</view>
</view>
</template>
<script>
import componentMixin from '../../mixins/componentMixin';
import sUi from '../../index';
/**
* s-nav-bar 导航栏
* @description 自定义导航栏
* @property {Number|String} height 导航栏高度(不包括状态栏高度在内内部自动加上)注意这里的单位是px
* @property {String} background 导航栏背景设置(APP和小程序上包括状态栏的颜色)
* @property {String|Object} backgroundStyle 背景样式
* @property {String} color 导航栏文本颜色
* @property {Boolean} border 底部是否显示下边框默认不显示
* @property {String} borderColor 边框颜色
* @property {Boolean} fixed 导航栏是否固定在顶部默认固定
* @property {Number|String} immersive 沉浸式允许fixed定位后导航栏塌陷仅fixed定位下生效
* @property {Number|String} zIndex 固定在顶部时的z-index值
* @property {String} title 导航栏标题如设置为空字符将会隐藏标题占位区域
* @property {String} titleAlign = [left|center] 标题位置
* @property {Number|String} titleWidth 导航栏标题的最大宽度内容超出会以省略号隐藏单位rpx
* @property {String|Object} titleStyle 标题样式
* @property {Boolean} back 是否显示导航栏左边返回功能
* @property {String} backIcon 左边返回图标的名称只支持s-ui自带的图标
* @property {String} backText 左边返回按钮文字
* @property {Number|String} backIconSize 左边返回图标的大小单位px
* @property {String|Object} backStyle 返回样式
* @property {String} homePath 当没有页面栈记录时默认返回首页路径
* @property {Function} customBack 自定义返回逻辑方法
* @property {Boolean} statusBar 是否预留状态栏高度
* @property {String|Object} statusBarStyle 状态栏样式
* @property {Boolean} rightMenuButton 是否预留右边胶囊菜单宽度
* @property {String} transparent = [none|fade-in|fade-out|always] 导航栏整体前景背景透明设置支持 always 一直透明 / fade-in 从0-1 / fade-out 从1-0 / none 不透明
* @property {Number|String} maxOpacity 导航透明度最大数值
* @property {Number} scrollTop 页面滚动scrollTop用来计算透明度
* @property {Number|String} startTop 开始计算透明度的scrollTop
* @property {Number|String} scrollRatio 滚动计算透明度阈值
* @event {Function} height(height) 高度变动触发单位 px
* @event {Function} opacity(opacity) 透明度改变时触发
* @example <s-nav-bar title="标题" />
*/
export default {
name: 'SNavBar',
mixins: [componentMixin],
props: {
height: {
type: [Number, String],
default: 44,
},
background: String,
backgroundStyle: [String, Object],
color: String,
padding: [Number, String],
border: Boolean,
borderColor: String,
zIndex: [Number, String],
fixed: {
type: Boolean,
default: true,
},
immersive: Boolean,
title: String,
titleAlign: {
type: String,
default: 'center',
},
titleWidth: {
type: [Number, String],
default: 420,
},
titleStyle: [String, Object],
back: Boolean,
backIcon: {
type: String,
default: 'arrow-left',
},
backText: String,
backIconSize: [Number, String],
backStyle: [String, Object],
statusBar: {
type: Boolean,
default: true,
},
statusBarStyle: [String, Object],
rightMenuButton: {
type: Boolean,
default: true,
},
transparent: {
type: String,
default: 'none',
},
minOpacity: {
type: [Number, String],
default: 0,
},
maxOpacity: {
type: [Number, String],
default: 1,
},
scrollTop: {
type: Number,
default: 0,
},
startTop: {
type: [Number, String],
default: 0,
},
scrollRatio: {
type: [Number, String],
default: 0.3,
},
homePath: String,
customBack: Function,
},
data: () => ({
windowWidth: 0,
statusBarHeight: 0,
rightMenuButtonWidth: 0,
opacity: 1,
}),
computed: {
nav_class() {
return this.$mergeClass({
's-nav-bar--fixed': this.fixed,
's-nav-bar--immersive': this.immersive,
's-hairline--bottom': this.border,
});
},
nav_style() {
return this.$mergeStyle({
color: this.color,
borderColor: this.borderColor,
zIndex: this.fixed ? this.zIndex : '',
}, this.custom_style);
},
c_height() {
return parseInt(this.height);
},
nav_height() {
return this.c_height + this.statusBarHeight;
},
status_bar_style() {
return this.$mergeStyle({
height: this.statusBarHeight + 'px',
}, this.statusBarStyle);
},
background_style() {
return this.$mergeStyle({
background: this.background,
}, this.backgroundStyle);
},
container_style() {
return this.$mergeStyle({
height: this.$addUnit(this.c_height, 'px'),
padding: this.$addUnit(this.padding, 'px'),
marginRight: this.$addUnit(this.rightMenuButtonWidth, 'px'),
});
},
title_class() {
return this.$mergeClass({
[`s-nav-bar__title--${this.titleAlign}`]: this.titleAlign,
});
},
title_style() {
const titleWidth = this.$toPx(this.titleWidth);
const style = {};
if (this.titleAlign === 'center') {
const space = parseInt((this.windowWidth - titleWidth) / 2);
style.left = space + 'px';
style.right = (space - this.rightMenuButtonWidth) + 'px';
} else {
style.width = titleWidth + 'px';
}
return this.$mergeStyle(style, this.titleStyle);
},
start_top() {
return this.$toPx(this.startTop);
},
opacity_state() {
return [
this.scrollTop,
this.transparent,
this.start_top,
this.minOpacity,
this.maxOpacity,
];
},
},
watch: {
nav_height() {
this.updateHeight();
},
opacity_state() {
this.refreshOpacity();
},
},
created() {
const systemInfo = uni.getSystemInfoSync();
this.windowWidth = systemInfo.windowWidth;
if (this.statusBar) {
this.statusBarHeight = systemInfo.statusBarHeight;
}
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
if (this.rightMenuButton) {
this.rightMenuButtonWidth = systemInfo.windowWidth - uni.getMenuButtonBoundingClientRect().left;
}
// #endif
this.updateHeight();
this.refreshOpacity();
},
methods: {
updateHeight() {
this.$emit('height', this.nav_height);
},
handleBack() {
const customBack = this.$getPropsFn('customBack');
if (customBack) {
customBack();
} else {
if (getCurrentPages().length > 1) {
uni.navigateBack();
} else {
uni.reLaunch({ url: this.homePath || sUi.config.homePath });
}
}
},
refreshOpacity() {
switch (this.transparent) {
case 'fade-in':
case 'fade-out': {
const scrollTop = Math.max(0, this.scrollTop - this.start_top);
let opacity = scrollTop / (this.windowWidth * Number(this.scrollRatio));
opacity = this.transparent === 'fade-out' ? (1 - opacity) : opacity;
if ((this.opacity >= this.maxOpacity && opacity >= this.maxOpacity) || (this.opacity <= this.minOpacity && opacity <= this.minOpacity)) return;
this.updateOpacity(opacity);
break;
}
case 'always':
this.updateOpacity(0);
break;
default:
this.updateOpacity(1);
break;
}
},
updateOpacity(opacity) {
this.opacity = Math.min(Math.max(opacity, this.minOpacity), this.maxOpacity);
this.$emit('opacity', this.opacity);
},
},
};
</script>
<style lang="scss" src="./index.scss"></style>