xx-applets/src/components/cate/cate.vue

270 lines
7.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="component-cate" :style="{ height: wrapHeight + 'px' }">
<view class="menu-wrap">
<scroll-view scroll-y class="tab-view menu-scroll-view" :scroll-top="scrollLeftTop" :enhanced="true" :bounces="false">
<view
class="tab-item"
v-for="(item, index) in data"
:key="index"
:class="[currentLeftIndex == index ? 'tab-item-active' : '']"
@tap.stop="switchMenu(index)"
>
<text class="line-1">{{ item.name }}</text>
</view>
</scroll-view>
<scroll-view
:scroll-top="scrollRightTop"
scroll-y
class="right-box"
@scroll="rightScroll"
:enhanced="true"
:bounces="false"
>
<view class="page-view" :class="[cateType]">
<view
class="class-item"
v-for="(item, index) in data"
:key="index"
:style="{ height: index == data.length - 1 ? wrapHeight + 'px' : 'auto' }"
>
<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"
@changeNumber="changeNumber"
></list-tmpl>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import CateTmpl from "@/components/cate/template/cate";
import ListTmpl from "@/components/cate/template/list";
export default {
name: "component-cate",
data() {
return {
utils: this.$utils,
isReady: false,
leftNodePos: [],
rightNodePos: [],
queryTimer: null,
currentLeftIndex: 0,
wrapHeight: 0,
scrollLeftTop: 0,
scrollRightTop: 0,
menuHeight: 0,
};
},
props: {
cateType: {
type: String,
default: "cate",
},
offsetHeight: {
type: Number,
default: 0,
},
activeId: {
type: [String, Number],
default: 0,
},
data: {
type: Array,
default: [],
},
},
components: {
CateTmpl,
ListTmpl,
},
created() {},
mounted() {
const { windowHeight, statusBarHeight, headerHeight } = getApp().globalData.pageConfig;
// 计算页面内边距------------------------------------------
// #ifndef H5
const bodyPt = statusBarHeight + headerHeight;
// #endif
// #ifdef H5
const bodyPt = 0 + this.$utils.rpx2px(headerHeight * 2);
// #endif
// 计算页面内边距------------------------------------------
const offsetHeight = this.$utils.rpx2px(this.offsetHeight);
// 窗口高度 - 头部高度 - 顶部内容高度 = 分类容器高度
this.wrapHeight = windowHeight - bodyPt - offsetHeight;
// #ifdef H5
// H5窗口高度会计算tabbar高度这里减去
this.wrapHeight -= this.$utils.rpx2px(100);
// #endif
this.menuHeight = this.$utils.rpx2px(100);
},
destroyed() {},
watch: {
/**
* 监听列表数据变化
*/
data() {
this.init().then(() => {
this.isReady = true;
this.reAction();
});
},
/**
* 监听ID变化
*/
activeId() {
if (this.isReady) {
this.reAction();
}
},
},
methods: {
/**
* 执行具体逻辑
*/
reAction() {
this.switchCate(this.activeId);
},
/**
* 初始化列表
*/
init() {
clearTimeout(this.queryTimer);
return new Promise((resolve, reject) => {
const that = this;
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();
}
})
.exec();
}, 200);
});
},
/**
* 更新左侧菜单
*/
updateMenuStatus(index) {
if (index != this.currentLeftIndex) {
this.$emit("onScroll", this.data[index].id);
}
this.currentLeftIndex = index;
this.scrollLeftTop = index * this.menuHeight - this.wrapHeight / 2;
},
/**
* 滚动监听
*/
rightScroll(e) {
let scrollTop = e.detail.scrollTop + 15;
for (let index = 0; index < this.rightNodePos.length; index++) {
let current = this.rightNodePos[index];
let next = this.rightNodePos[index + 1];
if (!next || (scrollTop >= current && scrollTop < next)) {
this.updateMenuStatus(index);
return;
}
}
},
/**
* 选中某项
*/
switchMenu(index) {
this.currentLeftIndex = index;
this.scrollRightTop = this.rightNodePos[index];
},
/**
* 按ID选中
*/
switchCate(id) {
let activeIndex = 0;
this.data.forEach((item, index) => {
if (item.id == id) {
activeIndex = index;
}
});
this.switchMenu(activeIndex);
},
/**
* 点击
*/
clickItem(parentId, id) {
this.$emit("clickItem", parentId, id);
},
/**
* 改变数量
*/
changeNumber(e, id) {
this.$emit("changeNumber", e, id);
},
},
};
</script>
<style lang="less" scoped>
.component-cate {
display: flex;
flex-direction: column;
width: 100%;
.menu-wrap {
flex: 1;
display: flex;
overflow: hidden;
}
.tab-view {
width: 200rpx;
height: 100%;
background-color: #f6f6f6;
.tab-item {
height: 100rpx;
box-sizing: border-box;
padding-left: 20rpx;
display: flex;
align-items: center;
font-size: 26rpx;
font-weight: bold;
color: #8b8b8b;
}
.tab-item-active {
position: relative;
color: #4b65ed;
background: #ffffff;
}
.tab-item-active::before {
content: "";
position: absolute;
border-left: 4px solid #4b65ed;
height: 24rpx;
left: 0;
top: 38rpx;
}
}
.right-box {
width: 550rpx;
.page-view.cate {
padding-right: 16rpx;
}
.page-view.list {
padding-right: 0;
}
.class-item {
background-color: #ffffff;
padding: 36rpx 32rpx 0 32rpx;
}
}
}
</style>