1.页面滚动组件
<template>
<view class="scroll_top_view">
<scroll-view
class="scroll_view"
@scrolltolower="$emit('scrolltolower', $event)"
@refresherrefresh="$emit('refresherrefresh', $event)"
:refresher-enabled="refresherEnabled"
:refresher-triggered="refresherTriggered"
:refresher-background="refresherBackground"
:refresher-default-style="refresherDefaultStyle"
:scroll-with-animation="scrollWithAnimation"
@scroll="onScroll"
:scroll-top="setScrollTop"
enable-back-to-top
scroll-y>
<slot></slot>
</scroll-view>
<view
v-if="scrollTopVisible"
class="top_btn"
:style="btnStyle"
@click="scrollTo(0)">
<view class="img">
<image src="@/static/images/image/top_btn.png" mode="aspectFill" />
</view>
</view>
</view>
</template>
<script>
/**
* 用于在滚动视图中添加 “返回顶部” 按钮
* 如需其他功能,可在此基础上进行扩展
*/
export default {
data() {
return {
currentScrollTop: 0,
setScrollTop: null,
}
},
props: {
/**
* 滚动多少距离后显示 “返回顶部” 按钮
* true: 保持显示
* false: 不显示
*/
showScrollTop: {
type: [Boolean, Number, String],
default: 50,
},
btnStyle: {
type: [Object, Array, String],
default: '',
},
scrollTop: {
type: Number,
default: 0,
},
refresherEnabled: {
type: Boolean,
default: false,
},
refresherTriggered: {
type: Boolean,
default: false,
},
refresherBackground: {
type: String,
default: '#fff',
},
refresherDefaultStyle: {
type: String,
default: 'black',
},
scrollWithAnimation: {
type: Boolean,
default: true,
},
},
computed: {
scrollTopVisible() {
if (typeof this.showScrollTop === 'boolean') {
return this.showScrollTop;
}
return this.currentScrollTop > parseFloat(this.showScrollTop);
},
},
watch: {
scrollTop(val) {
this.scrollTo(val);
},
},
methods: {
scrollTo(value = 0) {
this.setScrollTop = this.currentScrollTop;
this.$nextTick(() => {
this.setScrollTop = value;
});
},
onScroll(e) {
this.currentScrollTop = e.detail.scrollTop;
this.$emit('scroll', e);
},
},
}
</script>
<style lang="scss" scoped>
.scroll_top_view {
position: absolute;
width: 100%;
height: 100%;
}
.scroll_view {
position: absolute;
width: 100%;
height: 100%;
z-index: 1;
}
.top_btn {
position: absolute;
bottom: 180rpx;
right: 32rpx;
width: 88rpx;
height: 88rpx;
border-radius: 100%;
z-index: 2;
.img {
position: absolute;
left: -18%;
top: -18%;
width: 136%;
height: 136%;
pointer-events: none;
}
image {
width: 100%;
height: 100%;
}
}
</style>
2.通用自定义头部
<template>
<view id="pageHeader"
:style="{ '--status-height': statusBarHeight, '--title-height': headerTitleHeight }">
<!-- 顶部文字 -->
<view v-if="showTitle" class="page_header"
:style="{ 'background': bgColor,'color': textColor,
'border-top': `1px solid ${bgColor}`, 'line-height': `calc(${menuBtnInfo.height + menuBtnInfo.top + 1}px - ${statusBarHeight})`, 'animationDelay': '0.1s' }">
<view v-if="showBack" class="cuIcon-back" @tap="handleReturn" />
<view :style="showBack?'margin-left: 40rpx':''" class="title-line">{{title}}
<view class="btn">
<slot name="btn"></slot>
</view>
</view>
</view>
<view v-else class="page_header" :style="{ 'background': bgColor }" />
<view class="'titleBlank'">
<!-- 占位 -->
</view>
</view>
</template>
<script>
export default {
options: { styleIsolation: 'shared' },
props: {
title: {
// 导航栏标题
type: String,
default: '柳工充换电站云平台'
},
showTitle: {
type: Boolean,
default: true,
},
showBack: {
type: Boolean,
default: false
},
bgColor: {
type: String,
default: '#002D72'
},
textColor: {
type: String,
default: '#fff'
},
useReturnFunc: {
type: Boolean,
default: true
}
},
data() {
return {
value: '',
statusBarHeight: this.StatusBar,
headerTitleHeight: '40px',
menuBtnInfo: {},
blankPadding: '',
}
},
watch: {
searchValue: {
immediate: true,
handler(newVal) {
this.value = newVal;
}
}
},
created() {
const systemInfo = uni.getSystemInfoSync();
this.menuBtnInfo = uni.getMenuButtonBoundingClientRect();
this.statusBarHeight = this.StatusBar ? `${this.StatusBar}px` : `${systemInfo.statusBarHeight}px`;
if(this.showTitle) this.headerTitleHeight = `${this.menuBtnInfo.bottom - this.menuBtnInfo.top + 12}px`;
},
methods: {
handleReturn() {
if(this.useReturnFunc) uni.navigateBack();
else this.$emit('return');
},
getHeaderInfo() {
let domHeight = Number(this.statusBarHeight.slice(0, -2));
domHeight += this.showTitle ? this.menuBtnInfo.bottom - this.menuBtnInfo.top + 12 : 0;
return {
menuBtnInfo: this.menuBtnInfo,
statusBarHeight: Number(this.statusBarHeight.slice(0, -2)),
totalHeight: domHeight,
uint: 'px'
}
}
}
}
</script>
<style lang="scss" scoped>
$uni-primary: #002D72;
/* 自定义头部相关 */
$statusBarHeight: var(--status-height, 20px); // 头部状态栏高度
$headerTitleHeight: var(--title-height, 40px);
#pageHeader{
z-index: 999;
}
.page_header{
z-index: 999;
position: fixed;
width: 100vw;
}
.page_header{
padding-left: 16px;
font-size: 20px;
text-align: left;
top: 0;
left: 0;
padding-top: $statusBarHeight;
height: calc(var(--status-height, 20px) + var(--title-height, 40px));
view{
line-height: inherit;
}
}
.page_header [class^="cuIcon-"] {
display: inline-block;
}
.page_header .cuIcon-back{
position: absolute;
left: 20rpx;
cursor: pointer;
}
.titleBlank{
padding-top: calc(var(--status-height, 20px) + var(--title-height, 0px));
// padding-top: calc(var(--title-height, 0px));
}
.title-line{
display: flex;
align-items: center;
justify-content: space-between;
.btn{
margin-right: 200rpx;
}
}
</style>
3.使用
<template>
<view class="page">
<scroll-top-view
:refresher-triggered="refresherTriggered"
@refresherrefresh="refreshPage"
refresher-background="#008df7"
refresher-default-style="white"
refresher-enabled>
<view class="wrapper">
<view class="bg"></view>
<pageHeader title="工作台" bgColor="transparent" />
<view class="appli_wrapper">
<TodayWarning ref="TodayWarning" />
<EnterMachine ref="EnterMachine" />
<MachineType ref="MachineType" />
<RateBarStats ref="RateBarStats" />
<OilStats ref="OilStats" />
<CommonApplication ref="CommonApplication" />
</view>
</view>
</scroll-top-view>
</view>
</template>
<script>
import CommonApplication from './components/CommonApplication.vue'
import TodayWarning from './components/TodayWarning.vue'
import EnterMachine from './components/EnterMachine.vue'
import MachineType from './components/MachineType.vue'
import RateBarStats from './components/RateBarStats.vue'
import OilStats from './components/OilStats.vue'
export default {
components: {
CommonApplication,
TodayWarning,
EnterMachine,
MachineType,
RateBarStats,
OilStats,
},
data() {
return {
refresherTriggered: false,
}
},
mounted() {
this.init()
},
methods: {
async init() {
await this.$nextTick()
this.$modal.loading('加载中...')
await Promise.all([
this.$refs.CommonApplication?.init?.(),
this.$refs.TodayWarning?.init?.(),
this.$refs.EnterMachine?.init?.(),
this.$refs.MachineType?.init?.(),
this.$refs.RateBarStats?.init?.(),
this.$refs.OilStats?.init?.(),
]).finally(() => {
this.$modal.closeLoading()
})
},
async refreshPage() {
this.refresherTriggered = true
await this.init().catch(() => { })
this.refresherTriggered = false
},
}
}
</script>
<style lang="scss" scoped>
.page {
position: relative;
height: 100vh;
background-color: #f2f7ff;
}
.bg {
position: absolute;
top: 0;
width: 100%;
height: 450rpx;
background: linear-gradient(180deg, #008df7 0, #f2f7ff 450rpx);
}
.wrapper {
padding-bottom: calc(100rpx + env(safe-area-inset-bottom) / 2);
box-sizing: border-box;
/deep/ .page_header {
position: absolute !important;
}
}
.appli_wrapper {
flex: 1;
margin-top: 10rpx;
padding-bottom: 32rpx;
}
</style>