<template>
    <view class="component-wrap" :style="{ height: wrapHeight + 'px' }">
        <view class="component-menu-wrap">
            <scroll-view
                scroll-y
                class="component-tab-view menu-scroll-view"
                :scroll-top="scrollTop"
                :scroll-into-view="itemId"
                :enhanced="true"
                :bounces="false"
            >
                <view
                    class="component-tab-item"
                    v-for="(item, index) in data"
                    :key="index"
                    :class="[current == index ? 'component-tab-item-active' : '']"
                    @tap.stop="swichMenu(index)"
                >
                    <text class="component-line-1">{{ item.name }}</text>
                </view>
            </scroll-view>
            <scroll-view
                :scroll-top="scrollRightTop"
                scroll-y
                scroll-with-animation
                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"
                        :id="'item' + index"
                        :key="index"
                        :style="{ height: index == data.length - 1 ? wrapHeight + $utils.rpx2px(110) + 'px' : 'auto' }"
                    >
                        <cate-tmpl v-if="cateType === 'cate'" :data="item" @clickItem="clickItem"></cate-tmpl>
                        <list-tmpl v-if="cateType === 'list'" :data="item" @clickItem="clickItem"></list-tmpl>
                    </view>
                </view>
            </scroll-view>
        </view>
    </view>
</template>

<script>
import { mapState } from "vuex";
import CateTmpl from "@/components/cate/template/cate";
import ListTmpl from "@/components/cate/template/list";
export default {
    name: "component-cate",
    data() {
        return {
            scrollTop: 0, //tab标题的滚动条位置
            oldScrollTop: 0, // tab标题的滚动条旧位置
            current: 0, // 预设当前项的值
            menuHeight: 0, // 左边菜单的高度
            menuItemHeight: 50, // 左边菜单item的高度
            itemId: "", // 栏目右边scroll-view用于滚动的id
            arr: [], // 储存距离顶部高度的数组
            scrollRightTop: 0, // 右边栏目scroll-view的滚动条高度
            timer: null, // 定时器
            wrapHeight: 0,
        };
    },
    props: {
        cateType: {
            type: String,
            default: "cate",
        },
        offsetHeight: {
            type: Number,
            default: 0,
        },
        data: {
            type: Array,
            default: [],
        },
    },
    components: {
        CateTmpl,
        ListTmpl,
    },
    computed: {
        ...mapState({
            config: (state) => state.system.config,
        }),
    },
    created() {},
    mounted() {
        this.getMenuItemTop();
        const { windowHeight, statusBarHeight, headerHeight } = this.config;
        // 计算页面内边距------------------------------------------
        // #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.switchCate(5);
    },
    destroyed() {},
    methods: {
        getElRect(elClass, dataVal) {
            new Promise((resolve, reject) => {
                const query = uni.createSelectorQuery().in(this);
                query
                    .select("." + elClass)
                    .fields(
                        {
                            size: true,
                        },
                        (res) => {
                            // 如果节点尚未生成，res值为null，循环调用执行
                            if (!res) {
                                this.getElRect(elClass);
                                return;
                            }
                            this[dataVal] = res.height;
                            resolve();
                        }
                    )
                    .exec();
            });
        },
        /**
         * 获取右边菜单每个item到顶部的距离
         * 储存到 arr 数组里面用于后面滚动判断
         */
        getMenuItemTop() {
            new Promise((resolve) => {
                let selectorQuery = uni.createSelectorQuery().in(this);
                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() {
            this.data.map((val, index) => {
                let observer = uni.createIntersectionObserver(this);
                observer
                    .relativeTo(".right-box", {
                        top: 0,
                    })
                    .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;
                }
            }
        },
        switchCate(id) {
            let idx = 0;
            this.data.forEach((item, index) => {
                if (item.id == id) {
                    idx = index;
                }
            });
            this.swichMenu(idx);
        },
        clickItem(id) {
            this.$emit("clickItem", id);
        },
    },
};
</script>

<style lang="less" scoped>
.component-wrap {
    display: flex;
    flex-direction: column;
    width: 100%;
}
.component-search-box {
    padding: 18rpx 30rpx;
}
.component-menu-wrap {
    flex: 1;
    display: flex;
    overflow: hidden;
}
.component-tab-view {
    width: 200rpx;
    height: 100%;
    background-color: #f6f6f6;
}
.component-tab-item {
    height: 100rpx;
    box-sizing: border-box;
    padding-left: 20rpx;
    display: flex;
    align-items: center;
    font-size: 24rpx;
    color: #8b8b8b;
    font-weight: 400;
    line-height: 1;
}
.component-tab-item-active {
    position: relative;
    color: #4b65ed;
    background: #ffffff;
}
.component-tab-item-active::before {
    content: "";
    position: absolute;
    border-left: 4px solid #4b65ed;
    height: 24rpx;
    left: 0;
    top: 38rpx;
}
.component-tab-view {
    height: 100%;
}
.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>