这个图分解成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%; 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%; 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=" 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%; 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 { 174rpx; min-height: 100%; color: #333333; font-size: 28rpx; display: flex; flex-direction: column-reverse; .floorItem { box-sizing: border-box; height: 68rpx; 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- 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; 174rpx; height: 100vh; left: 0; bottom: 0; top: 220rpx; background-color: transparent; z-index: 999999; } .building-mask { position: fixed; 100vw; height: 196rpx; left: 0; right: 0; bottom: 0; background-color: transparent; z-index: 999999; } .table-mask { position: fixed; calc(100vw-174rpx); height: calc(100vh-206px); left: 174rpx; right: 0; bottom: 196rpx; background-color:transparent; z-index: 999999; } </style>