uniapp的双联滚动案例

双联滚动在做商城时经常会用到

本例采用左右scrollview组件实现双联滚动

效果图如下

本例右部采用单排显示,感觉效果比双排好,可完整显示图片,以及不会因为标题长短不一出现显示不美观

注意部分组件为自定义组件,您可以删除或更换自己的组件,本例仅为示例代码。

<template>
    <view class="bg color-555">
	<mo-nav isBarHeight>
		<view class="flex flex-row bgColor-whites flex-items-center" @click="$mo.pageto('/pagesA/shop/carlists')">
			<view class="headbtn flex flex-row">
				<mo-icon name="gouwuche" size="20"></mo-icon>
			</view>
			<view class="marlr10">购物车</view>
		</view>
	</mo-nav>
			<view class="mo-wrap">
			
			    <view class="mo-search-box">
			    	<mo-search v-model="sotext" bgColor="#ffffff" @search="soso" @confirm="soso"></mo-search>
			    </view>
			    <view class="mo-menmo-wrap">
			        <scroll-view scroll-y scroll-with-animation class="mo-tab-view menmo-scroll-view bg" :scroll-top="scrollTop">
			            <view v-for="(item,index) in categoryBox" :key="index" class="mo-tab-item" 
						 :class="[current==index ? 'mo-tab-item-active' : '']"
			             @tap.stop="swichMenu(index)">
			                <text class="flex-wrap any-font-size-14">{
   
   {item.name}}</text>
						</view>
						<mo-gap :gap="60"></mo-gap> 
			        </scroll-view>
			
			        <scroll-view scroll-y scroll-with-animation class="right-box flex-1" :scroll-top="scrollRightTop" @scroll="rightScroll">
			            <view class="page-view">
			                <view class="class-item" :id="'item' + index" 
							v-for="(item , index) in categoryBox" :key="index">
			                    <view class="item-title">
									<view v-if="item.thumb" class="width-bb"
									 @click="item.click>0?$mo.pageto('/pagesA/shop/listso?id='+item.id):''">
								<image :src="$comjs.api.uploadsUrl+item.thumb" mode="widthFix" class="width-bb" style="height: auto;"></image>		
									</view>
			                        <view class="any-font-size-14" @click="item.click>0?$mo.pageto('/pagesA/shop/listso?id='+item.id):''">{
   
   {item.name}}</view>
			                    </view>
			                    
				<view v-for="(items,indexs) in item.data" :key="indexs">
					<view class="martb10 flex flex-row  flex-items-center" @click="$mo.pageto('/pagesA/shop/show?id='+items.id+'&catid='+items.catid)">
							<view>
								<image :src="items.thumb?$comjs.api.uploadsUrl+items.thumb:'../../static/300.png'" mode="aspectFill" class="thumb"></image>
							</view>
							<view class="flex flex-column flex-1 any-padding-10">
								<view class="any-font-size-12 flex-wrap">{
   
   {items.title}}</view>
								<view class="flex flex-between martb10">
									<view class="color-red">
										<text class="any-font-size-14">¥</text>
										<text class="any-font-size-16">{
   
   {items.money}}</text>
									</view>
									<view class="text-right">
										<mo-icon name="shaogouwu" size="20"></mo-icon>
									</view>
								</view>
							</view>
							
					</view>
				</view>
				<view v-if="!item.data.length" class="martb10 text-center color-ccc">- 暂无商品 -</view>
				<view v-else-if="item.data.length>=6&&item.click>0" class="martb10 text-center"
				 @click="$mo.pageto('/pagesA/shop/listso?id='+item.id)">查看更多</view>
				 <mo-gap :gap="10"></mo-gap>
				<mo-divider></mo-divider>
				
			                </view>
			            </view> 
						<mo-gap :gap="60"></mo-gap>
			        </scroll-view>
			
			    </view>
			    <!-- tabbar占位高度 -->
		
			</view>
			<mo-loading ref="loading"></mo-loading>
    </view>
</template>

<script>
var num = 0;
var dsq = null;

export default {
    components: {

    },
    data() {
        return {
            //systemInfo:base.systemInfo,
            isPopup:false,
            PrimaryColor:'#fe461d',//主题色
            categoryBox:[],//分类商品
            current: 0,
            scrollTop:0,
            specGoodsData:{},//选择的规格数据
            
            // ***滑动联动所需参数***
            oldScrollTop: 0,
            current: 0, // 预设当前项的值
            menuHeight: 0, // 左边菜单的高度
            menuItemHeight: 0, // 左边菜单item的高度
            itemId: '', // 栏目右边scroll-view用于滚动的id
            menuItemPos: [],
            arr: [],
            scrollRightTop: 0, // 右边栏目scroll-view的滚动高度
            timer: null, // 定时器
            flag:false,//禁止current两次赋值
            flag2:true,//是否禁止右侧滑动
            c_id:'',//跳转的参数--定位分类id位置
			sotext:''
        }
    },
    onLoad(e) {
        // this.c_id = e.c_id
    	//this.c_id = 9 //跳转的参数--定位分类id位置
        
    },
    onReady() {
    	this.getMenuItemTop()
    },
    onShow(){
		let that=this;
		//加载药品列表
		this.getgoodsList()
		
    	// #ifndef MP-ALIPAY
    	num = 0;
    	this.DSQ()
    	// #endif
    },
    methods: {
		soso(){
			let that=this;
			that.$comjs.pageto("/pagesA/shop/listso",{},function(res){
				res.eventChannel.emit('sotext', { sotext:that.sotext})
			});
		},
        getgoodsList() {
			let that=this;
			that.$comjs.http(that,that.$comjs.api.shop,{},false,redata=>{
				that.categoryBox=redata.data;
				// 如果有传分类c_id参数-滑动到对应的选项
				if(that.sotext){
					let currItem=that.categoryBox.find(item=>{
						return item.data.find(items=>{
							return items.name==that.sotext;
						})		
					})
					if(currItem){
						console.log(currItem,11111)
						that.c_id=currItem.id;
						that.categoryBox.forEach((item,index)=>{
						    if(item.id == that.c_id){
						        let time =500 //实际接口这里数字可以调小点
						        // 等待页面渲染完成
						        setTimeout(()=>{
						            if(index>=2){
						                that.swichMenu(index-1)
						            }
						        },time) 
						        setTimeout(()=>{
						            that.swichMenu(index)
						        },time+200)
						    }
						})
					}
				}
				
			});
        },
        // 点击左边的栏目切换
        async swichMenu(index) {
            console.log('swichMenu')
            // #ifdef MP-ALIPAY
            if(index == this.current) return ;
            this.current = index;
            // 如果为0,意味着尚未初始化
            if(this.menuHeight == 0 || this.menuItemHeight == 0) {
                await this.getElRect('menmo-scroll-view', 'menuHeight');
                await this.getElRect('mo-tab-item', 'menuItemHeight');
            }
            // 将菜单菜单活动item垂直居中
            this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
            // #endif
            // #ifndef MP-ALIPAY
            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.flag = true
                this.flag2 = false //禁止右侧滑动
                this.leftMenuStatus(index);
                num = 0
            })
            // #endif
        },
        DSQ(isClear){
            // 解决点击分类,左侧多次滚动
            dsq && clearInterval(dsq)
            dsq = setInterval(()=>{
                num+=100
                if(num>500){
                    this.flag2 = true
                }
                // console.log(num)
            },100)
        },
        // 获取一个目标元素的高度
        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;
                }).exec();
            })
        },
        // ***********************************************  微信小程序 S  *****************************************************************
        // 设置左边菜单的滚动状态
        async leftMenuStatus(index) {
            console.log('左侧滚动')
            // #ifndef MP-ALIPAY
            if(this.flag){
                this.current = index;
                this.flag = false
                console.log(index)
            }
            // 如果为0,意味着尚未初始化
            if (this.menuHeight == 0 || this.menuItemHeight == 0) {
                await this.getElRect('menmo-scroll-view', 'menuHeight');
                await this.getElRect('mo-tab-item', 'menuItemHeight');
            }
            console.log(this.menuHeight,'this.menuHeight')
            console.log(this.menuItemHeight,'this.menuItemHeight')
            // 将菜单活动item垂直居中
            this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
            // #endif
        },
        // 获取右边菜单每个item到顶部的距离
        getMenuItemTop() {
            // #ifndef MP-ALIPAY
            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);
                        resolve();
                    })
                }).exec()
            })
            // #endif
        },
        // 右边菜单滚动
        async rightScroll(e) {
            // #ifndef MP-ALIPAY
            if(this.flag2 && !this.flag){
                 console.log('右侧滚动')
                this.oldScrollTop = e.detail.scrollTop;
                if(this.arr.length == 0) {
                    await this.getMenuItemTop();
                }
                if(this.timer) return ;
                if(!this.menuHeight) {
                    await this.getElRect('menmo-scroll-view', 'menuHeight');
                }
                setTimeout(() => { // 节流
                    this.timer = null;
                    // scrollHeight为右边菜单垂直中点位置
                    let scrollHeight = e.detail.scrollTop + this.menuHeight / 2;
                    for (let i = 0; i < this.arr.length; i++) {
                        let height1 = this.arr[i];
                        let height2 = this.arr[i + 1];
                        // 如果不存在height2,意味着数据循环已经到了最后一个,设置左边菜单为最后一项即可
                        if (!height2 || scrollHeight >= height1 && scrollHeight < height2) {
                            this.flag = true
                            this.leftMenuStatus(i);
                            return ;
                        }
                    }
                }, 10)
            }
            // #endif
        },
        // ***********************************************  微信小程序 E  *****************************************************************
    },

}
</script>

<style lang="scss" scoped>
.headbtn {
	border-radius: 20px;
	margin-left: 15px;
}

.bg {
	background: #edf4f7;
}	
.leftque{color:red;display: inline-block;margin-right:2px;border-radius:50%;background-color: #fff;border:1px solid red;width:10px;height:10px;padding:2px;}
.mo-wrap {
    height: calc(100vh);
    /* #ifdef H5 */
    height: calc(100vh - var(--window-top));
    /* #endif */
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: column;
}
.mo-search-box {
    padding: 0rpx 20rpx 15rpx 20rpx;
	margin-top:140rpx;
}
.mo-search-inner {
    background-color: #f5f5f5;
    border-radius: 100rpx;
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    align-items: center;
    padding: 10rpx 16rpx;
}
.mo-search-text {
    color: #999;
    margin-left: 10rpx;
}

.mo-menmo-wrap {
    flex: 1;
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    overflow: hidden;
	
}
.mo-tab-view {
	width: 160rpx;
    height: 100%;
}
.mo-tab-item {
    width: 160rpx;
    // height: 110rpx;
    padding:15px 8px;
    box-sizing: border-box;
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    align-items: center;
    font-weight: 400;
    line-height: 1;
    position: relative;
	z-index: 10;
    .cartNumber{
        position: absolute;
		z-index: 10;
        border-radius: 34rpx;
        top: 8rpx;
        right: 8rpx;
        // width: 34rpx;
        padding: 0 10rpx;
        height: 34rpx;
        line-height: 34rpx;
        background: #508c22;
        color: #fff;
    }
    text{
        line-height: 1.2;
    }
}
.mo-tab-item-active {
    position: relative;
	z-index: 10;
 
    color:#333;
    background: #fff;
    .title{
        color: #D54F4F
    }
}
.mo-tab-item-active::before {
    content: "";
    position: absolute;
	z-index: 10;
    border-left: 4rpx solid #D54F4F;
    height: 32rpx;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
}
.mo-tab-view {
    height: 100%;
}
.right-box {
    /* #ifdef MP-ALIPAY */
   
    /* #endif */
    /* #ifndef MP-ALIPAY */
   
    /* #endif */
	.thumb{width:68px;height:68px;border-radius:8px;}
}
.page-view {
    // padding: 16rpx;
}
.class-item {
    // margin-bottom: 30rpx;
    background-color: #fff;
    padding:10px 5px;
    border-radius: 8rpx;
    /* #ifndef MP-ALIPAY */
    padding-bottom: 20rpx;
    /* #endif */
}
.item-title {
    color: #333;
    text{
        color: #999;
    }
}
.item-menmo-name {
    font-weight: normal;
    color: #333;
}
.item-container {
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-wrap: wrap;
}
</style>

基本VUE3,兼容VUE2的UI组件正在开发中,届时免费提供大家使用

以下为正在使用本组件的一只个人项目管理小程序案例

猜你喜欢

转载自blog.csdn.net/qq_41589481/article/details/125848858
今日推荐