Vue3电商项目实战-分类模块5【12-二级类目-结果区-排序组件、13-二级类目-结果区-数据加载、14-二级类目-结果区-进行筛选】
文章目录
- 12-二级类目-结果区-排序组件
- 13-二级类目-结果区-数据加载
- 14-二级类目-结果区-进行筛选
12-二级类目-结果区-排序组件
目的:封装排序组件,完成排序切换效果
大致步骤:
- 定义一个组件
sub-sort,完成基础布局 - 在
sub.vue组件使用 - 完成切换排序时候的交换效果
落地代码:
- 1)基础布局:
src/views/category/components/sub-sort.vue
<template><div class='sub-sort'><div class="sort"><a href="javascript:;">默认排序</a> <a href="javascript:;">最新商品</a><a href="javascript:;">最高人气</a><a href="javascript:;">评论最多</a><a href="javascript:;">价格排序<i class="arrow up" /><i class="arrow down" /></a></div><div class="check"><XtxCheckbox>仅显示有货商品</XtxCheckbox><XtxCheckbox>仅显示特惠商品</XtxCheckbox></div></div>
</template>
<script>
export default {name: 'SubSort'
}
</script>
<style scoped lang='less'>
.sub-sort {height: 80px;display: flex;align-items: center;justify-content: space-between;.sort {display: flex;a {height: 30px;line-height: 28px;border: 1px solid #e4e4e4;padding: 0 20px;margin-right: 20px;color: #999;border-radius: 2px;position: relative;transition: all .3s;&.active {background: @xtxColor;border-color: @xtxColor;color: #fff;}.arrow {position: absolute;border: 5px solid transparent;right: 8px;&.up {top: 3px;border-bottom-color: #bbb;&.active {border-bottom-color: @xtxColor;}}&.down {top: 15px;border-top-color: #bbb;&.active {border-top-color: @xtxColor;}}}}}.check {.xtx-checkbox {margin-left: 20px;color: #999;}}
}
</style>
使用组件:src/views/category/sub.vue`
<template><div class='sub-category'><div class="container"><!-- 面包屑 --><SubBread /><!-- 筛选区 --><SubFilter /><!-- 结果区域 -->
+ <div class="goods-list">
+ <!-- 排序 -->
+ <SubSort />
+ <!-- 列表 -->
+ </div></div></div>
</template><script>
import SubBread from './components/sub-bread'
import SubFilter from './components/sub-filter'
+import SubSort from './components/sub-sort'
export default {name: 'SubCategory',
+ components: { SubBread, SubFilter, SubSort}
}
</script><style scoped lang='less'>
+.goods-list {
+ background: #fff;
+ padding: 0 25px;
+ margin-top: 25px;
+}
</style>
- 2)交互效果:
<template><div class='sub-sort'><div class="sort"><a :class="{active:sortParams.sortField===null}" @click="changeSort(null)" href="javascript:;">默认排序</a><a :class="{active:sortParams.sortField==='publishTime'}" @click="changeSort('publishTime')" href="javascript:;">最新商品</a><a :class="{active:sortParams.sortField==='orderNum'}" @click="changeSort('orderNum')" href="javascript:;">最高人气</a><a :class="{active:sortParams.sortField==='evaluateNum'}" @click="changeSort('evaluateNum')" href="javascript:;">评论最多</a><a @click="changeSort('price')" href="javascript:;">价格排序<i class="arrow up" :class="{active:sortParams.sortField==='price'&&sortParams.sortMethod=='asc'}" /><i class="arrow down" :class="{active:sortParams.sortField==='price'&&sortParams.sortMethod=='desc'}" /></a></div><div class="check"><XtxCheckbox v-model="sortParams.inventory">仅显示有货商品</XtxCheckbox><XtxCheckbox v-model="sortParams.onlyDiscount">仅显示特惠商品</XtxCheckbox></div></div>
</template>
<script>
import { reactive } from 'vue'
export default {name: 'SubSort',setup () {// 1. 根据后台需要的参数定义数据对象// 2. 根据数据对象,绑定组件(复选框,排序按钮)// 3. 在操作排序组件的时候,需要反馈给数据对象// sortField====>publishTime,orderNum,price,evaluateNum// sortMethod====>asc为正序 desc为倒序const sortParams = reactive({inventory: false,onlyDiscount: false,sortField: null,sortMethod: null})// 改变排序const changeSort = (sortField) => {if (sortField === 'price') {sortParams.sortField = sortFieldif (sortParams.sortMethod === null) {// 第一次点击,默认是降序sortParams.sortMethod = 'desc'} else {// 其他情况根据当前排序取反sortParams.sortMethod = sortParams.sortMethod === 'desc' ? 'asc' : 'desc'}} else {// 如果排序未改变停止逻辑 if (sortParams.sortField === sortField) returnsortParams.sortField = sortFieldsortParams.sortMethod = null}}return { sortParams, changeSort }}
}
</script>
13-二级类目-结果区-数据加载
目的:实现结果区域商品展示。
大致步骤:
- 完成结果区域商品布局
- 完成
xtx-infinite-loading组件封装 - 使用
xtx-infinite-loading完成数据加载和渲染
落地代码:src/views/category/sub.vue
1.基础布局
<template><div class='sub-category'><div class="container"><!-- 面包屑 --><SubBread /><!-- 筛选区 --><SubFilter /><!-- 结果区域 --><div class="goods-list"><!-- 排序 --><SubSort /><!-- 列表 --><ul><li v-for="i in 20" :key="i" ><GoodsItem :goods="{}" /></li></ul></div></div></div>
</template><script>
import SubBread from './components/sub-bread'
import SubFilter from './components/sub-filter'
import SubSort from './components/sub-sort'
import GoodsItem from './components/goods-item'
export default {name: 'SubCategory',components: { SubBread, SubFilter, SubSort, GoodsItem }
}
</script><style scoped lang='less'>
.goods-list {background: #fff;padding: 0 25px;margin-top: 25px;ul {display: flex;flex-wrap: wrap;padding: 0 5px;li {margin-right: 20px;margin-bottom: 20px;&:nth-child(5n) {margin-right: 0;}}}
}
</style>
2.无限列表加载组件 src/components/xtx-infinite-loading.vue

<template><div class="xtx-infinite-loading" ref="container"><div class="loading" v-if="loading"><span class="img"></span><span class="text">正在加载...</span></div><div class="none" v-if="finished"><span class="img"></span><span class="text">亲,没有更多了</span></div></div>
</template><script>
import { ref } from 'vue'
import { useIntersectionObserver } from '@vueuse/core'
export default {name: 'XtxInfiniteLoading',props: {loading: {type: Boolean,default: false},finished: {type: Boolean,default: false}},setup (props, { emit }) {const container = ref(null)useIntersectionObserver(container,([{ isIntersecting }], dom) => {if (isIntersecting) {if (props.loading === false && props.finished === false) {emit('infinite')}}},{threshold: 0})return { container }}
}
</script><style scoped lang='less'>
.xtx-infinite-loading {.loading {display: flex;align-items: center;justify-content: center;height: 200px;.img {width: 50px;height: 50px;background: url(../../assets/images/load.gif) no-repeat center / contain;}.text {color: #999;font-size: 16px;}}.none {display: flex;align-items: center;justify-content: center;height: 200px;.img {width: 200px;height: 134px;background: url(../../assets/images/none.png) no-repeat center / contain;}.text {color: #999;font-size: 16px;}}
}
</style>
3.定义获取数据的API src/api/category.js
/*** 获取分类下的商品(带筛选条件)* @param {Object} params - 可参考接口文档*/
export const findSubCategoryGoods = (params) => {return request('/category/goods/temporary', 'post', params)
}
4.在src/views/category/sub.vue 使用组件
<!-- 结果区域 --><div class="goods-list"><!-- 排序 --><GoodsSort /><!-- 列表 --><ul><li v-for="item in list" :key="item.id" ><GoodsItem :goods="item" /></li></ul><!-- 加载 -->
+ <XtxInfiniteLoading :loading="loading" :finished="finished" @infinite="getData" /></div>
<script>
import SubBread from './components/sub-bread'
import SubFilter from './components/sub-filter'
import SubSort from './components/sub-sort'
import GoodsItem from './components/goods-item'
import { ref, watch } from 'vue'
import { findSubCategoryGoods } from '@/api/category'
import { useRoute } from 'vue-router'
export default {name: 'SubCategory',components: { SubBread, SubFilter, SubSort, GoodsItem },setup () {// 1. 基础布局// 2. 无限加载组件// 3. 动态加载数据且渲染// 4. 任何筛选条件变化需要更新列表const route = useRoute()const loading = ref(false)const finished = ref(false)const goodsList = ref([])// 查询参数let reqParams = {page: 1,pageSize: 20}// 获取数据函数const getData = () => {loading.value = truereqParams.categoryId = route.params.idfindSubCategoryGoods(reqParams).then(({ result }) => {if (result.items.length) {goodsList.value.push(...result.items)reqParams.page++} else {// 加载完毕finished.value = true}// 请求结束loading.value = false})}// 切换二级分类重新加载watch(() => route.params.id, (newVal) => {if (newVal && route.path === ('/category/sub/' + newVal)) {goodsList.value = []reqParams = {page: 1,pageSize: 20}finished.value = false}})return { loading, finished, goodsList, getData }}
}
</script>
14-二级类目-结果区-进行筛选
目的:在做了筛选和排序的时候从新渲染商品列表。
大致步骤:
- 排序组件,当你点击了排序后 或者 复选框改变后 触发自定义事件
sort-change传出排序参数 - 筛选组件,当你改了品牌,或者其他筛选添加,触发自定义事件
filter-change传出筛选参数 - 在sub组件,分别绑定
sort-changefilter-change得到参数和当前参数合并,回到第一页,清空数据,设置未加载完成,触发加载。
落地代码:
- 组件:
src/views/category/components/sub-sort.vue
// 改变排序const changeSort = (sortField) => {// 省略代码....
+ emit('sort-change', sortParams)}
<div class="check"><XtxCheckbox @change="changeCheck" v-model="sortParams.inventory">仅显示有货商品</XtxCheckbox><XtxCheckbox @change="changeCheck" v-model="sortParams.onlyDiscount">仅显示特惠商品</XtxCheckbox></div>
const changeCheck = (sortField) => {emit('sort-change', sortParams)}
- 组件
src/views/category/components/sub-filter.vue
// 获取筛选参数const getFilterParams = () => {const filterParams = {}const attrs = []filterParams.brandId = filterData.value.selectedBrandfilterData.value.saleProperties.forEach(p => {const attr = p.properties.find(attr => attr.id === p.selectedProp)if (attr && attr.id !== undefined) {attrs.push({ groupName: p.name, propertyName: attr.name })}})if (attrs.length) filterParams.attrs = attrsreturn filterParams}// 选择品牌const changeBrand = (brandId) => {if (filterData.value.selectedBrand === brandId) return filterData.value.selectedBrand = brandIdemit('filter-change', getFilterParams())}// 选中属性const changeAttr = (p, attrId) => {if (p.selectedProp === attrId) returnp.selectedProp = attrIdemit('filter-change', getFilterParams())}return { filterData, filterLoading, changeBrand, changeAttr }}
- 组件
src/views/category/sub.vue
<SubFilter @sort-change="changeFilter" />
<GoodsSort @filter-change="changeSort"/>
// 监听筛选区改变const changeFilter = (filterParams) => {reqParams = { ...reqParams, ...filterParams }reqParams.page = 1goodsList.value = []finished.value = false}// 监听排序改变const changeSort = (sortParams) => {reqParams = { ...reqParams, ...sortParams }reqParams.page = 1goodsList.value = []finished.value = false}return { loading, finished, goodsList, getData, changeFilter, changeSort }
相关文章:
Vue3电商项目实战-分类模块5【12-二级类目-结果区-排序组件、13-二级类目-结果区-数据加载、14-二级类目-结果区-进行筛选】
文章目录12-二级类目-结果区-排序组件13-二级类目-结果区-数据加载14-二级类目-结果区-进行筛选12-二级类目-结果区-排序组件 目的:封装排序组件,完成排序切换效果 大致步骤: 定义一个组件 sub-sort,完成基础布局在 sub.vue 组件…...
计算机操作系统概述
文章目录1.0 操作系统概述1.1 操作系统的目标1.2 操作系统的功能1.3 操作系统结构1.4 操作系统接口1.5 操作系统的发展1.6 操作系统的特征2.0 进程管理2.1 进程调度2.2 进程调度算法2.3 进程间通信2.4 进程间的同步2.5 软件实现互斥的方法2.6 硬件实现互斥的方法2.7 信号2.8 管…...
面试官让你说说react状态管理?
hooks 为什么不能放在条件判断里 以 setState 为例,在 react 内部,每个组件(Fiber)的 hooks 都是以链表的形式存在 memoizeState 属性中 update 阶段,每次调用 setState,链表就会执行 next 向后移动一步。如果将 setState 写在条…...
CUDA线程块的分配
为了确保能够真正地了解线程块的分配,接下来我们写一个简短的内核程序来输出线程块、线程、线程束和线程全局标号到屏幕上。现在,除非你使用的是 3.2 版本以上的 SDK否则内核中是不支持 printf的。因此,我们可以将数据传送回 CPU 端然后输出到…...
史密斯圆图
在射频、微波中,常常使用史密斯圆图来做阻抗匹配。在不涉及复杂的数学推导,仍能把圆图用起来。 比如,共轭匹配。 RL1jX,需要找到-jX来抵消jX,消掉虚部之后,只留下实部,最终等效为RL‘1。 史密…...
Spring国际化实现
Java国际化 Java使用Unicode来处理所有字符。 Locales 国际化主要涉及的是数字、日期、金额等。 有若干个专门负责格式处理的类。为了对格式进行控制,可以使用Locale类。它描述了: 一种语言一个位置(通常包含)一段脚本(可选,自Java SE7开…...
10- 天猫用户复购预测 (机器学习集成算法) (项目十) *
项目难点 merchant: 商人重命名列名: user_log.rename(columns{seller_id:merchant_id}, inplaceTrue)数据类型转换: user_log[item_id] user_log[item_id].astype(int32)主要使用方法: xgboost, lightbm竞赛地址: 天猫复购预测之挑战Baseline_学习赛_天池大赛-阿里云天池…...
对于《MySQL 实战45讲》的理解
一.理论 一条SQL执行过程 连接器分析器优化器执行器 索引 索引的出现其实就是为了提高数据查询的效率,就像书的目录一样 常见索引数据结构(每碰到一个新数据库,我们需要先关注它的数据模型,这样才能从理论上分析出这个数据库的适用场景) 哈希…...
XQuery 函数
XQuery 1.0、XPath 2.0 以及 XSLT 2.0 共享相同的函数库。 XQuery 函数 XQuery 含有超过 100 个内建的函数。这些函数可用于字符串值、数值、日期以及时间比较、节点和 QName 操作、序列操作、逻辑值等等。您也可在 XQuery 中定义自己的函数。 XQuery 内建函数 XQuery 函数命…...
Elasticsearch的安装及常用操作
文章目录一、Elasticsearch的介绍1、Elasticsearch索引2、Elasticsearch的介绍二、Elasticsearch的安装1、安装ES服务2、安装kibana3、Docker安装ES4、Docker安装Kibana三、ES的常用操作1、索引操作2、文档操作3、域的属性3.1 index3.2 type3.3 store总结一、Elasticsearch的介…...
网络安全应急响应服务方案怎么写?包含哪些阶段?一文带你了解!
文章目录一、服务范围及流程1.1 服务范围1.2 服务流程及内容二、准备阶段2.1 负责人准备内容2.2 技术人员准备内容(一)服务需求界定(二)主机和网络设备安全初始化快照和备份2.3市场人员准备内容(1)预防和预…...
11、事务原理和实战,MVCC
事务原理和实战 1. 认识事务2. 事务控制语句2.1 开启事务2.2 事务提交2.3 事务回滚3. 事务的实现方式3.1 原子性3.2 一致性3.3 隔离性3.3 持久性4purge thread线程5事务统计QPS与TPS5.1 QPS5.2 TPS6. 事务隔离级别6.1 隔离级别6.2 查看隔离级别6.3 设置隔离级别6.4 不同隔离级别…...
Robust Self-Augmentation for Named Entity Recognition with Meta Reweighting
摘要 近年来,自我增强成为在低资源场景下提升命名实体识别性能的研究热点。Token substitution and mixup (token替换和表征混合)是两种有效提升NER性能的自增强方法。明显,自增强方法得到的增强数据可能由潜在的噪声。先前的研究…...
Java基础-xml
1.xml 1.1概述 万维网联盟(W3C) 万维网联盟(W3C)创建于1994年,又称W3C理事会。1994年10月在麻省理工学院计算机科学实验室成立。 建立者: Tim Berners-Lee (蒂姆伯纳斯李)。 是Web技术领域最具权威和影响力的国际中立性技术标准机构。 到目前为止&#…...
TCP的Nagle算法和delayed ack---延时发送和延时应答与稍带应答选项
本文目录提高TCP的网络利用率的二个思考解决方案:Nagle算法和delayed ack(延时发送和延时应答与稍带应答选项)Nagle算法和delayed ack算法同时启动可能会导致的问题提高TCP的网络利用率的二个思考 我们都知道,TCP是一个基于字节流…...
智能拣配单解决方案
电子货架标签系统(ESLs),是一种放置在货架上、可替代传统纸质价格标签的电子显示装置, 每一个电子货架标签通过有线或者无线网络与商场计算机数据库相连, 并将最新的商品价格通过电子货架标签上的屏显示出来。 电子…...
如何防御入侵服务器
根据中华人民共和国刑法: 第二百八十六条违反国家规定,对计算机信息系统功能进行删除、修改、增加、干扰,造成计算机信息系统不能正常运行,后果严重的,处五年以下有期徒刑或者拘役;后果特别严重的ÿ…...
[软件工程导论(第六版)]第4章 形式化说明技术(课后习题详解)
文章目录1. 举例对比形式化方法和欠形式化方法的优缺点。2. 在什么情况下应该使用形式化说明技术?使用形式化说明技术时应遵守哪些准则?3. 一个浮点二进制数的构成是:一个可选的符号(+或-)&…...
Premiere基础操作
一:设置缓存二:ctrI导入素材三:导入图像序列四:打开吸附。打开吸附后素材会对齐。五:按~键可以全屏窗口。六:向前选择轨道工具。在时间线上点击,向前选中时间线上素材。向后选择轨道工具&#x…...
Prometheus监控案例-tomcat、mysql、redis、haproxy、nginx
监控tomcat tomcat自身并不能提供监控指标数据,需要借助第三方exporter实现:https://github.com/nlighten/tomcat_exporter 构建镜像 基于tomcat官方镜像,重新制作一个镜像,将tomcat-exporter和tomcat整合到一起。Ddockerfile如…...
C++ 智能指针的生命周期分析
C智能指针的生命周期分析 在现代C开发中,智能指针是管理动态内存的重要工具,它通过自动化的资源管理机制显著降低了内存泄漏和悬垂指针的风险。理解智能指针的生命周期对于编写高效、安全的代码至关重要。本文将深入分析智能指针的生命周期,…...
OpenClaw压力测试:千问3.5-9B连续执行100个任务的稳定性
OpenClaw压力测试:千问3.5-9B连续执行100个任务的稳定性 1. 为什么需要压力测试? 上周我在本地部署了OpenClaw对接千问3.5-9B模型,准备用它来处理日常的文档整理和会议纪要工作。刚开始几个简单任务执行得很顺利,直到某天晚上让…...
风光负荷不同鲁棒性对系统总成本的影响研究(考虑上下备用容量)(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
17.在 React 中如何根据条件决定渲染哪个组件?
在 React 里,组件不是一上来就“全给你渲染出来”的。 很多时候,我们希望:界面要看情况说话——登录了看“欢迎回来”没登录就看“请先登录”加载中只给你个转圈圈请求失败再丢个错误提示这些“根据条件,决定渲染什么”的行为&…...
OpenClaw安全实践:千问3.5-27B私有化部署下的权限管控
OpenClaw安全实践:千问3.5-27B私有化部署下的权限管控 1. 为什么需要关注OpenClaw的安全配置? 去年我在尝试用OpenClaw自动整理财务报表时,差点酿成一场灾难。当时我的脚本误将未加密的财务数据同步到了公开目录,幸亏及时发现。…...
I2C总线原理与嵌入式系统应用实践
1. I2C总线基础解析I2C(Inter-Integrated Circuit)总线是Philips半导体(现NXP)在1982年推出的双线制串行通信协议。作为一名电子工程师,我在多个嵌入式项目中都深度使用过这种总线。它的精妙之处在于仅用两根线&#x…...
5个突破边界技巧:OpenSpeedy游戏变速工具深度优化指南
5个突破边界技巧:OpenSpeedy游戏变速工具深度优化指南 【免费下载链接】OpenSpeedy 🎮 An open-source game speed modifier. 项目地址: https://gitcode.com/gh_mirrors/op/OpenSpeedy 副标题:如何通过用户态Hook技术实现游戏帧率自由…...
字节跳动开源Coze后,个人开发者如何快速上手?保姆级教程来了
字节跳动开源Coze实战指南:从零构建AI智能体的完整路径 当字节跳动宣布将Coze平台全面开源时,整个开发者社区为之振奋。这个被称作"AI智能体全栈工厂"的平台,如今终于揭开了神秘面纱,让个人开发者能够深入探索其技术内核…...
[具身智能-229]:OpenCV 的 DNN (Deep Neural Networks) 模块,可以直接加载和运行,通过PyTorch AI框架训练好的模型,而不需要安装PyTorch AI框架
OpenCV 的 DNN (Deep Neural Networks) 模块确实是工业界和边缘计算领域非常推崇的推理引擎。它的核心定位不是“训练模型”,而是“让训练好的模型跑得更快、更轻、更通用”。它允许开发者在不依赖庞大的 TensorFlow 或 PyTorch 库的情况下,直接在生产环…...
09_Neo4j知识体系之行业应用与最佳实践
09_Neo4j知识体系之行业应用与最佳实践 体系 行业应用层:金融反欺诈、智能推荐、社交网络分析、知识图谱构建、供应链优化关联能力:与图建模、路径分析、图算法、GraphRAG、实时决策和企业数据治理密切相关适用对象:解决方案架构师、行业数字…...
