仿京东淘宝商品列表筛选组件:实现一个高效的侧边栏弹框筛选功能
一、引言
随着电子商务的快速发展,用户体验成为了竞争的关键因素。在众多的电商网站中,如京东和淘宝,商品列表筛选功能为用户提供了便捷的途径来找到心仪的商品。本文将详细介绍如何使用cc-widget、uni-icons和xg-list组件来仿制京东淘宝的商品列表筛选组件,并实现一个高效的侧边栏弹框筛选功能。
二、需求分析
我们的目标是创建一个仿京东淘宝的商品列表筛选组件,具有以下功能:
-
点击筛选标签时,能够切换到相应的筛选选项。
-
当点击“价格”标签时,显示价格图标状态;点击其他标签时,重置价格图标状态。
-
当点击“排序”标签时,显示排序选项;点击其他标签时,隐藏排序选项。
-
当点击“筛选”标签时,弹出一个侧边栏筛选弹框。
-
点击综合推荐排序方式时,能够设置当前排序选项,并隐藏排序选项。
-
点击筛选确定按钮时,能够触发一个事件来处理筛选结果。
三、技术实现
为了实现上述功能,我们需要使用Vue.js框架和一些UI组件库。这里我们选用cc-widget、uni-icons和xg-list组件来实现。
-
引入必要的组件库
在项目中引入cc-widget、uni-icons和xg-list组件库,确保能够正确使用这些组件。
-
编写HTML结构
根据需求,编写筛选组件的HTML结构。使用cc-widget、uni-icons和xg-list组件来构建基本的筛选框架。
-
实现事件处理逻辑
根据需求分析中的事件处理要求,编写相应的方法来处理点击事件。使用Vue.js的事件绑定机制来监听点击事件,并调用相应的方法来处理逻辑。
四、代码实现
使用方法
引入cc-widget uni-icons xg-list组件
事件处理如下:
// 筛选点击
onTabTitleTap(index) {
console.log("index = " + index);
this.setCurrentTabTitleIndex(index);
if ('price' !== index) {
this.resetPriceIconStatus();
}
if ('sort' !== index) {
this.hiddenSortOptions();
}
if ('sort' === index) {
this.toggleSortOptions();
return;
}
if ('volume' === index) {
return;
}
if ('price' === index) {
this.togglePriceIconStatus();
return;
}
if ('filter' === index) {
this.$refs['filter-popup'].open();
return;
}
},
// 综合推荐排列方式点击
onSortOptionTap(index) {
this.setCurrentSortOptionIndex(index);
this.hiddenSortOptions();
console.log("综合推荐排列方式 = " + index);
},
// 筛选确定
onFilterConfirm(e) {
console.log("filter确定 = " + JSON.stringify(e));
}
<template> <view class=""> <!-- #ifdef MP-WEIXIN --> <uni-nav-bar fixed status-bar left-icon="back" @clickLeft="onBackPressTap"> <view slot="left" class="nav-bar-search-bar" :style="{width: searchBarWidth + 'px'}"> <tpl-search-bar cancelButton="none" :radius="10000" @confirm="" @input="" /> </view> </uni-nav-bar> <view class="status-bar-placeholder"></view> <!-- #endif --> <view class="tab-title-section-placeholder"></view> <view class="tab-title-section"> <!-- #ifdef MP-WEIXIN --> <xg-status-bar></xg-status-bar> <!-- #endif --> <view class="position-relative "> <view class="row-center-center bg-color-white tab-title-list-wrap"> <view class="flex-1 row-between-stretch padding-side-lg tab-title-list"> <view class="row-center-stretch" @tap="onTabTitleTap('sort')"> <view class="tab-title-left"> <view class="tab-title-left-text"> <text class="font-size-lg">{ {currentSortOptionTitle}}</text> </view> <view v-if="currentTabTitleIndex === 'sort'" class="title-line"></view> </view> <view class="tab-title-right-icon"> <uni-icons :type="showSortOptions ? 'arrowup' : 'arrowdown'" :size="12"></uni-icons> </view> </view> <view class="row-center-stretch" @tap="onTabTitleTap('volume')"> <view class="tab-title-left"> <view class="tab-title-left-text"> <text class="font-size-lg">销量</text> </view> <view v-if="currentTabTitleIndex === 'volume'" class="title-line"></view> </view> </view> <view class="row-center-stretch" @tap="onTabTitleTap('price')"> <view class="tab-title-left"> <view class="tab-title-left-text"> <text class="font-size-lg">价格</text> </view> <view v-if="currentTabTitleIndex === 'price'" class="title-line"></view> </view> <view class="column-center-center tab-title-right-icon"> <view class="column-center-center" v-if="priceIconStatus === 'all'"> <uni-icons class="" v-if="priceIconStatus === 'all' || priceIconStatus === 'up'" type="arrowup" :size="12"></uni-icons> <uni-icons class="" v-if="priceIconStatus === 'all' || priceIconStatus === 'down'" type="arrowdown" :size="12"></uni-icons> </view> <view v-else> <uni-icons v-if="priceIconStatus === 'up'" type="arrowup" :size="12"></uni-icons> <uni-icons v-if="priceIconStatus === 'down'" type="arrowdown" :size="12"></uni-icons> </view> </view> </view> <view class="row-center-stretch" @tap="onTabTitleTap('filter')"> <view class="tab-title-left"> <view class="tab-title-left-text"> <text class="font-size-lg">筛选</text> </view> <view v-if="currentTabTitleIndex === 'filter'" class="title-line"></view> </view> </view> <!-- #ifdef MP-WEIXIN --> <view class="" @tap="onWaterfallSwitchTap"> <image class="img-size-base" :src="!waterfall ? '/static/product/waterfall.png' : '/static/product/list.png'" mode=""></image> </view> <!-- #endif --> </view> </view> <view v-if="showTabTitleMask" :style="{height: screenHeight + 'px'}" class="tab-title-mask" @tap="onTabMaskTap"></view> <view v-if="showSortOptions" class="bg-color-grey border-bottom-left-radius-xl border-bottom-right-radius-xl padding-lg sort-options-section"> <view class="row-start-center sort-option" v-for="(sortOption, sortOptionIndex) of sortOptions" :key="sortOptionIndex" @tap="onSortOptionTap(sortOptionIndex)"> <uni-icons v-if="sortOptionIndex === currentSortOptionIndex" type="checkmarkempty" :size="20" :color="UNI_COLOR_RED"></uni-icons> <text class="font-size-lg" :class="{'font-weight-bold': sortOptionIndex === currentSortOptionIndex}">{ {sortOption.desc}}</text> </view> </view> </view> </view> <com-product-list :waterfall="waterfall" :products="products"></com-product-list> <com-drawer ref="filter-popup" mode="right" :width="toPx('600rpx')"> <com-filter class="filter-popup-content" :serviceOptions="serviceOptions" :brandOptions="brandOptions" :specificationOptions="specificationOptions" @confirm="onFilterConfirm"></com-filter> </com-drawer> </view> </template> <script> import data from '@/data/product/list'; import config from './list/config.js'; import mixin from '@/common/mixin'; import comProductList from './list/com-product-list'; import comFilter from './list/com-filter'; import comDrawer from './list/com-drawer'; export default { mixins: [mixin, config], components: { comProductList, comFilter, comDrawer }, data() { return { serviceOptions: [], brandOptions: [], specificationOptions: [], products: [] } }, async created() { const productsPromise = data.products(); const serviceOptionsPromise = data.serviceOptions(); const brandOptionsPromise = data.brandOptions(); const specificationOptionsPromise = data.specificationOptions(); this.specificationOptions = await specificationOptionsPromise; this.brandOptions = await brandOptionsPromise; this.serviceOptions = await serviceOptionsPromise; this.products = await productsPromise; }, onNavigationBarButtonTap(e) { this.toggleWaterfall(); }, methods: { // #ifdef MP-WEIXIN onBackPressTap() { uni.navigateBack({ delta: 1 }) }, onWaterfallSwitchTap() { this.toggleWaterfall(); }, // #endif onTabMaskTap() { this.hiddenSortOptions(); }, // 筛选点击 onTabTitleTap(index) { console.log("index = " + index); this.setCurrentTabTitleIndex(index); if ('price' !== index) { this.resetPriceIconStatus(); } if ('sort' !== index) { this.hiddenSortOptions(); } if ('sort' === index) { this.toggleSortOptions(); return; } if ('volume' === index) { return; } if ('price' === index) { this.togglePriceIconStatus(); return; } if ('filter' === index) { this.$refs['filter-popup'].open(); return; } }, // 综合推荐排列方式点击 onSortOptionTap(index) { this.setCurrentSortOptionIndex(index); this.hiddenSortOptions(); console.log("综合推荐排列方式 = " + index); }, // 筛选确定 onFilterConfirm(e) { console.log("filter确定 = " + JSON.stringify(e)); } }, } <style lang="scss" scoped> .title-line { width: 50rpx; height: 8rpx; background-color: $uni-color-red; } /* #ifdef MP-WEIXIN */ .status-bar-placeholder { @include position(fixed, 0 0 none 0); height: var(--status-bar-height); z-index: 10000; background-color: $uni-color-white; } .nav-bar-search-bar { // width: 430rpx; } /* #endif */ $tab-title-section-height: 100rpx; $tab-title-item-top-section-height: 50rpx; .tab-title-section-placeholder { height: $tab-title-section-height; } .tab-title-section { @include position(fixed, 0 0 none 0); /* #ifdef MP-WEIXIN */ top: 44px; /* #endif */ /* #ifdef H5 */ top: var(--window-top); /* #endif */ /* #ifndef APP-NVUE */ z-index: 1; /* #endif */ } .tab-title-list-wrap { height: $tab-title-section-height; } .tab-title-list { height: $tab-title-item-top-section-height + 20rpx; } .tab-title-left { @include flex-layout(column, space-between, center); } .tab-title-left-text { height: $tab-title-item-top-section-height; @include flex-layout(column, center, center); } .tab-title-right-icon { height: $tab-title-item-top-section-height; @include flex-layout(column, center, center); } .tab-title-mask { background-color: rgba($color: #000000, $alpha: 0.8); } .sort-options-section { @include position(absolute, $tab-title-section-height 0 none 0); } .sort-option { height: 60rpx; } .filter-popup-content { @include position(absolute, 0 0 0 0); /* #ifdef MP-WEIXIN */ top: var(--status-bar-height); /* #endif */ } </style>
五、测试与验证
在代码实现完成后,我们需要进行测试与验证来确保功能的正确性。可以使用自动化测试工具或手动测试来验证每个功能点的正确性。例如,点击不同的筛选标签时,是否能够正确切换到相应的筛选选项;点击排序标签时,是否能够正确显示和隐藏排序选项;点击筛选确定按钮时,是否能够正确触发事件处理逻辑等。通过详细的测试与验证,可以确保我们的仿京东淘宝商品列表筛选组件的功能正确且健壮。
六、总结与展望
本文详细介绍了如何使用cc-widget、uni-icons和xg-list组件来仿制京东淘宝的商品列表筛选组件,并实现了一个高效的侧边栏弹框筛选功能。通过需求分析和技术实现的过程,我们可以了解到如何使用Vue.js框架和一些UI组件库来实现复杂的交互功能。同时,我们也进行了测试与验证来确保功能的正确性。在未来的工作中,我们可以进一步优化代码结构和性能,提高用户体验和系统的可扩展性。
阅读全文下载完整组件代码请关注微信公众号: 前端组件开发