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如…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
