
這個圖分解成4塊 上左:樓層 上右:基礎數據 下左:固定文字 下右:樓棟
樓層可上下滑動
樓棟可左右滑動
基礎信息可上下左右滑動
樓層scroll-view 與基礎信息scroll-view 上下滑動關聯
樓棟scroll-view 與基礎信息scroll-view 左右滑動關聯
當同時滑動 樓層與基礎信息 並且滑動方向相反就會導致scroll事件的監聽進入死循環導致頁面抖動
為了解決這個問題就設想同時只能滑動一個scroll-view
就寫了三個遮罩層在三個scroll-view上
當 一個scroll-view 觸發了 touchstart 事件其他兩個scroll-view 上面的遮罩層顯示
當 scroll-view 觸發了 touchend 事件三個scroll-view 上面的遮罩層隱藏
這樣就解決了同時觸發兩個@scroll事件進入死循環
<template>
<view :style="'height:' + scrollViewHeight + ';'" id="scroll-v3" class="projectProgress">
<view v-if="isFloorMask" class="floor-mask"></view>
<view v-if="isTableMask" :style="'height:' + tableHeight + ';'" class="table-mask"></view>
<view v-if="isBuildingMask" class="building-mask"></view>
<!-- 樓層和項目構件進度匯總 -->
<view class="floorsTable">
<scroll-view @touchend="hideMask" @touchstart="floorTouchstart" @scroll="floorScrollHandler" scroll-y="true"
:scroll-top="floorScrollTop" :scroll-anchoring="true" style="height: 100%; width: 174rpx">
<view class="floors">
<view class="floorItem" v-for="floor in floorsList" :key="floor">{{ floor }}層</view>
</view>
</scroll-view>
<scroll-view @touchend="hideMask" @touchstart="tableTouchstart" @scroll="tableScrollHandler" scroll-x="true" scroll-y="true"
:scroll-top="tableScrollTop" :scroll-left="tableScrollLeft" :scroll-anchoring="true"
style="height: 100%; width: calc(100vw - 174rpx)">
<view class="allComponents">
<view class="componentTable">
<componentTable v-for="(buildingItem, index) in boardsInfo" :key="index"
:boardsInfo="buildingItem" :floorsList="floorsList">
</componentTable>
</view>
</view>
</scroll-view>
</view>
<!-- 樓棟和構件類型 -->
<view class="projectInfo">
<view class="title"> 項目詳情 </view>
<scroll-view @touchend="hideMask" @touchstart="buildTouchstart" @scroll="buildingScrollHandler" scroll-x="true"
:scroll-left="buildingScrollLeft" :scroll-anchoring="true"
style="width: calc(100vw - 170rpx); height: 196rpx">
<view class="buildingAndType">
<BuildingAndType v-for="(buildingItem, index) in boardsInfo" :key="index"
:building="buildingItem.buildingName" :typeList="buildingItem.typeList">
</BuildingAndType>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import debounce from "@/utils/deBounce.js";
import BuildingAndType from "./BuildingAndType.vue";
import componentTable from "./componentTable.vue";
import {
getBillBoardsList
} from "@/api/project.js";
export default {
name: "ProjectProgress",
components: {
BuildingAndType,
componentTable,
},
props: {
projectId: {
type: Number,
},
},
created() {
this.getBillBoardsList();
},
data() {
return {
tableHeight:'calc(100vh -20px - 44px - 44px - 196rpx)',
isFloorMask: false,
isBuildingMask: false,
isTableMask: false,
scrollViewHeight: "80vh",
floorScrollTop: 0,
tableScrollTop: 0,
tableScrollLeft: 0,
buildingScrollLeft: 0,
floorScrollFunc: false,
tableScrollFunc: false,
buildingScrollFunc: false,
floorTimer: null,
tableTimer: null,
buildingTimer: null,
boardsInfo: [],
floorsList: [],
};
},
mounted() {
uni.getSystemInfo({
success: (resu) => {
this.tableHeight = `calc(100vh - ${resu.statusBarHeight}px - 44px - 44px - 196rpx)`
const query = uni.createSelectorQuery();
query.select("#scroll-v3").boundingClientRect();
query.exec((res) => {
this.scrollViewHeight =
`calc(${resu.windowHeight}px - ${resu.statusBarHeight}px - 44px - 44px)`;
});
},
fail: (res) => {},
});
},
methods: {
hideMask() {
this.isFloorMask = false
this.isBuildingMask = false
this.isTableMask = false
},
initScrollTop(){
this.boardsInfo=[]
this.floorsList=[]
this.floorScrollTop=0
this.tableScrollTop=0
this.tableScrollLeft=0
},
// 獲取項目下看板的信息
getBillBoardsList() {
this.initScrollTop()
uni.showLoading({
title:"加載中"
})
getBillBoardsList(this.projectId).then((responseData) => {
this.boardsInfo = responseData?.data?.data?.buildingUnitVOList;
uni.hideLoading()
if (this.boardsInfo) {
this.floorsListHandler();
}
}).catch(()=>{
uni.hideLoading()
})
},
// 樓層數據匯總處理
floorsListHandler() {
this.floorsList = [];
const floorsList = [];
this.boardsInfo.forEach((boardInfo) => {
Object.keys(boardInfo.floorMap).forEach((floor) => {
if (floorsList.indexOf(floor) === -1) {
floorsList.push(floor);
}
});
});
setTimeout(() => {
this.floorScrollTop = 68 * this.floorsList.length + Math.random();
this.tableScrollTop = this.floorScrollTop;
}, 100);
this.floorsList = floorsList;
},
floorTouchstart() {
this.floorScrollFunc = true;
this.isBuildingMask = true
this.isTableMask = true
},
tableTouchstart() {
this.tableScrollFunc = true;
this.isFloorMask = true
this.isBuildingMask = true
},
buildTouchstart() {
this.buildingScrollFunc = true;
this.isFloorMask = true
this.isTableMask = true
},
floorScrollHandler(e) {
if (this.floorTimer) clearTimeout(this.floorTimer);
if (!this.floorScrollFunc) return;
this.floorTimer = setTimeout(() => {
this.floorScrollFunc = false;
}, 200);
const {
scrollTop
} = e.detail;
this.tableScrollTop = scrollTop;
},
tableScrollHandler(e) {
if (this.tableTimer) clearTimeout(this.tableTimer);
if (!this.tableScrollFunc) return;
this.tableTimer = setTimeout(() => {
this.tableScrollFunc = false;
}, 200);
const {
scrollTop,
scrollLeft
} = e.detail;
this.floorScrollTop = scrollTop;
this.buildingScrollLeft = scrollLeft;
},
buildingScrollHandler(e) {
if (this.buildingTimer) clearTimeout(this.buildingTimer);
if (!this.buildingScrollFunc) return;
this.buildingTimer = setTimeout(() => {
this.buildingScrollFunc = false;
}, 200);
const {
scrollLeft
} = e.detail;
this.tableScrollLeft = scrollLeft;
},
},
};
</script>
<style lang="scss" scoped>
.projectProgress {
height: 100%;
width: 100vw;
background-color: #ffffff;
border-top: 2rpx solid #dfdfdf;
box-sizing: border-box;
.floorsTable {
height: calc(100% - 196rpx);
background-color: #ffffff;
display: flex;
box-sizing: border-box;
.floors {
width: 174rpx;
min-height: 100%;
color: #333333;
font-size: 28rpx;
display: flex;
flex-direction: column-reverse;
.floorItem {
box-sizing: border-box;
height: 68rpx;
width: 100%;
text-align: center;
border-top: 2rpx solid #dfdfdf;
border-right: 2rpx solid #dfdfdf;
border-left: 2rpx solid #dfdfdf;
padding-top: 10rpx;
}
}
.allComponents {
display: flex;
flex-direction: row;
min-width: calc(100vw - 174rpx);
min-height: 100%;
flex-direction: column-reverse;
.componentTable {
display: flex;
}
}
}
.projectInfo {
height: 196rpx;
border: 2rpx solid #dfdfdf;
display: flex;
box-sizing: border-box;
.title {
height: 196rpx;
line-height: 170rpx;
background-color: #f8f8f8;
color: #333333;
font-size: 28rpx;
writing-mode: vertical-lr;
text-align: center;
z-index: 97;
letter-spacing: 8rpx;
border-right: 2rpx solid #dfdfdf;
box-sizing: border-box;
}
.buildingAndType {
display: flex;
}
}
}
.floor-mask {
position: fixed;
width: 174rpx;
height: 100vh;
left: 0;
bottom: 0;
top: 220rpx;
background-color: transparent;
z-index: 999999;
}
.building-mask {
position: fixed;
width: 100vw;
height: 196rpx;
left: 0;
right: 0;
bottom: 0;
background-color: transparent;
z-index: 999999;
}
.table-mask {
position: fixed;
width: calc(100vw-174rpx);
height: calc(100vh-206px);
left: 174rpx;
right: 0;
bottom: 196rpx;
background-color:transparent;
z-index: 999999;
}
</style>
