左分类,右商品
左点击跳到其商品区 右滑动,左跳到其分类
左分类点击跳至其所有产品
scroll-into-view:值应为某子元素id (id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素
右产品 通过滑动判断子元素位置 改变左侧分类已选状态
@scroll:滚动时触发,event.detail = {scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY}
uni.createSelectorQuery :返回一个 SelectorQuery 对象实例。可以在这个实例上使用 select 等方法选择节点,并使用 boundingClientRect 等方法选择需要查询的信息。
scroll-view 属性链接
//左分类
<scroll-view scroll-y="true" class="scroll-Y" :scroll-into-view=tocate scroll-with-animation="true">
<view :class="(index+1)==select_index?'item active':'item'" v-for="(item,index) in listData" :key="index" @click="selectCategory(item)" :id="'pro_'+item.id">
<image :src="item.images.path"></image>
<text>{{item.name}}</text>
</view>
</scroll-view>
//右产品
<scroll-view scroll-y="true" class="scroll-Y scroll-3" :scroll-into-view=toview scroll-with-animation="true" @scroll="cateScroll">
<view class="item aaaaa" v-for="(item,index) in childlist" :key="index" :id="'pro_'+item.id">
<text class="cate_name">{{item.name}}</text>
<view v-for="(item1,i) in item.productList" :key="i" class="list_pro">
<image :src="item1.image[0].path" mode="aspectFit"></image>
<view class="detail">
<text class="type-name">{{item1.product_name}}</text>
<text class="selling_point">{{item1.selling_point}}</text>
<text class="price">¥{{item1.product_price}}</text>
<text class="guige" @click="addCart(item1)">加购</text>
</view>
</view>
</view>
</scroll-view>
/*点击分类跳产品*/
selectCategory(e) {
this.toview = 'pro_' + e.id
this.select_index = e.sort
},
/*滑动产品改变分类已选*/
cateScroll() {
const query = uni.createSelectorQuery().in(this);
query.selectAll('.aaaaa').boundingClientRect(data => {
for (var cate = 0; cate < data.length; cate++) {
if (data[cate].top < 120 && data[cate].top > 0) {
this.toview = data[cate].id;
this.select_index = cate + 1;
}
}
}).exec();
}
补上一份可以直接用的文件,之前数据都找不到了,写了份类似的加上数据结构,放进uniapp里可以直接运行起来看到效果
–2023/12/21
<template>
<view class="category-wrap">
<view style="height: 20vh;background-color: aliceblue;">
展示区
</view>
<view class="order_product">
<!--类别列表-->
<view class="category-content">
<view class="cotegory-type cotegory-type-3">
<view class="category-tab">
<scroll-view
scroll-y="true"
class="scroll-Y"
:scroll-into-view="tocate"
scroll-with-animation="true"
>
<view
:class="index == select_index ? 'item active' : 'item'"
v-for="(item, index) in listData"
:key="index"
@click="selectCategory(item.category_id, index)"
:id="'pro_' + item.category_id"
>
<text style="white-space: pre;">{{ item.name.replace(' ','\n')}}</text>
<view class="cate_num_all" v-if="item.cate_num_all">
<text>{{ item.cate_num_all }}</text>
</view>
</view>
</scroll-view>
</view>
<view class="category-content pr">
<scroll-view
scroll-y="true"
class="scroll-Y scroll-3"
:scroll-into-view="toview"
scroll-with-animation="true"
@scroll="cateScroll"
>
<block v-for="(item, index) in listData" :key="index">
<view
v-if="item.name == '精选'+ ' ' + '套餐'"
:id="'pro_' + item.category_id">
<view
v-for="(item1, i) in item.productList"
:key="i"
class="list_pro_one"
@click="getdetail(item1.product_id, item1)"
>
<image
class="pro_img_info"
:src="item1.image[0].file_path"
mode="scaleToFill"
>
</image>
<view class="detail">
<view class="type-name">{{ item1.product_name }}</view>
<view class="selling_point">{{
item1.selling_point
}}</view>
<view class="price">¥{{ item1.product_price }}</view>
<view
v-if="item1.spec_type == 20"
class="guige"
@click.stop="getdetail(item1.product_id, item1)"
>
{{ item1.product_stock ? "选规格" : "库存不足" }}
</view>
<view
v-else
class="guige_jj icon iconfont icon-jia"
@click.stop="addCart(item1)"
></view>
</view>
</view>
</view>
<view v-else class="item aaaaa" :id="'pro_' + item.category_id">
<!-- <text class="cate_name">{{item.name}}</text> -->
<!-- item.titleimg -->
<image
class="cate_name"
v-if="item.titleimg"
:src="item.titleimg.file_path"
>
</image>
<view
v-for="(item1, i) in item.productList"
:key="i"
class="list_pro"
:id="item1.product_id"
@click="getdetail(item1.product_id, item1)"
>
<image
class="pro_img_info"
:src="item1.image[0].file_path"
mode="aspectFill"
>
</image>
<view class="detail">
<text class="type-name">{{ item1.product_name }}</text>
<text class="selling_point">{{
item1.selling_point
}}</text>
<text class="price">¥{{ item1.product_price }}</text>
<block>
<text
v-if="item1.spec_type == 20"
class="guige"
@click.stop="getdetail(item1.product_id, item1)"
>{{
item1.product_stock ? "选规格" : "库存不足"
}}</text
>
<text
v-else
class="guige_j icon iconfont icon-jia"
@click.stop="addCart(item1)"
></text>
</block>
</view>
</view>
</view>
</block>
</scroll-view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
toview: "",
select_index: 0,
listData: [
{
name:'大分类1',
titleimg:{file_path:''}, //商品分类的展示图片
category_id:'1',
cate_num_all:'',
productList:[
{
product_id:'200',
product_name:'商品1',
product_price:'20.00',
selling_point:'好吃不贵',
product_stock:false,
image:[
{
file_path:''
}
]
},
{
product_id:'201',
product_name:'商品2',
product_price:'22.00',
selling_point:'好吃不贵',
product_stock:false,
image:[
{
file_path:''
}
]
},
{
product_id:'208',
product_name:'商品256',
product_price:'22.00',
selling_point:'好吃不贵',
product_stock:false,
image:[
{
file_path:''
}
]
}
]
},
{
name:'大分类2',
titleimg:{file_path:''},
category_id:'2',
cate_num_all:'',
productList:[
{
product_id:'300',
product_name:'23商品',
product_price:'230.00',
selling_point:'好吃不贵',
product_stock:false,
image:[
{
file_path:''
}
]
},
{
product_id:'201',
product_name:'12商品2',
product_price:'223.00',
selling_point:'好吃不贵',
product_stock:false,
image:[
{
file_path:''
}
]
},
{
product_id:'204',
product_name:'pocy',
product_price:'23.00',
selling_point:'好吃不贵',
product_stock:false,
image:[
{
file_path:''
}
]
},
{
product_id:'205',
product_name:'poc111y',
product_price:'23.00',
selling_point:'好吃不贵',
product_stock:false,
image:[
{
file_path:''
}
]
},
]
},
{
name:'大分类3',
titleimg:{file_path:''},
category_id:'3',
cate_num_all:'',
productList:[
{
product_id:'400',
product_name:'23商品',
product_price:'230.00',
selling_point:'好吃不贵',
product_stock:false,
image:[
{
file_path:''
}
]
},
{
product_id:'401',
product_name:'12商品2',
product_price:'223.00',
selling_point:'好吃不贵',
product_stock:false,
image:[
{
file_path:''
}
]
},
{
product_id:'404',
product_name:'23商品',
product_price:'230.00',
selling_point:'好吃不贵',
product_stock:false,
image:[
{
file_path:''
}
]
},
{
product_id:'405',
product_name:'测试2',
product_price:'223.00',
selling_point:'好吃不贵',
product_stock:false,
image:[
{
file_path:''
}
]
}
]
},
],
}
},
methods:{
/*选择分类*/
selectCategory(e, index) {
this.toview = "pro_" + e;
this.select_index = index;
},
cateScroll() {
const query = uni.createSelectorQuery().in(this);
query.selectAll(".aaaaa")
.boundingClientRect((data) => {
for (var cate = 0; cate < data.length; cate++) {
if (data[cate].top < 200 && data[cate].top > 0) {
this.toview = data[cate].id;
this.select_index = cate;
}
}
})
.exec();
},
}
}
</script>
<style lang="less">
/**/
.list_pro_one {
position: relative;
margin: 10px 20px 10px 0px;
image {
width: 100%;
height: 166px;
border-radius: 10px;
}
.detail {
width: 100%;
position: absolute;
top: 0;
padding: 18px 12px;
box-sizing: border-box;
color: #343434;
height: 100%;
}
.detail .type-name {
font-size: 18px;
//color: #343434;
}
.detail .selling_point {
font-size: 13px;
margin-top: 6px;
}
.detail .price {
font-size: 23px;
margin-top: 10px;
font-weight: bold;
}
.guige_jj {
background: #278D44;
color: #fff !important;
border-radius: 15px;
font-size: 10px;
padding: 5px;
position: absolute;
bottom: 20px;
right: 10px;
}
}
.guige_j {
background: #278D44;
color: #fff !important;
border-radius: 15px;
font-size: 10px;
padding: 5px;
float: right;
}
.cate_num_all {
display: inline-block;
background: #499E39;
border-radius: 50%;
position: absolute;
right: 8px;
width: 16px;
color: #fff;
top: 10px;
height: 16px;
line-height: 16px;
font-size: 10px;
}
.header_cate {
display: flex;
padding-top: 6vh;
background: #177B3D;
align-items: center;
padding-bottom: 5px;
text {
color: #fff;
font-size: 17px;
margin: 0 17px;
}
input {
background: #f7f7f7;
padding: 5px;
text-align: center;
border-radius: 16px;
font-size: 14px;
color: #969696;
width: 190px;
}
}
.category-wrap {
background-color: #fff;
}
.shop {
font-size: 15px;
margin-left: 7px;
}
.category-content {
overflow: hidden;
}
.cotegory-type {
width: 100%;
}
.category-tab {
width: 87px;
background: #f5f5f5;
overflow-y: scroll;
padding-bottom: 22px;
.seach {
padding: 20rpx 0;
font-size: 14px;
text-align: center;
color: #b6c0cf;
}
.seach .icon {
font-size: 25px !important;
display: block;
}
.item {
position: relative;
padding: 20px;
font-size: 16px;
text-align: center;
color: #6f6f6f;
display: inline-block;
text-align: center;
width: 100%;
box-sizing: border-box;
}
.item image {
width: 40px;
height: 40px;
margin: auto;
display: block;
}
.item.active {
position: relative;
background: #c9ebc9;
color: #000;
font-weight: bold;
}
}
.cotegory-type-3 .category-content {
flex: 1;
background-color: #e99494;
}
.scroll-3 {
height: 73vh;
margin: 0 10px;
padding-bottom: 15px;
}
.cotegory-type-3 .list {
padding: 0 25rpx;
}
.cotegory-type-3 {
display: flex;
}
.cotegory-type-3 .scroll-3 .item {
font-size: 24rpx;
.detail {
vertical-align: top;
width: 51%;
position: relative;
padding-top: 10px;
}
.cate_name {
width: 94%;
height: 91px;
border-radius: 10px;
}
.list_pro {
width: 94%;
background: #fff;
border-radius: 10px;
margin: 10px 0;
padding: 10px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
}
.type-name {
font-size: 16px;
display: block;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
color: #343434;
font-weight: bold;
}
.selling_point {
display: block;
color: #999;
height: 100rpx;
overflow: hidden;
padding: 4px 0;
font-size: 12px;
line-height: 20px;
}
.price {
font-size: 18px;
color: #343434;
font-weight: 600;
}
.guige {
float: right;
padding: 0px 10px;
background-color: #278D44;
border-radius: 11px;
color: #fff;
z-index: 999;
font-size: 12px;
height: 22px;
line-height: 22px;
}
}
.cotegory-type-3 .scroll-3 .item .pro_img_info {
width: 45%;
height: 220rpx;
border-radius: 10px;
}
</style>