赞
踩
第一步,页面布局
- <view class="u-wrap">
- <view class="u-menu-wrap">
- <scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop" :scroll-into-view="itemId">
- <view v-for="(item,index) in flist" :key="index" class="u-tab-item" :class="[current == index ? 'u-tab-item-active':'']" @tap.stop="swichMenu(index)">
- <text class="u-line-1">{{item.name}}</text>
- </view>
- </scroll-view>
- <scroll-view scroll-y scroll-with-animation :scroll-top="scrollRightTop" class="right-box" @scroll="rightScroll">
- <view class="page-view">
- <view class="class-item" :id="'item' + index" v-for="(item,index) in slist" :key="index">
- <view class="item-title">
- <text>{{item.name}}</text>
- </view>
- <view class="item-container">
- <view class="thumb-box" v-for="(item1,index1) in item.children" :key="index1" @click="featureC(item1.id)">
- <image :src="item1.img_url" class="item-menu-image" mode=""></image>
- <view class="item-menu-name">{{item1.name}}</view>
- </view>
- </view>
- </view>
-
- </view>
- </scroll-view>
- </view>
- </view>
第二步:css部分,这里就自己写了,按照自己的项目效果图自己调一下效果
第三步:js部分
1、
- data() {
- return {
- scrollTop: 0, //tab标题的滚动条位置
- oldScrollTop: 0, // tab标题的滚动条旧位置
- current: 0, // 预设当前项的值
- menuHeight: 0, // 左边菜单的高度
- menuItemHeight: 0, // 左边菜单item的高度
- itemId: '', // 栏目右边scroll-view用于滚动的id
- scrollRightTop: 0, // 右边栏目scroll-view的滚动条高度
- arr: [], // 储存距离顶部高度的数组
- timer: null, // 定时器
- flist: [], //左侧一级分类
- slist: [] //右侧一级+二级分类,构造可以嵌套的数组结构
-
- }
- },
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);
- })
- },
3、右侧滑动事件
- async rightScroll(e) {
- this.oldScrollTop = e.detail.scrollTop;
- if(this.arr.length == 0) {
- await this.getMenuItemTop();
- }
- if(this.timer) return ;
- if(!this.menuHeight) {
- await this.getElRect('menu-scroll-view', 'menuHeight');
- }
- setTimeout(() => { // 节流
- this.timer = null;
- // scrollHeight为右边菜单垂直中点位置
- // let scrollHeight = e.detail.scrollTop + this.menuHeight / 2;
- // scrollHeight为右边菜单头部位置
- let scrollHeight = e.detail.scrollTop + 20;
- 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 ;
- }
- }
- }, 10)
- },
4、页面初始化时,获取右边每个节点距离顶部的高度,主要用于判断是否滑动,比如右边数据比较少的时候就不会在滑动
- onReady() {
- this.getMenuItemTop()
- },
-
-
- getMenuItemTop() {
- new Promise(resolve => {
- let selectorQuery = uni.createSelectorQuery();
- selectorQuery.selectAll('.class-item').boundingClientRect((rects) => {
- // 如果节点尚未生成,rects值为[](因为用selectAll,所以返回的是数组),循环调用执行
- if(!rects.length) {
- setTimeout(() => {
- this.getMenuItemTop();
- }, 10);
- return ;
- }
- rects.forEach((rect) => {
- // 视情况而定,这里减去rects[0].top,是因为第一项顶部可能不是贴到导航栏(比如有个搜索框的情况)
- // this.arr.push(rect.top - rects[0].top);
- this.arr.push(rect.top)
- resolve();
- })
- }).exec()
- })
- },
5、基础功能函数
- /**
- * 观测元素相交状态
- * 检测右边scroll-view的id为itemxx的元素与right-box的相交状态
- * 如果跟.right-box底部相交,就动态设置左边栏目的活动状态
- */
- async observer() {
- this.tabbar.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('u-tab-item', 'menuItemHeight');
- }
- // 将菜单活动item垂直居中
- this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
- },
-
- /**
- * 获取一个目标元素的高度
- * @elClass 元素的类名
- * @dataVal 储存高度的对象
- */
- getElRect(elClass, dataVal) {
- new Promise((resolve, reject) => {
- const query = uni.createSelectorQuery().in(this);
- query.select('.' + elClass).fields({
- size: true
- }, res => {
- // 如果节点尚未生成,res值为null,循环调用执行
- if (!res) {
- setTimeout(() => {
- this.getElRect(elClass);
- }, 10);
- return;
- }
- this[dataVal] = res.height;
- resolve();
- }).exec();
- })
- },
主要是uniapp操作dom节点的时候不是很方便,核心的实现原理其实跟jq一样
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。