余姚企业网站建设全国最大的关键词挖掘
商品双向联动列表的使用
电商app中,商品双向联动列表是非常常见的。
类似于这样的:
dcloud插件市场是有现成的插件的,是黄河爱浪同学写的。。。
商品双向联动列表插件 地址:https://ext.dcloud.net.cn/plugin?id=707
目前我没有详细调整样式,因为UI图还在修改中,最终实现的效果不是很好看,但是基本功能都是有的:
接口的数据是前端模拟的,后续会根据接口自行调整数据。
另外如果某个商品选择数量时,如果有不同的规格,则需要在底部弹窗进行规格的展示,然后选择规格后再加入购物车。这个目前还没有处理。后续会完善。
代码如下:
<view class="swiperCon"><view class="scroll-panel" id="scroll-panel"><view class="list-box"><view class="left"><scroll-view scroll-y="true" :style="{ 'height':scrollHeight+'px' }":scroll-into-view="leftIntoView":scroll-with-animation="true"><view class="item" v-for="(item,index) in leftArray":key="index" :class="{ 'active':index==leftIndex }" :id="'left-'+index":data-index="index"@tap="leftTap">{{item}}</view></scroll-view></view><view class="main"><view class="mainCate"><scroll-view scroll-x class="nav z" scroll-with-animation :scroll-left="mainCateScrollLeft"><text class="cu-item" v-for="(item,index) in goodsCate" :key="index" :class="mainCateIndex==index?'select':''" @click="toSelectCate(item,index,$event)">{{item}}</text></scroll-view></view><swiper class="swiper" :style="{ 'height':scrollHeight - 20 +'px'}":current="leftIndex" @change="panelSwiperChange"vertical="true" duration="300"><swiper-item v-for="(item,index) in mainArray" :key="index"><scroll-view scroll-y="true" :style="{ 'height':scrollHeight - 20 +'px' }"><view class="item"><view class="title"><view>{{item.title}}</view></view><view class="goods" v-for="(item2,index2) in item.list" :key="index2" @click="toDetail(item2)"><image src="/static/logo.png" mode=""></image><view class="goods-right"><view>第{{index2+1}}个商品标题</view><view class="describe">第{{index2+1}}个商品的描述内容</view><view class="money" style="position: relative;" @click.stop><text>第{{index2+1}}个价格</text><uni-number-box class="step":min="1"style="position: absolute;right:40upx;":max="item2.stock || 1000":value="item2.number>item2.stock?item2.stock:item2.number":isMax="item2.number>=item2.stock?true:false":isMin="item2.number===1":disabled="true":index="index2"@eventChange="numberChange"></uni-number-box></view></view></view></view></scroll-view></swiper-item></swiper></view></view></view>
</view>
script部分代码:
import uniNumberBox from '@/components/uni-number-box.vue' // 加减数字组件
export default {data() {return {scrollHeight:400,leftArray:[],mainArray:[],leftIndex:0,goodsCate:[],mainCateIndex:0,mainCateScrollLeft:0}},components:{uniNumberBox},computed: {leftIntoView(){return `left-${this.leftIndex > 5 ? (this.leftIndex-5):0}`;}},mounted(){/* 等待DOM挂载完成 */this.$nextTick(()=>{/* 在非H5平台,nextTick回调后有概率获取到错误的元素高度,则添加200ms的延迟来减少BUG的产生 */setTimeout(()=>{/* 等待滚动区域初始化完成 */this.initScrollView().then(()=>{/* 获取列表数据,你的代码从此处开始 */this.getListData();})},200);})},onLoad(){this.goodsCate = ["薯片","巧克力","薯片","巧克力","薯片","巧克力","薯片","巧克力"];},methods:{// scroll-view 实现 横线标签的滑动展示toSelectCate(item, index, e) {this.mainCateIndex = index;this.mainCateScrollLeft = (index - 1) * 60;},// 数字组件改变数字numberChange(data){console.log(data.number);},/* 初始化滚动区域 */initScrollView(){return new Promise((resolve, reject)=>{let view = uni.createSelectorQuery().select('#scroll-panel');view.boundingClientRect(res => {this.scrollHeight = res.height;this.$nextTick(()=>{resolve();})}).exec();});},/* 获取列表数据 */ // 此处可以通过自己的接口进行数据覆盖getListData(){// Promise 为 ES6 新增的API ,有疑问的请自行学习该方法的使用。new Promise((resolve,reject)=>{/* 因无真实数据,当前方法模拟数据。正式项目中将此处替换为 数据请求即可 */uni.showLoading();setTimeout(()=>{/* 因无真实数据,当前方法模拟数据 */let [left,main]=[[],[]];for(let i=0;i<25;i++){left.push(`${i+1}类商品`);let list=[];let max = Math.floor(Math.random()*15) || 8;for(let j=0;j<max;j++){list.push(j);}main.push({title:`第${i+1}类商品标题`,list})}// 将请求接口返回的数据传递给 Promise 对象的 then 函数。resolve({left,main});},1000);}).then((res)=>{console.log('-----------请求接口返回数据示例-------------');console.log(res);uni.hideLoading();this.leftArray=res.left;this.mainArray=res.main;});},/* 左侧导航点击 */leftTap(e){let index=e.currentTarget.dataset.index;this.leftIndex=Number(index);},/* 轮播图切换 */panelSwiperChange(e){let index=e.detail.current;this.leftIndex=Number(index);},}
css样式部分:
.swiperCon{height: 100%;display: flex;margin-bottom:40upx;flex-direction: column;flex-wrap: nowrap;justify-content: flex-start;align-items: flex-start;align-content: flex-start;&>view{width: 100%;}.scroll-panel{flex-grow: 1;height: 0;overflow: hidden;.list-box{display: flex;flex-direction: row;flex-wrap: nowrap;justify-content: flex-start;align-items: flex-start;align-content: flex-start;font-size: 28rpx;.left{width: 200rpx;background-color: #f6f6f6;line-height: 80rpx;box-sizing: border-box;font-size: 32rpx;.item{padding-left: 20rpx;position: relative;&:not(:first-child) {margin-top: 1px;&::after {content: '';display: block;height: 0;border-top: #d6d6d6 solid 1px;width: 620upx;position: absolute;top: -1px;right: 0;transform:scaleY(0.5); /* 1px像素 */}}&.active,&:active{color: #42b983;background-color: #fff;}}}.main{background-color: #fff;padding-left: 20rpx;width: 0;flex-grow: 1;box-sizing: border-box;.mainCate{display: flex;.nav{display: flex;white-space: nowrap;border:1px solid red;.cu-item{padding:6upx 10upx;&.select{background:red;color:#fff;}}}}.swiper{height: 500px;}.title{line-height: 64rpx;font-size: 24rpx;font-weight: bold;color: #666;background-color: #fff;position: sticky;top: 0;z-index: 999;}.item{padding-bottom: 10rpx;}.goods{display: flex;flex-direction: row;flex-wrap: nowrap;justify-content: flex-start;align-items: center;align-content: center;margin-bottom: 10rpx;&>image{width: 120rpx;height: 120rpx;margin-right: 16rpx;margin-left: 2px;flex-shrink: 0;}.goods-right{flex:1;}.describe{font-size: 24rpx;color: #999;}.money{font-size: 24rpx;color: #efba21;}}}}}.bottom-panel{padding-bottom: 0;padding-bottom: constant(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom); }
}