当前位置: 首页 > news >正文

商品分类左右联动

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标示,用于匹配

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 平凯星辰黄东旭出席 2024 全球数字经济大会 · 开放原子开源数据库生态论坛
  • 安卓逆向经典案例——XX优品(uniapp)
  • 医院门诊预约挂号小程序模板源码
  • 前端JS特效第30波:jquery图片列表按顺序分类排列图片组效果
  • 【MySQL】MySQL连接池原理与简易网站数据流动是如何进行
  • 【计算机组成原理 | 第二篇】计算机硬件架构的发展
  • 【机器学习】基于线性回归的医疗费用预测模型
  • 硬件开发工具Arduino IDE
  • 关于.NETCORE站点程序部署到nginx上无法访问静态文件和无法正确生成文件的问题解决过程。
  • 【Linux】内核文件系统系统调用流程摸索
  • Windows安装和使用Doccano标注工具
  • linux 文件末尾追加内容
  • C语言之指针的奥秘(二)
  • flutter
  • 09.AOP-尚硅谷Spring零基础入门到进阶,一套搞定spring6全套视频教程(源码级讲解)
  • 【5+】跨webview多页面 触发事件(二)
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • Codepen 每日精选(2018-3-25)
  • create-react-app项目添加less配置
  • Facebook AccountKit 接入的坑点
  • JS字符串转数字方法总结
  • Mysql5.6主从复制
  • node入门
  • Objective-C 中关联引用的概念
  • Spring Boot快速入门(一):Hello Spring Boot
  • Vultr 教程目录
  • 翻译:Hystrix - How To Use
  • 批量截取pdf文件
  • 强力优化Rancher k8s中国区的使用体验
  • 深入浅出Node.js
  • 用element的upload组件实现多图片上传和压缩
  • ​LeetCode解法汇总2808. 使循环数组所有元素相等的最少秒数
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • (¥1011)-(一千零一拾一元整)输出
  • (delphi11最新学习资料) Object Pascal 学习笔记---第13章第1节 (全局数据、栈和堆)
  • (笔记)M1使用hombrew安装qemu
  • (规划)24届春招和25届暑假实习路线准备规划
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (一)使用Mybatis实现在student数据库中插入一个学生信息
  • (原創) 如何刪除Windows Live Writer留在本機的文章? (Web) (Windows Live Writer)
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • (转)全文检索技术学习(三)——Lucene支持中文分词
  • (转贴)用VML开发工作流设计器 UCML.NET工作流管理系统
  • .form文件_SSM框架文件上传篇
  • .Net 6.0--通用帮助类--FileHelper
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .NET 表达式计算:Expression Evaluator
  • .NET4.0并行计算技术基础(1)
  • .Net多线程Threading相关详解
  • .NET开源项目介绍及资源推荐:数据持久层
  • .pyc文件是什么?
  • @Transactional 参数详解
  • [ Linux ] Linux信号概述 信号的产生