jiuyiUniapp/jiuyi/pages/shop/search/components/jy-linkage/index.vue

361 lines
12 KiB
Vue

<template>
<view class="zh-wrapper">
<scroll-view class="menus" :scroll-into-view="menuScrollIntoView" scroll-with-animation scroll-y>
<view class="wrapper">
<view class="menu" :id="`menu-${item.id}`" :class="{ 'current': item.id == curCateId }"
v-for="(item, index) in goods" :key="index" @click="handleMenuTap(item.id)">
<text>{{ item.name }}</text>
</view>
</view>
</scroll-view>
<scroll-view class="goods" scroll-with-animation scroll-y :scroll-top="cateScrollTop"
@scroll="handleGoodsScroll">
<view class="wrapper">
<view class="list">
<!-- category begin -->
<view class="category" v-for="(item, index) in goods" :key="index" :id="`cate-${item.id}`">
<slot name="custom" :data="item">
<view class="title">
<text>{{ item.name }}</text>
</view>
<view class="items">
<!-- 商品 begin -->
<view class="good" v-for="(good, key) in item.goods_list" :key="key">
<view class="right">
<view class="tips">
<text @click="clickTips(tips)" class="tips_item"
:class="{ 'tips_current': handerTips(tips) }"
v-for="(tips, k) in good.tips" :key="k">
{{ tips }}
</text>
</view>
</view>
</view>
<!-- 商品 end -->
</view>
</slot>
</view>
<!-- category end -->
</view>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref, nextTick, getCurrentInstance, watch, defineEmits } from "vue";
const props = defineProps({
scrollList: {
type: Array,
default: () => []
}
})
const instance = getCurrentInstance();
const menuScrollIntoView = ref("");
const curCateId = ref(6905);
const cateScrollTop = ref(0);
// 计算高度状态
const sizeCalcState = ref(false);
const goods = ref([]);
//选中的数组
const curCate = ref([])
const emit = defineEmits(['clickTips'])
//tips选中
const clickTips = (id) => {
//判断id是否在里面
let index = curCate.value.indexOf(id)
if (index > -1) {
//删除
curCate.value.splice(index, 1)
} else {
//添加
curCate.value.push(id)
}
emit('clickTips', curCate)
}
//判断是否有选中的tips
const handerTips = (id) => {
//判断id是否在里面
return curCate.value.indexOf(id) > -1
}
//重置选择
const resetTips = () => {
curCate.value = []
}
//暴露方法
defineExpose({
resetTips
})
//监听数据变化
watch(
() => props.scrollList,
newVal => {
goods.value = newVal;
nextTick(() => {
if (newVal && newVal.length > 0) {
calcSize();
}
})
},
{
immediate: true,
deep: true
}
)
// 点击左侧菜单
function handleMenuTap(id) {
if (!sizeCalcState.value) {
calcSize()
}
curCateId.value = id
nextTick(() => {
cateScrollTop.value = goods.value.find(item => item.id == id).top
})
}
// 商品滚动
function handleGoodsScroll({ detail }) {
if (!sizeCalcState.value) {
calcSize()
}
const { scrollTop } = detail
// 此处scrollTop + 1为了处理scrolltop的偏差值
let tabs = goods.value.filter(item => item.top <= (scrollTop + 1)).reverse()
if (tabs.length > 0) {
curCateId.value = tabs[0].id
}
}
function calcSize() {
let h = 10
goods.value.forEach(item => {
let view = uni.createSelectorQuery().in(instance).select(`#cate-${item.id}`)
view.fields({
size: true
}, (data) => {
item.top = h
h += data.height
item.bottom = h
}).exec()
})
sizeCalcState.value = true
}
</script>
<style lang="scss">
$text-color-assist: #919293; // 辅助色
$text-color-base: #5A5B5C; // 基础色
$choose: #FF9B27;
page {
height: 100%;
}
.zh-wrapper {
height: 100%;
overflow: hidden;
width: 100%;
display: flex;
.menus {
width: 200rpx;
height: 100%;
overflow: hidden;
background-color: $uni-bg-color-grey;
.wrapper {
width: 100%;
height: 100%;
.menu {
display: flex;
align-items: center;
justify-content: flex-start;
padding: 30rpx 20rpx;
font-size: $uni-font-size-base;
color: $uni-text-color;
position: relative;
&:nth-last-child(1) {
margin-bottom: 130rpx;
}
&.current {
background-color: $uni-bg-color;
color: $choose;
}
.dot {
position: absolute;
width: 34rpx;
height: 34rpx;
line-height: 34rpx;
font-size: $uni-font-size-sm;
background-color: $uni-color-primary;
color: $uni-bg-color;
top: 16rpx;
right: 10rpx;
border-radius: 100%;
text-align: center;
}
}
}
}
.goods {
flex: 1;
height: 100%;
overflow: hidden;
background-color: $uni-bg-color;
.wrapper {
width: 100%;
height: 100%;
padding: 20rpx;
.list {
width: 100%;
font-size: $uni-font-size-base;
padding-bottom: 130rpx;
:deep(.category) {
width: 100%;
.title {
padding: 30rpx 0;
display: flex;
align-items: center;
color: $text-color-base;
.icon {
width: 38rpx;
height: 38rpx;
margin-left: 10rpx;
}
}
}
:deep(.items) {
display: flex;
flex-direction: column;
padding-bottom: -30rpx;
.good {
display: flex;
align-items: center;
margin-bottom: 30rpx;
.right {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
padding-right: 14rpx;
.name {
font-size: $uni-font-size-base;
margin-bottom: 10rpx;
}
.tips {
display: flex;
flex-wrap: wrap;
&_item {
display: flex;
align-items: center;
justify-content: center;
width: 172rpx;
height: 74rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: $uni-font-size-base;
color: $uni-text-color;
background: $uni-bg-color-grey;
margin: 10rpx;
border-radius: 12rpx;
&.tips_current {
color: $choose;
background: rgba(248, 209, 164, 0.2);
box-sizing: border-box;
border: 2rpx solid #FF9B27;
}
}
}
.price_and_action {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
.price {
font-size: $uni-font-size-base;
font-weight: 600;
}
.btn-group {
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
.btn {
padding: 0 20rpx;
box-sizing: border-box;
font-size: $uni-font-size-sm;
height: 44rpx;
line-height: 44rpx;
&.property_btn {
border-radius: 24rpx;
}
&.add_btn,
&.reduce_btn {
padding: 0;
width: 44rpx;
border-radius: 44rpx;
}
}
.dot {
position: absolute;
background-color: $uni-bg-color;
border: 1px solid $uni-color-primary;
color: $uni-color-primary;
font-size: $uni-font-size-sm;
width: 36rpx;
height: 36rpx;
line-height: 36rpx;
text-align: center;
border-radius: 100%;
right: -12rpx;
top: -10rpx;
}
.number {
width: 44rpx;
height: 44rpx;
line-height: 44rpx;
text-align: center;
}
}
}
}
}
}
}
}
}
}
</style>