vue3+Ts+Hook的方式实现商城核心功能sku选择器

前言

Hooks是React等函数式编程框架中非常受欢迎的工具,随着VUE3 Composition API 函数式编程风格的推出,现在也受到越来越多VUE3开发者的青睐,它让开发者的代码具有更高的复用度且更加清晰、易于维护。

本文将通过CRMEB商城商品详情sku选择功能了解Hooks的使用基础以及自定义HOOK开发相关的要点,快速入门。

a5943202401031729583572.jpg

Hook简介

1.什么是hook

Hooks并不是VUE特有的概念,实际上它原本被用于指代一些特定时间点会触发的勾子。而在React16之后,它被赋予了新的意义:

一系列以 use 作为开头的方法,它们提供了让你可以完全避开 class式写法,在函数式组件中完成生命周期、状态管理、逻辑复用等几乎全部组件开发工作的能力

在VUE3中,Hooks的概念结合了VUE的响应式系统,被称为组合函数。组合函数是VUE3组合式API中提供的新的逻辑复用的方案,是一类利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数,简单来说,它就是一个创建工具的工具.

2.Hooks与composition Api

Hooks是一种基于闭包的函数式编程思维产物,所以通常我们会在函数式风格的框架或组件中使用Hook,比如VUE的组合式API(Composition Api)。Hooks在VUE2所使用的选项式风格API中也不是不可以使用,毕竟Hook本质只是一个函数,只要hook内部所使用的api能够得到支持,我们可以在任何地方使用它们,只是可能需要额外的支持以及效果没有函数式组件中那么好,因为仍会被选项分割。

VUE3推出时为开发者带来了全新的Composition API即组合式API。它是一种通过函数来描述组件逻辑的开发模式。组合式API为开发者带来了更好的逻辑复用能力,通过组合函数来实现更加简洁高效的逻辑复用。

为什么要使用Hooks

在以往VUE2的选项式API中,主要通过Mixin或是Class继承来实现逻辑复用,但这种方式有三个明显的短板:

1.不清晰的数据来源:当使用了多个mixin/class时,哪个数据是哪个模块提供的将变得难以追寻,这将提高维护难度

2.命名空间冲突:来自多个class/mixin的开发者可能会注册同样的属性名,造成冲突

3.隐性的跨模块交流:不同的mixin/class之间可能存在某种相互作用,产生未知的后果

以上三种主要的缺点导致在大型项目的开发中,多mixin/class的组合将导致逻辑的混乱以及维护难度的提升,因而在VUE3的官方文档中不再继续推荐使用,保留mixin也只是为了迁移的需求或方便VUE2用户熟悉。

mixin的缺点其实就是Hooks的优点:

1.清晰一目了然的源头

2.没有命名冲突的问题

3.精简逻辑

怎么开始玩Hooks

Hooks的各类规范

1.通常来讲,一个Hook的命名需要以use开头,比如useTimeOut,这是约定俗成的,开发者看到useXXX即可明白这是一个Hook。Hook的名称需要清楚地表明其功能。

2.只在当前关注的最顶级作用域使用Hook,而不要在嵌套函数、循环中调用Hook

3.函数必须是纯函数,没有副作用

4.返回值是一个函数或数据,供外部使用

5.Hook内部可以使用其他的Hook,组合功能

6.数据必须依赖于输入,不依赖于外部状态,保持数据流的明确性

7.在Hook内部处理错误,不要把错误抛出到外部,否则会增加hook的使用成本

8.Hook是单一功能的,不要给一个Hook设计过多功能。单个Hook只负责做一件事,复杂的功能可以使用多个Hook互相组合实现,如果给单个Hook增加过多功能,又会陷入过于臃肿、使用成本高、难维护的问题中

下面通过一个简单的hooks感受一下它的魅力:

这是一个控制页面弹窗或者抽屉显示或隐藏的hook,在以往vue2中,我们实现这样一个功能,需要在data中定义一个变量,在methods中大概率会写两个方法分别控制弹窗的显示和隐藏,如果页面有多个这样的显隐组件,我们的代码简直是灾难,糟糕的事,我们的代码中这样的案例实在是太多了,有了hooks就完全不一样了.

这是一个useBoolean的hooks,可以看到它抛出了一个响应式的布尔值和四个方法.在使用的组件内就可以多次使用该方法,从而简化代码

import { ref } from 'vue';/*** boolean组合式函数* @param initValue 初始值*/
export default function useBoolean(initValue = false) {const bool = ref(initValue);function setBool(value: boolean) {bool.value = value;}function setTrue() {setBool(true);}function setFalse() {setBool(false);}function toggle() {setBool(!bool.value);}return {bool,setBool,setTrue,setFalse,toggle,};
}

3e1e0202401031733568131.png

通过这个例子发现,我们在vue2中大概率要写6个方法和定义三个变量的工作在vue3配合Hooks的情况下,三行代码就实现了.

下面进入我们本文的重点,通过hooks的方式实现sku选择器的功能.

a183f202401031730208119.png

在CRMEB各个项目中,加购功能并不是只有在商品详情页使用,还有很多页面也有使用,比如商品分类的几个模板,购物车页面,搭配购等,都会需要到打开sku选择商品规格的功能,改功能包含选择商品规格,价格,库存,规格图跟随切换实时变化,还有加购数量的操作,对库存为0的规格做不可操作的限制等等,所以这段代码在前端是非常臃肿庞大的一部分代码,牵扯的业务复杂,功能广泛,若是在需要的组件内每次复制粘贴,代码量就会非常庞大,所以若是可以将这部分功能单独抽离出来整理为一个可调用的方法就非常适合我们的使用场景.

先截图看看以前vue2的方式书写的该段代码.

bbf1a202401031712117992.png

f4c36202401031712371200.png

下面是我用vue3+ts+hooks的方式实现一下,代码如下:

import { ref, reactive, watch, unref } from 'vue';
import { cloneDeep } from 'lodash-es';
export default function useSkuSelect(productInfo: Product.Details) {watch(productInfo, () => {attr.productAttr = cloneDeep(productInfo.productAttr);DefaultSelect();});// 向sku选择器传递的数据const attr = reactive({productAttr: [],productSelect: createDefaultModel(),});const attrTxt = ref('请选择');const attrValue = ref('');attr.productAttr = productInfo.productAttr;function DefaultSelect() {let productAttr = attr.productAttr;let valueObj: Array = [];let value: Array = [];let productValue = productInfo.productValue;for (const key in productValue) {if (Object.prototype.hasOwnProperty.call(productValue, key)) {const element = productValue[key];if (element.stock > 0) {valueObj = attr.productAttr.length ? key.split(',') : [];break;}}}// 处理已售罄时默认选中第一个if (!valueObj.length && productAttr.length) {// value = Object.keys(productValue)[0].split(',');} else {value = valueObj;}for (let index = 0; index < productAttr.length; index++) {productAttr[index]!.index = value[index];}// 排序type selectPro = Pick;let productSelect: selectPro = productValue[value.join(',')];if (productSelect && productAttr.length) {attr.productSelect = createProductSelect(1, productSelect);attrValue.value = value.join(',');attrTxt.value = '已选择';} else if (!productSelect && productAttr.length) {attr.productSelect = createProductSelect(2, productSelect);attrValue.value = '';attrTxt.value = '请选择';} else if (!productSelect && !productAttr.length) {attr.productSelect = createProductSelect(3, productSelect);attrValue.value = '';attrTxt.value = '请选择';}}function attrVal(val: Product.AttrVal) {const { index, indexn } = val;const attrValue = attr.productAttr[index]!.attr_values[indexn];attr.productAttr[index]!.index = attrValue;}function ChangeAttr(res: any) {let productSelect = productInfo.productValue[res];if (productSelect && productSelect.stock >= 0) {attr.productSelect = createProductSelect(1, productSelect);attrValue.value = res;attrTxt.value = '已选择';} else {attr.productSelect = createProductSelect(2, productSelect);attrValue.value = '';attrTxt.value = '请选择';}}/**** @param type* true 加* false 减*/function changeCartNum(type: boolean) {// 获取当前变动属性let proSelect = productInfo.productValue[unref(attrValue)];//无属性值即库存为0;不存在加减;if (!proSelect) return;let stock = proSelect.stock || 0;if (attr.productSelect.cart_num) {if (type) {attr.productSelect.cart_num++;if (attr.productSelect.cart_num > stock) {attr.productSelect.cart_num = stock ? stock : 1;}} else {if (attr.productSelect.cart_num <= 1) {attr.productSelect.cart_num = 1;} else {attr.productSelect.cart_num--;}}}}function createProductSelect(type: number, productSelect: any): Product.selectPro {let proSelect: Product.selectPro = createDefaultModel();if (type === 1) {proSelect = {store_name: productInfo.storeInfo.store_name,image: productSelect.image,price: productSelect.price,stock: productSelect.stock,unique: productSelect.unique,cart_num: 1,vip_price: productSelect.vip_price,};} else if (type === 2) {proSelect = {store_name: productInfo.storeInfo.store_name,image: productInfo.storeInfo.image,price: productInfo.storeInfo.price,stock: 0,unique: '',cart_num: 0,vip_price: productInfo.storeInfo.vip_price,};} else if (type === 3) {proSelect = {store_name: productInfo.storeInfo.store_name,image: productInfo.storeInfo.image,price: productInfo.storeInfo.price,stock: productInfo.storeInfo.stock,unique: '',cart_num: 1,vip_price: productInfo.storeInfo.vip_price,};}return proSelect;}function createDefaultModel(): Product.selectPro {return {store_name: '',image: '',price: '',stock: 0,vip_price: '',unique: '',cart_num: 0,};}return {ChangeAttr,attrVal,changeCartNum,attrValue,attrTxt,attr,};
}

在使用sku选择器组件的页面上使用:

08ddd202401031735273907.png

1228d20240103173613725.png

这是一个管理sku选择器内商品规格选择的Hook,在使用时只需传入该商品的详情数据以及一些配置项即可快默认选中,节省了大量重复的控制代码,使用该Hook后只需调用useSkuSelect即可实现规格的切换,加购数量的控制等等,且继承原接口的类型.因为本人其实也是hooks小白,处于学习阶段,书写的该hook和ts代码有可能并不规范,欢迎读者交流指正.

总结

Hooks是VUE3中利用组合式API响应式的特性的,实现简单高效的逻辑复用、提高开发效率、提高VUE模块可维护性的工具。Hooks的组合可以让组件低代价、高效率地实现高复杂度业务,Hooks之间通常相互独立,没有过度耦合,降低后期陷入维护地狱的风险,而且可以使得功能模块更加易于测试.使用开源的Hook将为开发带来很多方便,而开发自定义Hook则需要花费一些时间,但在实现后,高度的定制化将为项目开发带来巨大的便利.Hooks的出现不意味着抛弃Class,Hooks也有自己的缺点比如内存泄漏和可能的性能问题。Class更加易于上手,在经验丰富、技术深厚的开发者手中也可以一定程度上避开Class的缺点

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

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

相关文章

iOS苹果和Android安卓测试APP应用程序的差异

Hello大家好呀&#xff0c;我是咕噜铁蛋&#xff01;我们经常需要关注移动应用程序的测试和优化&#xff0c;以提供更好的用户体验。在移动应用开发领域&#xff0c;iOS和Android是两个主要的操作系统平台。本文铁蛋讲给各位小伙伴们详细介绍在App测试中iOS和Android的差异&…

Flyweight享元/共享模式(对象性能)

Flyweight 链接&#xff1a;享元模式实例代码 解析 目的 在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中&#xff0c;从而带来很高的运行时代价——主要指内存需求方面的代价。如何在避免大量细粒度对象问题的同时&#xff0c;让外部客户程序仍然…

快速、准确地检测和分类病毒序列分析工具 ViralCC的介绍和详细使用方法, 附带应用脚本

介绍 viralcc是一个基因组病毒分析工具&#xff0c;可以用于快速、准确地检测和分类病毒序列。 github&#xff1a;dyxstat/ViralCC: ViralCC: leveraging metagenomic proximity-ligation to retrieve complete viral genomes (github.com) Instruction of reproducing resul…

java基于ssm框架的滁艺咖啡在线销售系统+vue论文

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装滁艺咖啡在线销售系统软件来发挥其高效地信息处理的作用&am…

客服系统接入FastGPT

接入FastGPT 点击【应用】【外部使用】【API访问】【新建】新建一个KEY&#xff0c;同时也可以看到我们的API根地址 这个根地址和Key可以填入任何支持OpenAI接口的应用里&#xff0c;这个接口是兼容OpenAI格式。 在客服系统【知识库AI配置】里填上接口地址和接口密钥。这样我…

更新!又10本期刊被踢,Scopus期刊目录-第九版(附下载)

Scopus概况 Scopus是Elsevier创立于2004年的摘要和引文数据库&#xff0c;同时也是全世界最大的摘要和引文数据库&#xff0c;涵盖了丛书、期刊和行业期刊这三种资源类型。 截止到2023年8月&#xff0c;Scopus期刊目录中共包含期刊44049本。 Scopus与SCIE或SSCI一样&#xf…

第十四章 14.2案例:使用KVM命令集管理虚拟机

查看命令帮助 [rootLinux01 ~]# virsh -h—————————————————————————————————————————— 查看KVM的配置文件存放目录〈test01 , xml是虚拟机系统实例的配置文件) [rootLinux01 ~]# ls /etc/libvirt/qemu —————————————…

Git 常用命令详解及如何在IDEA中操作

文章目录 前言发现宝藏一、初识Git1.Git概述2. Git的功能3. Git运行图示 二、Git下载安装三、Git 代码托管服务1.常用的 Git 代码托管服务2.使用码云代码托管服务 四、Git 常用命令1.Git 全局设置2.获取Git 仓库3.工作区、暂存区、版本库 概念4.Git 工作区中文件的两种状态5.本…

第一课:Transformer

第一课&#xff1a;Transformer 文章目录 第一课&#xff1a;Transformer1、学习总结&#xff1a;什么是语言模型&#xff1f;大语言模型&#xff08;LLM&#xff09;技术演变史注意力机制Transformer结构课程ppt及代码地址 2、学习心得&#xff1a;3、经验分享&#xff1a;4、…

【VSCode】CMake Language Support 总是下载 .NET 超时,但又不想升级dotnet

错误信息 Error: Could not resolve dotnet path!An error occurred while installing .NET (6.0): .NET Acquisition Failed: Installation failed: Error: .NET installation timed out. You may need to change the timeout time if you have a slow connection. Please se…

【基础篇】十三、强软弱虚引用、终结器引用

文章目录 0、相关&#x1f58a;1、强引用2、软引用3、弱引用4、虚引用5、终结引用 关于对象能否被回收&#xff1a; 计数器可达性分析 还可以根据引用的类型&#xff0c;不同的引用类型&#xff0c;对应对象的不同GC回收规则。 0、相关&#x1f58a; &#x1f4d5;【强软弱虚…

高质量发展项目——糖尿病管理医药共话交流会在京成功举行

为积极配合国家在卫生事业改革发展的前进方向&#xff0c;抓好医院管理的顶层设计&#xff0c;中国初级卫生保健基金会公共卫生专业委员会与国家卫生健康委人才交流服务中心于2023年7月18日成功举行高质量发展项目—糖尿病管理医药共话交流会。此次会议邀请全国内分泌领域及药学…

gRPC 为什么这么快?

gRPC 为什么这么快&#xff1f; 本文转自 公众号 ByteByteGo&#xff0c;如有侵权&#xff0c;请联系&#xff0c;立即删除 RPC&#xff08;Remote Procedural Call, 远程过程调用&#xff09;之所以被称为 remote&#xff0c;因为在微服务架构下&#xff0c;RPC 可以实现远程服…

【大数据】安装 Zookeeper 单机版

安装 Zookeeper 单机版 下面安装 Zookeeper&#xff0c;由于它是 Apache 的一个顶级项目&#xff0c;所以域名是 zookeeper.apache.org&#xff0c;所有 Apache 的顶级项目的官网都是以项目名 .apache.org 来命名的。 点击 Download 即可下载&#xff0c;这里我们选择的版本是 …

Python 简单爬虫程序及其工作原理

前言 网络中包含大量的数据&#xff0c;这些数据对于我们来说是非常有价值的&#xff0c;因此编写一个爬虫程序&#xff0c;自动从网页中获取所需的数据&#xff0c;对于信息收集和分析是非常有帮助的。Python 是一种高效而灵活的编程语言&#xff0c;它提供了强大的库和框架来…

软考报名有哪些要求?

报考任何级别不需要学历、资历条件&#xff0c;只要达到相应的专业技术水平就可以报考相应的级别 (一)2024年软考报名入口 2024年软考采用网络报名方式&#xff0c;考生在报名期间进入中国计算机技术职业资格网 (中国计算机技术职业资格网)&#xff0c;点击页面右下角的报名入…

JAVA学习专栏

JAVA专栏 Java核心技术 Java核心技术 Java练手算法 Java练手算法 Java数据结构和算法 Java数据结构和算法 Java设计模式 Java设计模式 Java并发编程 Java并发编程 MySQL数据库 MySQL数据库 Java项目管理Maven Java项目管理Maven 项目管理工具gradle 项目管理工具gradle…

分布式锁Lock4J 使用总结

Lok4j 简介 lock4j是一个分布式锁组件&#xff0c;其提供了多种不同的支持以满足不同性能和环境的需求。 立志打造一个简单但富有内涵的分布式锁组件。 特点 简单易用&#xff0c;功能强大&#xff0c;扩展性强。支持redission,redisTemplate,zookeeper。可混用&#xff0c…

分布式【Zookeeper三大核心之数据节点ZNode】

ZooKeeper在分布式领域&#xff0c;能够帮助解决很多很多的分布式难题&#xff0c;但是底层却只是依赖于两个主要的组件&#xff1a;ZNode文件/数据存储系统和watch监听系统&#xff0c;另外还有一大模块&#xff0c;就是ACL系统。本节我们介绍下znode文件/数据存储系统。 一、…

【QT】自定义代理类

目录 1 我们为什么要使用自定义代理类&#xff1f; 2 自定义代理类的基本设计要求 3 自定义代理的功能 4 基于QSpinBox的自定义代理类 5 自定义代理类的使用 1 我们为什么要使用自定义代理类&#xff1f; 传统的模型-视图框架可以让我们实现逻辑展示相分离&#xff0c;我们…