商品分类左右联动

1、先看效果

2、以hooks方法处理,方便复制使用,见代码

Good.vue文件

<script setup lang="ts" name="goods">import {onMounted, ref, nextTick} from "vue";import useProductScroll from "@/utils/hooks/useProductScroll.ts";import loading from '@/assets/images/loading.gif'import categoryHolder from './images/category-holder.png'import productHolder from './images/product-holder.png'const productList = ref<any[]>([])const refSide = ref()const refMain = ref()const {mark, setMark, setRefSide, setRefMain} = useProductScroll()onMounted(() => {// 模拟productList的数据const tmpList = Array(15).fill(1).map((v, i) => {return {name: `人气热卖${i}`,pList: Array(5).fill(1).map((v2, i2) => {return {name: `名字${i}-${i2}`}})}})setTimeout(async () => {productList.value = tmpListawait nextTick()setRefSide(refSide.value)setRefMain(refMain.value)setMark(tmpList[0].name)}, 200)})</script><template><div class="product-limit"><ul class="category-box" ref="refSide"><li v-for="v in productList" :key="v" :class="{'active': v.name===mark}" @click="() => setMark(v.name)" :mark="v.name"><div><van-image :loading-icon="loading" :src="categoryHolder" lazy-load /></div><span>{{v.name}}</span></li><li></li></ul><div class='right-content'><div class="search-box"><van-search shape="round" placeholder="请输入商品关键词" /></div><ul class="com-product-list" ref="refMain"><li v-for="v in productList" :key="v" :mark="v.name"><div class="c-category-name">{{v.name}}</div><div class="c-detail-box" v-for="v2 in v.pList" :key="v2"><div class="img-show"><van-image :loading-icon="loading" :src="productHolder" lazy-load /></div><div class="product-tro"><p class="c-name">{{v2.name}}</p><p class="c-cut-money"><span>立省11.00元起</span></p><div class="c-money"><div class="c-money-detail">¥&nbsp;<i>5.60</i>起&nbsp;<span>¥19.62</span></div><span class="c-btn-size">选规格</span></div></div></div></li><li class="product-holder"></li></ul></div></div>
</template>

useProductScroll.ts文件

import {ref} from "vue";function getDomStyle(dom: HTMLElement, style: any) {return window.getComputedStyle(dom, null)[style];
}const catchMainMarkDom: {[mark: string]: {dom: HTMLElement,top: number}
} = {}
const catchSideMarkDom: {[mark: string]: {dom: HTMLElement,}
} = {}
const catchMainMarkTop: number[] = []
const sideDomView: {[key: string]: number
} = {}
let timer:any = null
let io:any = nullexport default function useProductScroll() {const mark = ref('')const refSide = ref()const refMain = ref()const setRefSide = (d: HTMLElement) => {if (getDomStyle(d, 'position') === 'static') {d.style.position = 'relative'}refSide.value = d// 判断是否在可视区域io = new IntersectionObserver(entries => {for (let i=0; i<entries.length; i++) {const dom = entries[i].targetconst m = dom.getAttribute('mark')sideDomView[m as string] = entries[i].intersectionRatio}});// 缓存const children: any = d.childrenfor (let i=0; i<children.length; i++) {const dom = children[i]const mName = dom.getAttribute('mark')if (mName) {io.observe(dom);catchSideMarkDom[mName] = {dom: dom,}}}}const setRefMain = (d: HTMLElement) => {if (getDomStyle(d, 'position') === 'static') {d.style.position = 'relative'}refMain.value = d// 缓存const children: any = d.childrenfor (let i=0; i<children.length; i++) {const dom = children[i]const mName = dom.getAttribute('mark')if (mName) {catchMainMarkDom[mName] = {dom: dom,top: dom.offsetTop}catchMainMarkTop.unshift(dom.offsetTop)}}// 绑定refMain.value.addEventListener('scroll', bindMainScroll)}const setMark = (str: string) => {mark.value = strconst dom = catchMainMarkDom[str]['dom']dom.scrollIntoView({behavior: "smooth"});}const bindMainScroll = (e: any) => {clearTimeout(timer)const scrollTop = e.target.scrollToptimer = setTimeout(() => {// 判断top值和scroll比较,获取最近的top值,获取新的mark值let newTop = 0for (let i=0; i<catchMainMarkTop.length; i++) {if (scrollTop >= catchMainMarkTop[i]) {newTop = catchMainMarkTop[i]break;}}let markName = ''// 通过newTop值,获取新的mark名称for (let mName in catchMainMarkDom) {if (catchMainMarkDom[mName]['top'] === newTop) {markName = mNamebreak}}if (mark.value === markName) return;mark.value = markNameconst isView = sideDomView[markName] > 0if (!isView) {catchSideMarkDom[markName]['dom'].scrollIntoView({behavior: "smooth"});}}, 200)}const unbind = () => {refMain.value.removeEventListener('scroll', bindMainScroll)io?.disconnect()io = null}return {mark,setMark,setRefSide,setRefMain,unbind}
}

3、使用,hooks抛出了5个方法,作用分别是:
mark:标示字符,用于判断分类

setMark:当分类点击时,传入mark值

setRefSide:传入dom元素,分类的scroll元素

setRefMain:传入dom元素,商品的scroll元素

unbind:组件卸载时调用

4、使用规则

a、用原生滚动

b、需要在页面渲染后使用

c、依次调用setRefSide,setRefMain,setMark

d、在分类列表和产品列表,scroll元素的子元素,需要绑定mark标示,用于匹配

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/43833.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Milvus核心设计(2)-----TSO机制详解

目录 背景 动机 Timestamp种类及使用场景 Guarantee timestamp Service timestamp Graceful time Timestamp同步机制 主流程 时间戳同步流程 背景 Milvus 在设计上突出了分布式的设计,虽然Chroma 也支持分布式的store 与 query。但是相对Milvus来说,不算非常突出。…

Python 神器:wxauto 库——解锁微信自动化的无限可能

&#x1f4dd;个人主页&#x1f339;&#xff1a;誓则盟约 ⏩收录专栏⏪&#xff1a;机器学习 &#x1f921;往期回顾&#x1f921;&#xff1a;“探索机器学习的多面世界&#xff1a;从理论到应用与未来展望” &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f…

mysql高并发设计

mysql高并发设计 一、部署方案 https://blog.csdn.net/weixin_37519752/article/details/138728036 方案1&#xff1a;双主 1、优点 写入扩展性&#xff1a;两个节点都可以处理写入操作&#xff0c;提高了写入操作的扩展性。 高可用性&#xff1a;在任一节点故障时&#xff…

数据结构复习计划之复杂度分析(时间、空间)

第二节&#xff1a;算法 时间复杂度和空间复杂度 算法(Algorithm)&#xff1a;是对特定问题求解方法(步骤)的一种描述&#xff0c;是指令的有限序列&#xff0c;其中每一条指令表示一个或多个操作。 算法可以有三种表示形式&#xff1a; 伪代码 自然语言 流程图 算法的五…

猫不吃东西还呕吐是什么原因?可以预防猫咪呕吐的主食冻干推荐

猫咪突然食欲不振&#xff0c;还出现了呕吐的症状&#xff0c;这究竟是为什么呢&#xff1f;结合我多年养猫的经验&#xff0c;让我们一起分析一下可能的原因。 一、 猫不吃东西还呕吐是什么原因 &#xff08;1&#xff09;首先、排除猫瘟 如果你的猫咪一直家养&#xff0c;…

【Android】基于 LocationManager 原生实现定位打卡

目录 前言一、实现效果二、定位原理三、具体实现1. 获取权限2. 页面绘制3. 获取经纬度4. 方法调用5. 坐标转换6. 距离计算7. 完整代码 前言 最近公司有个新需求&#xff0c;想要用定位进行考勤打卡&#xff0c;在距离打卡地一定范围内才可以进行打卡。本文将借鉴 RxTool 的 Rx…

php快速入门

前言 php是一门脚本语言&#xff0c;可以访问服务器&#xff0c;对数据库增删查改&#xff08;后台/后端语言&#xff09; 后台语言&#xff1a;php&#xff0c;java&#xff0c;c&#xff0c;c&#xff0c;python等等 注意&#xff1a;php是操作服务器&#xff0c;不能直接在…

微软开源项目GraphRAG——基于知识图谱的RAG简介

前言 在大型语言模型&#xff08;LLM&#xff09;的前沿研究中&#xff0c;一个核心挑战与机遇并存的领域是扩展它们的能力&#xff0c;以解决超出其训练数据范畴的问题。这不仅要求模型在面对全新数据时仍能保持卓越表现&#xff0c;还意味着开辟了全新的数据分析可能性&…

Hadoop-15-Hive 元数据管理与存储 Metadata 内嵌模式 本地模式 远程模式 集群规划配置 启动服务 3节点云服务器实测

章节内容 上一节我们完成了&#xff1a; Hive中数据导出&#xff1a;HDFSHQL操作上传内容至Hive、增删改查等操作 背景介绍 这里是三台公网云服务器&#xff0c;每台 2C4G&#xff0c;搭建一个Hadoop的学习环境&#xff0c;供我学习。 之前已经在 VM 虚拟机上搭建过一次&am…

简单的基追踪一维信号降噪方法(MATLAB 2018)

基追踪法是基于冗余过完备字典下的一种信号稀疏表示方法。该方法具有可提高信号的稀疏性、实现阈值降噪和提高时频分辨率等优点。基追踪法采用表示系数的范数作为信号来度量稀疏性&#xff0c;通过最小化l型范数将信号稀疏表示问题定义为一类有约束的极值问题&#xff0c;进而转…

SpringSecurity中文文档(Servlet Authorize HttpServletRequests)

Authorize HttpServletRequests SpringSecurity 允许您在请求级别对授权进行建模。例如&#xff0c;对于 Spring Security&#xff0c;可以说/admin 下的所有页面都需要一个权限&#xff0c;而其他所有页面只需要身份验证。 默认情况下&#xff0c;SpringSecurity 要求对每个…

Umi.js 项目中使用 Web Worker

1.配置 Umi.js 在 Umi.js 中&#xff0c;需要通过配置来扩展 Webpack 的功能。在项目根目录下修改 config/config.ts 文件&#xff1a; export default defineConfig({chainWebpack(config) {config.module.rule(worker).test(/\.worker\.ts$/).use(worker-loader).loader(wo…

C语言之指针的奥秘(二)

一、数组名的理解 int arr[10]{1,2,3,4,5,6,7,8,9,10}; int *p&arr[0]; 这里使用 &arr[0] 的⽅式拿到了数组第⼀个元素的地址&#xff0c;但是其实数组名本来就是地址&#xff0c;而且是数组首元素的地址。如下&#xff1a; 我们发现数组名和数组⾸元素的地址打印出…

重要文件放u盘还是硬盘?硬盘和u盘哪个适合长期存储

在数字时代&#xff0c;我们每天都会处理大量的文件。其中&#xff0c;不乏一些对我们而言至关重要的文件&#xff0c;如家庭照片、工作文档、财务记录等。面对这些重要文件的存储问题&#xff0c;我们通常会面临&#xff1a;“重要文件放U盘还是硬盘”、“硬盘和U盘哪个适合长…

Vue2打包部署后动态修改后端接口地址的解决方法

文章目录 前言一、背景二、解决方法1.在public文件夹下创建config文件夹&#xff0c;并创建config.js文件2.编写config.js内容3.在index.html中加载config.js4.在封装axios工具类的js中修改配置 总结 前言 本篇文章将介绍使用Vue2开发前后端分离项目时&#xff0c;前端打包部署…

系统架构师考点--系统安全

大家好。今天我来总结一下系统安全相关的考点&#xff0c;这类考点每年都会考到&#xff0c;一般是在上午场客观题&#xff0c;占2-4分。 一、信息安全基础知识 信息安全包括5个基本要素&#xff1a;机密性、完整性、可用性、可控性与可审查性 (1)机密性&#xff1a;确保信息…

Navicat导入sql文件

文章目录 Navicat导入SQL文件&#xff0c;使用默认导入&#xff0c;不做任何修改报错尝试一修改运行时的选择 尝试二修改my.ini的配置文件 Navicat导入SQL文件&#xff0c;使用默认导入&#xff0c;不做任何修改报错 尝试一 修改运行时的选择 取消勾选 ‘每个运行中运行多重查…

3,区块链加密(react+区块链实战)

3&#xff0c;区块链加密&#xff08;react区块链实战&#xff09; 3.1 哈希3.2 pow-pos-dpos3.3非对称加密&#xff08;1&#xff09;对称加密AES&#xff08;2&#xff09;非对称加密RSA 3.4 拜占庭将军3.5 P2P网络3.6 区块链 3.1 哈希 密码学&#xff0c;区块链的技术名词 …

【Git的基本操作】版本回退 | 撤销修改的三种情况 | 删除文件

目录 5.版本回退 5.1选项hard&后悔药 5.2后悔药&commit id 5.3版本回退的原理 6.撤销修改 6.1情况一 6.2情况二 6.3情况三 ​7.删除文件 Git重要能力之一马&#xff0c;版本回退功能。Git是版本控制系统&#xff0c;能够管理文件历史版本。本篇以ReadMe文件为…

神器!3个免费PPT成品网站推荐+3款AIPPT工具盘点!

熬夜加班做PPT却没有头绪&#xff1f;别再自己憋着想了&#xff01;现在凡事主打一个“抄作业”&#xff0c;想做ppt却没想法&#xff0c;可以去到ppt成品网站搜集PPT模板&#xff0c;或是使用时下流行的AI生成PPT工具&#xff0c;只需输入PPT主题&#xff0c;即可快速生成一份…