重新实现分类组件逻辑

This commit is contained in:
TOP糯米 2023-03-09 01:40:16 +08:00
parent 35b5535a97
commit d39cc6a2fb
1 changed files with 87 additions and 154 deletions

View File

@ -1,20 +1,13 @@
<template> <template>
<view class="component-cate" :style="{ height: wrapHeight + 'px' }"> <view class="component-cate" :style="{ height: wrapHeight + 'px' }">
<view class="menu-wrap"> <view class="menu-wrap">
<scroll-view <scroll-view scroll-y class="tab-view menu-scroll-view" :scroll-top="scrollLeftTop" :enhanced="true" :bounces="false">
scroll-y
class="tab-view menu-scroll-view"
:scroll-top="scrollTop"
:scroll-into-view="itemId"
:enhanced="true"
:bounces="false"
>
<view <view
class="tab-item" class="tab-item"
v-for="(item, index) in data" v-for="(item, index) in data"
:key="index" :key="index"
:class="[current == index ? 'tab-item-active' : '']" :class="[currentLeftIndex == index ? 'tab-item-active' : '']"
@tap.stop="swichMenu(index)" @tap.stop="switchMenu(index)"
> >
<text class="line-1">{{ item.name }}</text> <text class="line-1">{{ item.name }}</text>
</view> </view>
@ -32,9 +25,8 @@
<view <view
class="class-item" class="class-item"
v-for="(item, index) in data" v-for="(item, index) in data"
:id="'item' + index"
:key="index" :key="index"
:style="{ height: index == data.length - 1 ? wrapHeight + utils.rpx2px(110) + 'px' : 'auto' }" :style="{ height: index == data.length - 1 ? wrapHeight + 'px' : 'auto' }"
> >
<cate-tmpl v-if="cateType === 'cate'" :parentId="item.id" :data="item" @clickItem="clickItem"></cate-tmpl> <cate-tmpl v-if="cateType === 'cate'" :parentId="item.id" :data="item" @clickItem="clickItem"></cate-tmpl>
<list-tmpl v-if="cateType === 'list'" :parentId="item.id" :data="item" @clickItem="clickItem"></list-tmpl> <list-tmpl v-if="cateType === 'list'" :parentId="item.id" :data="item" @clickItem="clickItem"></list-tmpl>
@ -53,18 +45,16 @@ export default {
data() { data() {
return { return {
utils: this.$utils, utils: this.$utils,
scrollTop: 0, //tab isReady: false,
oldScrollTop: 0, // tab
current: 0, // leftNodePos: [],
menuHeight: 0, // rightNodePos: [],
menuItemHeight: 50, // item queryTimer: null,
itemId: "", // scroll-viewid currentLeftIndex: 0,
arr: [], //
scrollRightTop: 0, // scroll-view
wrapHeight: 0, wrapHeight: 0,
// ID scrollLeftTop: 0,
timer: null, scrollRightTop: 0,
activeIndex: 0, menuHeight: 0,
}; };
}, },
props: { props: {
@ -91,7 +81,6 @@ export default {
}, },
created() {}, created() {},
mounted() { mounted() {
this.getMenuItemTop();
const { windowHeight, statusBarHeight, headerHeight } = getApp().globalData.pageConfig; const { windowHeight, statusBarHeight, headerHeight } = getApp().globalData.pageConfig;
// ------------------------------------------ // ------------------------------------------
// #ifndef H5 // #ifndef H5
@ -108,163 +97,107 @@ export default {
// H5tabbar // H5tabbar
this.wrapHeight -= this.$utils.rpx2px(100); this.wrapHeight -= this.$utils.rpx2px(100);
// #endif // #endif
this.menuHeight = this.$utils.rpx2px(100);
}, },
destroyed() {}, destroyed() {},
watch: {
/**
* 监听列表数据变化
*/
data() {
this.init().then(() => {
this.isReady = true;
this.reAction();
});
},
/**
* 监听ID变化
*/
activeId() {
if (this.isReady) {
this.reAction();
}
},
},
methods: { methods: {
getElRect(elClass, dataVal) { /**
new Promise((resolve, reject) => { * 执行具体逻辑
const query = uni.createSelectorQuery().in(this); */
query reAction() {
.select("." + elClass) this.switchCate(this.activeId);
.fields( },
{ /**
size: true, * 初始化列表
}, */
(res) => { init() {
// resnull clearTimeout(this.queryTimer);
if (!res) { return new Promise((resolve, reject) => {
// this.getElRect(elClass); const that = this;
return; this.queryTimer = setTimeout(() => {
that.rightNodePos = [];
let query = uni.createSelectorQuery().in(that);
query
.selectAll(".class-item")
.boundingClientRect((result) => {
if (result.length > 0) {
result.forEach((item) => {
that.rightNodePos.push(item.top - result[0].top);
});
resolve();
} }
this[dataVal] = res.height; })
resolve(); .exec();
} }, 200);
)
.exec();
}); });
}, },
/** /**
* 获取右边菜单每个item到顶部的距离 * 更新左侧菜单
* 储存到 arr 数组里面用于后面滚动判断
*/ */
getMenuItemTop() { updateMenuStatus(index) {
new Promise((resolve) => { this.currentLeftIndex = index;
let selectorQuery = uni.createSelectorQuery().in(this); this.scrollLeftTop = index * this.menuHeight - this.wrapHeight / 2;
selectorQuery
.selectAll(".class-item")
.boundingClientRect((rects) => {
// rects[](selectAll)
if (!rects.length) {
// this.getMenuItemTop();
return;
}
rects.forEach((rect) => {
// rects[0].top()
this.arr.push(rect.top - rects[0].top);
// this.arr.push(rect.top)
resolve();
});
})
.exec();
});
}, },
/** /**
* 观测元素相交状态 * 滚动监听
* 检测右边scroll-view的id为itemxx的元素与right-box的相交状态
* 如果跟.right-box底部相交就动态设置左边栏目的活动状态
*/ */
async observer() { rightScroll(e) {
this.data.map((val, index) => { let scrollTop = e.detail.scrollTop + 15;
let observer = uni.createIntersectionObserver(this); for (let index = 0; index < this.rightNodePos.length; index++) {
observer let current = this.rightNodePos[index];
.relativeTo(".right-box", { let next = this.rightNodePos[index + 1];
top: 0, if (!next || (scrollTop >= current && scrollTop < next)) {
}) this.updateMenuStatus(index);
.observe("#item" + index, (res) => {
if (res.intersectionRatio > 0) {
let id = res.id.substring(4);
this.leftMenuStatus(id);
}
});
});
},
/**
* 设置左边菜单的滚动状态
* @index 传入的 ID
*/
async leftMenuStatus(index) {
this.current = index;
// 0
if (this.menuHeight == 0 || this.menuItemHeight == 0) {
await this.getElRect("menu-scroll-view", "menuHeight");
await this.getElRect("component-tab-item", "menuItemHeight");
}
// item
this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
},
/**
* 点击左边的栏目切换
* @index 传入的 ID
*/
async swichMenu(index) {
if (this.arr.length == 0) {
await this.getMenuItemTop();
}
if (index == this.current) return;
this.scrollRightTop = this.oldScrollTop;
this.$nextTick(function () {
this.scrollRightTop = this.arr[index];
this.current = index;
this.leftMenuStatus(index);
});
},
/**
* 右边菜单滚动
* 如果不存在height2意味着数据循环已经到了最后一个设置左边菜单为最后一项即可
*/
async rightScroll(e) {
this.oldScrollTop = e.detail.scrollTop;
if (this.arr.length == 0) {
await this.getMenuItemTop();
}
if (!this.menuHeight) {
await this.getElRect("menu-scroll-view", "menuHeight");
}
// scrollHeight
// let scrollHeight = e.detail.scrollTop + this.menuHeight / 2;
// scrollHeight
let scrollHeight = e.detail.scrollTop + 15;
for (let i = 0; i < this.arr.length; i++) {
let height1 = this.arr[i];
let height2 = this.arr[i + 1];
if (!height2 || (scrollHeight >= height1 && scrollHeight < height2)) {
this.leftMenuStatus(i);
return; return;
} }
} }
}, },
/**
* 选中某项
*/
switchMenu(index) {
this.currentLeftIndex = index;
this.scrollRightTop = this.rightNodePos[index];
},
/** /**
* 按ID选中 * 按ID选中
*/ */
async switchCate(id) { switchCate(id) {
if (this.arr.length == 0) { let activeIndex = 0;
await this.getMenuItemTop();
}
this.data.forEach((item, index) => { this.data.forEach((item, index) => {
if (item.id == id) { if (item.id == id) {
this.activeIndex = index; activeIndex = index;
} }
}); });
this.swichMenu(this.activeIndex); this.switchMenu(activeIndex);
}, },
/**
* 点击
*/
clickItem(parentId, id) { clickItem(parentId, id) {
this.$emit("clickItem", parentId, id); this.$emit("clickItem", parentId, id);
}, },
}, },
watch: {
activeId(activeId) {
this.switchCate(activeId);
},
arr(arr) {
clearTimeout(this.timer);
if (this.activeIndex > 0) {
const that = this;
this.timer = setTimeout(() => {
that.scrollRightTop = arr[that.activeIndex];
}, 200);
}
},
},
}; };
</script> </script>