Vue组件-卡片动画倒计时

news/2024/4/30 13:10:38/文章来源:https://blog.csdn.net/pfourfire/article/details/127210377

前言

最近有朋友在做投票的项目,里面有用到一个倒计时的组件,还想要个动画效果。cv大法浸染多年的我,首先想到的是直接找个现有的组件。

通过一通搜索,看上的只有一个 vue2-flip-countdown,但是当我要修改大小和颜色的时候发现改不了,从而直接把源码拉到项目里面,改起来也挺麻烦。

而且,在搜索大法运行几个周天以后,其实心理已经有了一个倒计时开发整体思路,便决定自己封装一个倒计时出来,最终实现效果如下:

需求拆解

1.开发一个开箱即用的组件,实现倒计时的效果,显示模式为 01日01时01分01秒。
2.以终止时间为入参,计算倒计时显示的各个数据。
3.方便的控制显示的文案,以及主题颜色,大小。

组件设计思路

1.组件分为两个部分* animate-clock,控制组件数据结构,例如:自定义文案、将中文时间单位改成英文,是否换行等等* animate-card,动画卡片,即组件里面的具体数字部分,并加上动画。
2.clock 组件中,对传入的 props 进行处理,最核心的为 终止时间(terminalTime),根据终止时间计算
3.通过定时任务,把计算出来的 数据传入 card 组件,触发视图更新。
4.card 组件中,当数据发生改变的时候触发动画效果。
5.【升级】在此基础上进行扩展,变为一个倒计时通用解决方案:* 反向倒计时* 只有数字的倒计时* 只有分、秒的倒计时* 中文、英文字符串倒计时* 动画抽奖* 专注时间计时器* …

具体开发

animate-clock.vue

首先设计视图部分:

<template><div class="animate-clock"><!-- <p>{{days}}{{hours}}{{minites}}{{seconds}}</p> --><span>距离结束还剩</span><animate-card :val="days" :size="16" :self-disabled="disabled" /><span>天</span><animate-card :val="hours" :size="16" :self-disabled="disabled" /><span>时</span><animate-card :val="minites" :size="16" :self-disabled="disabled" /><span>分</span><animate-card :val="seconds" :size="16" :self-disabled="disabled" /><span>秒</span></div>
</template><style lang="scss" scoped> .animate-clock {width: 100%;text-align: center;font-size: 16px;font-weight: bold;padding: 40px 0 ;
} </style> 

很简单的结构,现在版本为截图所示的一行结构,可以看到,完全可以通过业务组件中通过传入 props 的形式,修改每一个部分的文案,而且 样式也可以随时控制。

js 部分主要做这么几件事:

1.接收 props,并声明 data
2.声明一个 工具函数,用来 处理 小于 10 的数字,前面增加 0
3.声明主要业务函数,被定时任务调用的更新数据方法

<script>
import animateCard from './animate-card.vue'export default {components: { animateCard },props: {terminalTime: String,},data() {return {days: ['0', '0'],hours: ['0', '0'],minites: ['0', '0'],seconds: ['0', '0'],setIntVal: null,disabled: false,}},mounted() {// 先调用一次this.updateClock()// 箭头函数不修改当前作用域下的 this 指向this.setIntVal = setInterval(() => {this.updateClock()}, 1000)},methods: { /** * 更新计时器 * @result void */updateClock() {let now = new Date().getTime()let stopTime = 0// 错误入参 处理逻辑try {stopTime = new Date(this.terminalTime).getTime()} catch (err) {console.error(err)return false}// 终止逻辑const remainingTime = stopTime - nowif (remainingTime < 1000) {clearInterval(this.setIntVal)this.setIntVal = null// 计时器 清零this.days = this.hours = this.minites = this.seconds = ['0', '0']this.disabled = trueconsole.log('时间到!')return false}// 计算 日、时、分、秒let days = parseInt(remainingTime / (24 * 60 * 60 * 1000))let hours = parseInt((remainingTime - 24 * 60 * 60 * 1000 * days) / (60 * 60 * 1000))let minites = parseInt((remainingTime - 24 * 60 * 60 * 1000 * days - 60 * 60 * 1000 * hours) /(60 * 1000))let seconds = parseInt((remainingTime -24 * 60 * 60 * 1000 * days -60 * 60 * 1000 * hours -60 * 1000 * minites) /1000)// 更新 datathis.days = this.toStringAndUnshiftZero(days)this.hours = this.toStringAndUnshiftZero(hours)this.minites = this.toStringAndUnshiftZero(minites)this.seconds = this.toStringAndUnshiftZero(seconds)},/** * 转化数字为数组,并在 头部填充 0 * @params num: numnber * @result string[] */toStringAndUnshiftZero(num) {const val = num.toString().split('')if (num < 10) {val.unshift('0')}return val},},
}
</script> 

这一块根本没有什么技术含量,主要是异常数据的处理,和停止逻辑。 其实计时器清零理论上是不需要出现的,但是在测试过程中发现,会出现最后一帧为 01 的情况,就直接清零了。

animate-card

这个组件一开始考虑的很复杂,想着监听数据的变化,触发一个动画的方法,然后这个方法支持重写,提高组件的扩展性,但是时间不允许,后面又觉得不太必要。

最后选择的方案很简单,却提供了一个可以实现 css 能实现的所有效果的思路。

主要思路是通过 vue 的 transition-group 机制,将 0-9 所有的卡片都渲染好,隐藏起来,通过 v-show 来触发绑定在 transition-group 上的动画效果,从而实现动态监听数据变化的效果。

需要注意的是因为宿主项目中 引入了 animate.css,所以就直接使用 animate 的动画效果了。> 有需要的,可以翻看文档 【animate.css 官方文档】进行配置。> 如果直接CV这套代码的话,没有动画效果。

代码如下:

<template><div class="aimate-card"><div class="card-group" v-for="(item,idx) in val" :key="idx" :style="{'font-size': size+'px'}"><transition-group enter-active-class="animate__animated animate__bounceIn" leave-active-class="animate__animated animate__fadeOutDown"><div class="card-item" :class="{'disabled': selfDisabled}" v-for="num in 10" :key="num" v-show="item== num-1">{{num-1}}</div></transition-group></div></div>
</template><script> export default {props: {val: {type: Array,default: () => ['0', '0'],},size: {type: Number,default: 16,},selfDisabled: {type: Boolean,default: false,},},mounted() {console.log(this.selfDisabled)},
} </script><style lang="scss" scoped> .aimate-card {width: auto;display: inline-block;height: 100%;.card-group {display: inline-block;position: relative;width: 40px;padding: 5px;height: 100%;vertical-align: middle;.card-item {position: absolute;background: #3a7fe4;color: #fff;width: 30px;height: 40px;top: -20px;line-height: 40px;}.disabled {background: #ccc !important;}}
} </style> 

看完代码以后很容易发现,我设计的样式其实一点都不好看,可以对 card-item 写一些前端比较炫的效果。而且动画效果也可以自定义。

使用方法

npm 安装

当然没有发布到 npm 上啦!

项目中使用

1.粘贴上面两个 vue 文件
2.在业务页面中 引入并使用

使用方法如下:

<div class="vote-clock"><animate-clock :terminalTime="'2023-07-11 23:27:00'" />
</div> 

CV大法只支持 terminalTime 这一个入参。

后记

这个组件很简单,但是也有很多可以琢磨的地方,更重要的是整理出一个开发通用组件的思路。

另外,这套代码其实只是一个基础结构,扩展性还是很强的,尤其是前面设计思路中第5条中提到的其他功能,在此基础上可以很快速的进行开发,感兴趣的道友可以简单琢磨一下。

大家在工作中不可避免的会遇到多种多样的需要复用的代码块,有的道友会选择提出为一个公共组件或者公共代码块,有的道友则选择使用CV大法直接复用,也有的可能会另辟蹊径在第一个场景的基础上优化为第二套代码。

我以为这三种情况其实就是一个递进的关系,首先CV大法好,发功后发现场景不是完全一致,进行些许优化,进而搞出一个兼容多个可能存在的场景的通用解决方案。

在设计一个组件的时候,需要尽可能的考虑多种场景,并考虑一下后续的升级方案。想兼容所有的场景肯定不可能,那么就要知道当前组件的边界在哪里。所以,在设计组件的时候不能只着眼于当前业务,更要考虑到其他场景。最简单的例如:一个Button组件,除了保证全局的按钮风格一致的前提下,也要考虑到按钮禁用状态,大按钮带图标按钮按钮组这些方面的东西。

以上就是我关于做这个小组件之后进行的一些浅显的思考,共勉之。

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

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

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

相关文章

(附源码)计算机毕业设计SSM游乐园娱乐项目管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Github的使用教程

文章目录注册查找仓库下载代码fork仓库管理创建仓库添加文件提交issue提交/接受PRpages一直想进入工程这块领地&#xff0c;但是好像没咋学过github&#xff0c;今天学一下&#xff0c;先上个名词解释 注册 首先&#xff0c;github其实是不需要邮箱和手机号的&#xff0c;可以…

window11下安装.framework3.5的方法

window11下安装.framework3.5的方法 如果正常安装报错了&#xff0c;可采用如下方法重新安装 一、把安装iso文件 zh-cn_windows_11_business_editions_version_22h2_updated_sep_2022_x64_dvd_515a832b.iso 装载到虚拟盘中H:\sources\sxs\中的文件拷贝到硬盘已存在的盘符F:\w…

容器适配器——stack/queue/priority_queue

目录 一. stack 二. queue 三. priority_queue 1. empty()&#xff0c;top()&#xff0c;size()的实现 2. pop和push的实现 适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结)&#xff0c;该种模式是将一个类的接口转…

C语言:数组参数、指针参数

目录 一.字符指针&#xff0c;指针数组&#xff0c;数组指针简单回顾 二.数组参数、指针参数 一维数组传参 二维数组传参 这里需要注意&#xff1a; 一级指针传参 思考 二级指针传参 思考 一.字符指针&#xff0c;指针数组&#xff0c;数组指针简单回顾 #include<std…

java虚拟机中的双亲委派机制

文章目录双亲委派机制工作原理工作场景调用过程三种加载器调用范围String类加载过程StringTest类加载过程双亲委派机制优点双亲委派机制 Java虚拟机对class文件采用的是按需加载的方式&#xff0c;也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。而且加…

一些有趣的小项目合集~

pyqt人脸识别&#xff1a; nullhttps://www.jb51.net/article/168718.htmpyqt目标检测&#xff1a; 利用PyQt5为目标检测Faster-rcnn-Pytorch添加GUI界面&#xff08;二&#xff09;-python黑洞网 (pythonheidong.com)https://www.pythonheidong.com/blog/article/337144/e2d…

最常见的IMU:MPU6050

I2CI^2CI2C通讯 ​ I2CI^2CI2C is a two-wire interface comprised of the signals serial data (SDA) and serial clock (SCL). In general, the lines are open-drain and bi-directional. In a generalized I-C interface implementation, attached devices can be a maste…

优雅的处理参数校验以及异常

1、前言 编写控制层时&#xff0c;我们可能会自己去校验请求参数&#xff0c;就会出现这样的代码&#xff1a; if (StringUtils.isEmpty(memberSid)) {return new JsonResult(false, "参数memberSid为空"); } if (null test) {return new JsonResult(false, "…

油溶性PbS量子点近红外发射光PL800nm-1600nm

油溶性PbS量子点近红外发射光PL800nm-1600nm 油溶性PbS量子点产品&#xff0c;表面由疏水配体包覆&#xff0c;平均的量子产率为50%&#xff0c;储存时应避免阳光直射&#xff0c;4度密封暗处保存&#xff0c;可以为客户订制生产800nm&#xff5e;1600nm任一波长不同克数的产品…

叶毓睿:元宇宙发展与治理中,治理的主体是谁?治理的对象是谁?

中国移联元宇宙产业委员会联席秘书长、《元宇宙十大技术》著者之一、高效能服务器和存储技术国家重点实验室首席研究员叶毓睿&#xff1a;治理之可能性的关键在于延续性和开创性。 2022年9月24日&#xff0c;元宇宙产业委特别筹备的“发展与治理”2022元宇宙共治大会暨《元宇宙…

【JT-1/2电子式同步检查继电器】

1 用途 JT-1型同步检查继电器用于两端供电线路的自动重合闸线路中&#xff0c;其作用在于检查线路上电压的存在及线路上和变电站汇流排上电压向量间的相角差。 2 结构和原理 2.1 本继电器采用嵌入式安装&#xff0c;其主体部分系插拔式结构 2.2 本继电器主体部分与DT-1型同…

【Python基础面向对象】self、类变量和实例变量、__init__

哈喽兄弟们&#xff0c;我们接着上篇继续学习面向对象。 面向对象化编程所有的实例对象和实例方法都必须以self作为第一个参数&#xff0c;文章内容接上一章&#xff1a;Python面向对象编程基础之面向对象思想和特点、类和对象。这个系列将会很详细的解释清楚Python面向对象编程…

java实现多层级目录树详解

一&#xff0c;引言 在开发中&#xff0c;经常遇到前端需要实现一个多层级的目录树&#xff0c;那么后端就需要根据这种结构返回对应的数据&#xff0c;因此在这里记录一下本人在开发中是如何实现这个多层级的目录树。 二&#xff0c;建表建库 在建表时&#xff0c;需要注意…

(附源码)计算机毕业设计SSM悠哈出租车管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

模拟IC设计到底怎么学?给初学者一点建议

想必大家都知道&#xff0c;模拟IC设计非常难学。就拿最普遍的晶体管来说&#xff0c;我们分析它的时候必须首先分析直流偏置&#xff0c;其次在分析交流输出电压。可以说&#xff0c;这是一项相当复杂的工作。有些朋友一直吐槽模拟IC设计真的非常难学&#xff0c;那么到底该怎…

SWAT模型 建模方法、实例应用、高级进阶

目录 第一部分&#xff1a;【建模及实践】SWAT模型在水文水资源、面源污染模拟中的实践技术应用及典型案例分析 第二部分&#xff1a;【高级进阶】SWAT模型高阶应用暨无资料地区建模、不确定分析与气候变化、土地利用对面源污染影响模型改进及案例分析 基于ArcGIS的SWAT模型是…

yolov5-6.1的完全使用手册,含模型训练测试(可训练自己的数据集)

安装yolov5 安装命令如下下所示&#xff0c;包含了下载yolov5-6.1&#xff0c;及相关包安装命令。yolov5项目目前已经更新到6.2&#xff0c;支持对图像数据的分类&#xff0c;但使用较为麻烦&#xff0c;因此仅以6.1为例进行说明。安装yolov5后&#xff0c;切记不要安装wandb&…

条件区域循环的Sumif

问题:Sumif条件为D12:D16,求和区域从E3:E8向右,条件区域为B3:D8三列循环 函数解决:=SUMIF(OFFSET($B$3:$B$8,,MOD(COLUMN(C1),3)),$D12,E$3:E$8) 思路: 利用Mod(Column(C1),3),右拉生成0、1、2、0、1、2……这样的循环数 利用Offset,从B3:B8起,右拉生成向右偏移0、1、…

国民技术MCU之串口烧录

国民技术MCU串口烧录 前言 在我们使用国民技术单片机的时候&#xff0c;一般是用JLink SWD来烧录调试固件。 但是在某些情况下&#xff0c;比如需要刷写固件的现场没有JLink工具&#xff0c;采用批量生产、或者MCU在程序上电后SWD功能没有正常运行&#xff08;变砖&#xff0…