0


uniapp —— 实现左右联动商品分类页面

uniapp —— 实现左右联动商品分类页面

零、前因

我们在日常的开发种,这种页面在项目当中经常会用得到,所以本篇文章会比较注重描述其思路,顺带附上其代码,以便以后在任何代码环境下都能使用上,先介绍一下实现思路:

  1. 点击左侧类别,右侧会跳转到对应的分类;
  2. 右侧滚动到顶部区域,左侧自动高亮对应的类别。

要求就这么多,可以先看下效果如何:
效果

一、搭建结构

**重点:使用uniapp的

scroll-view

组件,如果是小程序原生开发也是这个组件;其次如果是

html

开发,就自己实现一个溢出滚动。**

废话不多说,上代码:

<template><viewclass="u-wrap"><viewclass="u-menu-wrap"><scroll-viewscroll-yscroll-with-animationclass="u-tab-view menu-scroll-view":scroll-top="scrollTop":scroll-into-view="itemId"><viewv-for="(item,index) in tabbar":key="index"class="u-tab-item":class="[current == index ? 'u-tab-item-active' : '']"@tap.stop="swichMenu(index)"><textclass="u-line-1">{{item.name}}</text></view></scroll-view><scroll-view:scroll-top="scrollRightTop"scroll-yscroll-with-animationclass="right-box"@scroll="rightScroll"><viewclass="page-view"><viewclass="class-item":id="'item' + index"v-for="(item , index) in tabbar":key="index"><viewclass="item-title"><text>{{item.name}}</text></view><viewclass="item-container"><viewclass="thumb-box"v-for="(item1, index1) in item.foods":key="index1"@click="featureC(item1.cat, item1.name)"><imagev-if="item1.icon != ''"class="item-menu-image":src="item1.icon"mode=""></image><viewv-elseclass="item-menu-image row-c"style="background-color: #F4F6F8;"><textstyle="font-size: 20rpx;color: #d0d0d0;">加载失败</text></view><viewclass="item-menu-name">{{item1.name}}</view></view></view></view></view></scroll-view></view></view></template>

JavaScript业务逻辑代码:

data(){return{scrollTop:0,//tab标题的滚动条位置oldScrollTop:0,// tab标题的滚动条旧位置current:0,// 预设当前项的值menuHeight:0,// 左边菜单的高度menuItemHeight:0,// 左边菜单item的高度itemId:'',// 栏目右边scroll-view用于滚动的idtabbar:JSON.parse(uni.getStorageSync('categroy')),// 渲染的数据,放在最后供你们测试arr:[],// 储存距离顶部高度的数组scrollRightTop:0,// 右边栏目scroll-view的滚动条高度timer:null// 定时器}}

CSS代码:

.u-wrap{/* #ifdef H5 */height:calc(100vh - var(--window-top));/* #endif */display: flex;flex-direction: column;height: 100vh;}.u-search-box{padding: 18rpx 30rpx;}.u-menu-wrap{flex: 1;display: flex;overflow: hidden;}.u-tab-view{width: 200rpx;height: 100%;}.u-tab-item{height: 110rpx;background: #f6f6f6;box-sizing: border-box;display: flex;align-items: center;justify-content: center;font-size: 26rpx;color: #444;font-weight: 400;line-height: 1;}.u-tab-item-active{position: relative;color: #06A446;font-size: 30rpx;font-weight: 500;background: #D6FFE7;}.u-tab-item-active::before{content:"";position: absolute;border-left: 4px solid #06A446;height: 52rpx;left: 0;top: 29rpx;}.u-tab-view{height: 100%;}.right-box{background-color:rgb(250, 250, 250);}.page-view{padding: 16rpx;}.class-item{margin-bottom: 30rpx;background-color: #fff;padding: 16rpx;border-radius: 8rpx;}.class-item:last-child{min-height: 100vh;}.item-title{font-size: 26rpx;color: $u-main-color;font-weight: bold;}.item-menu-name{margin-top: 8rpx;font-weight: normal;font-size: 24rpx;color: $u-main-color;}.item-container{display: flex;flex-wrap: wrap;}.thumb-box{width: 33.333333%;display: flex;align-items: center;justify-content: center;flex-direction: column;margin-top: 20rpx;}.item-menu-image{width: 120rpx;height: 120rpx;}

二、添加逻辑层业务

  1. 分别获取左侧和右侧每一个类别的高度

我们知道,在

uniapp

里面没有

window

对象和

dom

元素,所以如果我们要获取页面上的一些节点信息时,需要通过

uni.createSelectorQuery()

这个API来获取,这里不再赘述。—— 《传送地址》

/**
* 获取一个目标元素的高度
* @elClass 元素的类名
* @dataVal 储存高度的对象
*/methods:{getElRect(elClass, dataVal){newPromise((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();})}}
  1. 计算右侧每个分类距离顶部的高度并保存
onReady(){this.getMenuItemTop()},mehods:{/**
    * 获取右边菜单每个item到顶部的距离
    * 储存到 arr 数组里面用于后面滚动判断
    */getMenuItemTop(){newPromise(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()})},}
  1. 监听右侧元素滚动时交互的状态

节点布局交叉状态 API 可用于监听两个或多个组件节点在布局位置上的相交状态。这一组API常常可以用于推断某些节点是否可以被用户看见、有多大比例可以被用户看见。这里也不再赘述,不懂的直接阅读文档 —— 《传送地址》

methods:{/**
    * 观测元素相交状态
    * 检测右边scroll-view的id为itemxx的元素与right-box的相交状态
    * 如果跟.right-box底部相交,就动态设置左边栏目的活动状态
    */asyncobserver(){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
    */asyncleftMenuStatus(index){this.current = index;// 如果为0,意味着尚未初始化if(this.menuHeight ==0||this.menuItemHeight ==0){awaitthis.getElRect('menu-scroll-view','menuHeight');awaitthis.getElRect('u-tab-item','menuItemHeight');}// 将菜单活动item垂直居中this.scrollTop = index *this.menuItemHeight +this.menuItemHeight /2-this.menuHeight /2;}}
  1. 实现左侧菜单点击联动右侧滚动
methods:{/**
    * 点击左边的栏目切换
    * @index 传入的 ID
    */asyncswichMenu(index){if(this.arr.length ==0){awaitthis.getMenuItemTop();}if(index ==this.current)return;this.scrollRightTop =this.oldScrollTop;this.$nextTick(function(){this.scrollRightTop =this.arr[index];this.current = index;this.leftMenuStatus(index);})},}
  1. 实现右侧菜单滚动联动左侧高亮
methods:{/**
    * 右边菜单滚动
    * 如果不存在height2,意味着数据循环已经到了最后一个,设置左边菜单为最后一项即可
    */asyncrightScroll(e){this.oldScrollTop = e.detail.scrollTop;if(this.arr.length ==0){awaitthis.getMenuItemTop();}if(this.timer)return;if(!this.menuHeight){awaitthis.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)}}

三、最后tabbar数据

[{"name":"蔬菜水果","foods":[{"cat":383,"name":"蔬菜","icon":"http://nq348.com/uploads/category/20220315/1aeed6fa43b54cd68cce0c4883160f91.png","key":"蔬菜"},{"cat":384,"name":"食用菌","icon":"http://nq348.com/uploads/category/20220418/09839c618b35b510d50151f9a17793ee.png","key":"食用菌"},{"cat":385,"name":"水果","icon":"http://nq348.com/uploads/category/20220418/5294ad2fc7effc9629cbfdb8baf41773.png","key":"水果"}]},{"name":"畜禽养殖","foods":[{"cat":388,"name":"禽类","icon":"http://nq348.com/uploads/category/20220418/da31895fc5a9aacf93fea6f27f08afd7.png","key":"禽类"},{"cat":389,"name":"畜类","icon":"http://nq348.com/uploads/category/20220418/6352081e3f3b36f9360a933676e9452c.png","key":"畜类"},{"cat":391,"name":"蛋类","icon":"http://nq348.com/uploads/category/20220418/d2e7ab4224679c0c796ba3ddd8a68e2f.png","key":"蛋类"},{"cat":390,"name":"水产","icon":"http://nq348.com/uploads/category/20220418/52a1f1baa7617ef4d4e1a4b344b2fce7.png","key":"水产"}]},{"name":"粮油副食","foods":[{"cat":393,"name":"米面粮油","icon":"http://nq348.com/uploads/category/20220418/1bb32e319ecf5aa352b7fe26fc265004.png","key":"米面粮油"},{"cat":394,"name":"坚果干果","icon":"http://nq348.com/uploads/category/20220418/6ded13eae4a3b113b5225ca8b99bbfdd.png","key":"坚果干果"},{"cat":395,"name":"加工食品","icon":"http://nq348.com/uploads/category/20220418/1e1c10838799de5834aa77f0f9eb8f40.png","key":"加工食品"},{"cat":396,"name":"茶烟酒","icon":"http://nq348.com/uploads/category/20220418/c43cd994e49023c7efdf2b18b1bca30b.png","key":"茶烟酒"}]},{"name":"花卉苗木","foods":[{"cat":398,"name":"鲜花盆景","icon":"http://nq348.com/uploads/category/20220418/b21c44045daaa8b8d148981ba9efc2e0.png","key":"鲜花盆景"},{"cat":399,"name":"果树苗","icon":"http://nq348.com/uploads/category/20220418/63ee2b902ff0f4d638d8a5ad770f7641.png","key":"果树苗"},{"cat":400,"name":"蔬瓜种子","icon":"http://nq348.com/uploads/category/20220418/2df521877616ee44fd01aae0434a5815.png","key":"蔬瓜种子"},{"cat":401,"name":"经济作物","icon":"http://nq348.com/uploads/category/20220418/f85be72a98694befd889f30de45a1d64.png","key":"经济作物"}]},{"name":"中草药材","foods":[{"cat":403,"name":"全草类","icon":"http://nq348.com/uploads/category/20220418/01812c1a83f5db7eafbf3bdae927f134.png","key":"全草类"},{"cat":405,"name":"根茎皮叶花","icon":"http://nq348.com/uploads/category/20220418/dca8dcc814401474d4f19ae7394cc209.png","key":"根茎皮叶花"},{"cat":406,"name":"滋补品类","icon":"http://nq348.com/uploads/category/20220418/33b965295811fdd6f5e672e9a3ce34a2.png","key":"滋补品类"},{"cat":404,"name":"果实籽仁类","icon":"http://nq348.com/uploads/category/20220418/1dc8c46c66b4625d458a7f45787ecef9.png","key":"果实籽仁类"}]},{"name":"其他","foods":[{"cat":434,"name":"包装","icon":"http://nq348.com/uploads/category/20220418/ebdfd326333344825adbe81dbd89e2c9.png","key":"包装"},{"cat":435,"name":"安全溯源","icon":"http://nq348.com/uploads/category/20220418/03230c63f066f46005abf5f576df0ed1.png","key":"安全溯源"},{"cat":436,"name":"农用百货","icon":"http://nq348.com/uploads/category/20220418/93393f2df3264faba86bb449a0c10a79.png","key":"农用百货"},{"cat":437,"name":"仓储物流","icon":"http://nq348.com/uploads/category/20220418/f553505ebabbcb1bf762b288716cf1e7.png","key":"仓储物流"}]}]
标签: 前端 javascript

本文转载自: https://blog.csdn.net/LizequaNNN/article/details/124433574
版权归原作者 vk阿木 所有, 如有侵权,请联系我们删除。

“uniapp —— 实现左右联动商品分类页面”的评论:

还没有评论