用vue实现一个简单的时间屏幕
前言
去年用了一个小的 app
,叫做 一个木函
,本来想着用来做动画优化就删掉了的,不过看到他有个时间屏幕的小工具,就点进去看了下,觉得挺好玩的,就想着能不能自己实现一下。
ps: 闲话不多说,先上例子点我查看,觉得没啥意思的就不需要再往下看了
简单的搭建一下
初始化一个 vue
项目
vue create vue-time
然后无脑下一步就好了(回车),这里我打算用 scss
方便我们书写样式 ,所以创建完成后,我们在安装下 scss
cd vue-time
npm i sass-loader node-sass -D
ps: 如果网络不好,就换下源或者用
cnpm
吧
新建时间屏幕组件
在 components
目录下新建 TimeScreen.vue
文件,然后通过 vbase
指令生成生成一个最基础的 vue
代码片段
ps:
vbase
是vscode
中vue代码片段的一个插件
<template>
<div>
</div>
</template>
<script>
export default {
name: "TimeScreen"
}
</script>
<style lang="scss" scoped>
</style>
思考一下,如何做时间切换的动画
emmm... 不知是否有看过我之前的一篇文章用jq实现的单个span为单个的数字动画,没错,其实我们实现的思路,和这里基本一样,所以接下来我们就分析分析我们该怎么来实现了吧
首先,我们要明确一下,要有多少个 span
,众所周知,一天最后就是23:59:59,所以我们所需要的 span
数组为 [3, 10, 0, 6, 10, 0, 6, 10]
ps: 中间的
:
是只需要一个span
的
因为布局不是我们要将的重点,所以我们就想想我们该怎么获取我们需要的东西。比如,怎么获取到Saturday 14 March
,怎么获取到当前时间
众所周知啦,我们知道 js
中提供了 Date
这个对象,所以我们可以通过他可以获取我们想要的东西,废话不多说了,开始写代码吧。
新建 utils
目录,在该目录下新建 time.js
文件,内容如下
// 月份
const months = [
"January","February","March","April","May","June",
"July","August","September","October","November","December"
];
// 星期
const weekday = [
"Sunday","Monday","Tuesday","Wednesday",
"Thursday","Friday","Saturday"
];
// 获取日期
function getTime() {
const date = new Date();
const days = date.getDate();
const month = date.getMonth();
const day = date.getDay();
const hours = toDou(date.getHours());
const minutes = toDou(date.getMinutes());
const seconds = toDou(date.getSeconds());
return {
date: `${weekday[day]} ${days} ${months[month]}`,
time: `${hours}:${minutes}:${seconds}`
};
}
// 转成两位 eg: 6 => 06
function toDou(str) {
const num = ~~str;
return num > 9 ? num : "0" + str;
}
// 测试一下我们写的方法,上线记得注释掉
// console.log(getTime()) // {date: "Saturday 14 March", time: "18:53:40"}
export default getTime
通过上面代码,我们就得到我们需要的格式啦,接下来就是写布局啦,但这里不是我们的重点,所以略过
<template>
<div
class="time-container"
:class="{ dark: isDark }"
@click="toggleClass"
:date="date"
>
<div class="time">
<template v-for="(str, idx) in time">
<div
class="time-num"
v-if="str !== ':'"
:style="numStyle[idx]"
:key="idx"
>
<span
v-for="(i, spanIdx) in haveSpan[idx]"
:key="spanIdx"
>{{ i - 1 }}</span
>
<span>0</span>
</div>
<div class="time-dist" v-else :key="idx">
<span>{{ str }}</span>
</div>
</template>
</div>
</div>
</template>
<script>
import getTime from "../utils/time";
// 设置样式
function setStyle(val) {
return `transform: translateY(-${~~val * 100}%)`;
}
// 每个字的样式
function numStyle(time) {
return time.split("").map(val => setStyle(val));
}
export default {
name: "TimeScreen",
data() {
const { time,date } = getTime();
return {
isDark: 0,
time,
date,
numStyle: numStyle(time)
};
},
methods: {
// 切换样式
toggleClass() {
this.isDark = !this.isDark;
},
},
created() {
// 判单有多少个Span
// 比较小时数最多24小时,所以第一位最多是3个,0、1、2
// 这里使用 freeze 是因为这个值已经固定,没有必要进行数据劫持
this.haveSpan = Object.freeze([3, 10, 0, 6, 10, 0, 6, 10]);
}
};
</script>
<style lang="scss" scoped>
%flexCenter {
display: flex;
justify-content: center;
align-items: center;
}
$timeColor: #d9d4d0;
$white: #fff;
.time-container {
background: $white;
color: $timeColor;
position: absolute;
width: 100%;
height: 100%;
max-width: 540px;
top: 0;
left: 50%;
transform: translateX(-50%);
&.dark {
background: #000;
color: $white;
}
&::after {
content: attr(date);
position: absolute;
color: $timeColor;
font-size: 18px;
line-height: 1;
transform: rotate(90deg);
bottom: 20%;
left: -48px;
}
@extend %flexCenter;
.time {
font-size: 70px;
transform: rotate(90deg);
position: relative;
height: 106px;
line-height: 106px;
overflow: hidden;
@extend %flexCenter;
.time-num {
position: relative;
width: 100%;
height: 100%;
text-align: center;
text-shadow: 0 0 2px $white;
transition: 0.5s all;
span {
display: block;
}
}
.time-dist {
padding-bottom: 15px;
margin: 0 10px;
}
}
}
</style>
写到这里,其实基本的样子已经出来了,这里我们用到了 attr
函数,用来回选择元素的属性值,这个小技巧在一些场景很用用哦。
这里我们多加了一个 <span>0</span>
这里主要是为了无缝,那么我们如何做到无缝呢?即,当我们滚动最低下的时候,在500ms
之内让动画取消。
ps: 这里的
500ms
是因为动画设置了500ms
,所以需要用1s - 500ms
得出来的500ms
哦
既然知道了原理,那么我们就开始写我们的代码了
首先定义一下清空动画之后的样式,即
// 清除样式
const style = "transform: translateY(0%);transition:0s all";
那么什么时候清空呢,前面也说了,当滚动到最下面的时候,也就是当 time
这个字符串某个为 0
的时候,我们就要清空了,所以
this.time.split("").forEach((val, idx) => {
// 当 val 为 0 时,说明已经滚到最底下,这里需要清除动画,并让他回到最顶上来实现无缝
if (val == 0) {
if (this.numStyle[idx] !== style) {
// 500ms后清除当前这个span的动画
this.removeAnimate(idx);
// 设置样式
this.numStyle[idx] = setStyle(this.haveSpan[idx]);
}
} else {
this.numStyle[idx] = setStyle(val);
}
})
// 清除动画
removeAnimate(idx) {
setTimeout(() => {
this.numStyle[idx] = style;
this.numStyle = [...this.numStyle];
}, 500);
}
最后,就是写一个简单的定时器啦,我想这应该难不倒各位小伙伴啦,所以我就不详解啦,就贴一下代码
<template>
<div
class="time-container"
:class="{ dark: isDark }"
@click="toggleClass"
:date="date"
>
<div class="time">
<template v-for="(str, idx) in time">
<div
class="time-num"
v-if="str !== ':'"
:style="numStyle[idx]"
:key="idx"
>
<span
v-for="(i, spanIdx) in haveSpan[idx]"
:key="spanIdx"
>{{ i - 1 }}</span
>
<span>0</span>
</div>
<div class="time-dist" v-else :key="idx">
<span>{{ str }}</span>
</div>
</template>
</div>
</div>
</template>
<script>
import getTime from "../utils/time";
// 清除样式
const style = "transform: translateY(0%);transition:0s all";
// 设置样式
function setStyle(val) {
return `transform: translateY(-${~~val * 100}%)`;
}
// 每个字的样式
function numStyle(time) {
// 这里等于0则清除样式,避免0点时,有奇怪的bug
return time.split("").map(val => (val == "0" ? style : setStyle(val)));
}
export default {
name: "TimeScreen",
data() {
// 获取时间
let { time, date } = getTime();
return {
isDark: 0,
time,
date,
numStyle: numStyle(time)
};
},
methods: {
// 更新样式
updateStyle() {
this.time.split("").forEach((val, idx) => {
if (val == 0) {
if (this.numStyle[idx] !== style) {
this.removeAnimate(idx);
this.numStyle[idx] = setStyle(this.haveSpan[idx]);
}
} else {
this.numStyle[idx] = setStyle(val);
}
});
},
// 切换样式
toggleClass() {
this.isDark = !this.isDark;
},
// 清除样式
removeAnimate(idx) {
setTimeout(() => {
this.numStyle[idx] = style;
this.numStyle = [...this.numStyle];
}, 500);
},
// 每秒更新时间
updateTime() {
const { time, date } = getTime();
this.time = time;
this.date = date;
this.updateStyle();
}
},
created() {
// 判单有多少个Span
// 比较小时数最多24小时,所以第一位最多是3个,0、1、2
this.haveSpan = Object.freeze([3, 10, 0, 6, 10, 0, 6, 10]);
// 定时器
this.timer = null;
},
mounted() {
// 触发定时器
this.timer = setInterval(this.updateTime, 1000);
},
destroyed() {
// 清除定时器
clearInterval(this.timer);
}
};
</script>
<style lang="scss" scoped>
%flexCenter {
display: flex;
justify-content: center;
align-items: center;
}
$timeColor: #d9d4d0;
$white: #fff;
.time-container {
background: $white;
color: $timeColor;
position: absolute;
width: 100%;
height: 100%;
max-width: 540px;
top: 0;
left: 50%;
transform: translateX(-50%);
&.dark {
background: #000;
color: $white;
}
&::after {
content: attr(date);
position: absolute;
color: $timeColor;
font-size: 18px;
line-height: 1;
transform: rotate(90deg);
bottom: 20%;
left: -48px;
}
@extend %flexCenter;
.time {
font-size: 70px;
transform: rotate(90deg);
position: relative;
height: 106px;
line-height: 106px;
overflow: hidden;
@extend %flexCenter;
.time-num {
position: relative;
width: 100%;
height: 100%;
text-align: center;
text-shadow: 0 0 2px $white;
transition: 0.5s all;
span {
display: block;
}
}
.time-dist {
padding-bottom: 15px;
margin: 0 10px;
}
}
}
</style>
最后的最后
感谢各位观众老爷的观看啦O(∩_∩)O,希望大家可以一起进步
用vue实现一个简单的时间屏幕的更多相关文章
- 用Vue开发一个实时性时间转换功能,看这篇文章就够了
前言 最近有一个说法,如果你看见某个网站的某个功能,你就大概能猜出背后的业务逻辑是怎么样的,以及你能动手开发一个一毛一样的功能,那么你的前端技能算是进阶中高级水平了.比如咱们今天要聊的这个话题:如何用 ...
- 使用Laravel 和 Vue 构建一个简单的SPA
本教程是作者自己在学习Laravel和Vue时的一些总结,有问题欢迎指正. Laravel是PHP的一个框架,Vue是前端页面的框架,这两个框架如何结合起来构建一个SPA(Single Page Ap ...
- 用 Vue 做一个简单的购物app
前言 最近在学习Vue的使用.看了官方文档之后,感觉挺有意思的.于是着手做了一个简单的购物app.h5 与原生 app 交互的原理这是我第一次在这个网站上写分享,如有不当之处,请多多指教. 一整个项目 ...
- [Vue]写一个简单的文件上传控件
这篇将介绍如何写一个简单的基于Vue+Element的文件上传控件. 控件将具有 1. 上传队列的列表,显示文件名称,大小等信息,可以显示上传进度实时刷新 2. 取消上传 使用Element的u ...
- vue封装一个简单的div框选时间的组件
记录一下我前段时间封装的一个vue组件吧.技术需要积累,有时间我把我之前写的还不错的组件都开源出来.并尝试vue和react 两种方式的组件封装.今天简单写下鼠标框选div选中效果的封装吧. div框 ...
- vue实现一个简单的选项卡
用vue来实现一个小的选项卡切换,比之前要简单.方便很多. <!DOCTYPE html> <html lang="en"> <head> &l ...
- 基于vue实现一个简单的MVVM框架(源码分析)
不知不觉接触前端的时间已经过去半年了,越来越发觉对知识的学习不应该只停留在会用的层面,这在我学jQuery的一段时间后便有这样的体会. 虽然jQuery只是一个JS的代码库,只要会一些JS的基本操作学 ...
- 用Vue实现一个简单的图片轮播
本文已收录至https://github.com/likekk/studyBlog欢迎大家star,共同学习,共同进步.如果文章有错误的地方,欢迎大家指出.后期将在将GitHub上规划前端学习的路线和 ...
- 用Vue编写一个简单的仿Explorer文件管理器
大家一定很熟悉你桌面左上角那个小电脑吧,学名Windows资源管理器,几乎所有的工作都从这里开始,文件云端化是一种趋势.怎样用浏览器实现一个Web版本的Windows资源管理器呢?今天来用Vue好好 ...
随机推荐
- Shell脚本定时监控
1.建立脚本文件 autostart.sh #!/bin/bashexport JAVA_HOME=/home/java/jdk1.8.0_191export JRE_HOME=$JAVA_HOME/ ...
- 【雕爷学编程】Arduino动手做(5)---热敏温度传感器模块
37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器模块,依照实践(动手试试)出真知的理念,以学习和交流为目的,这里准备逐 ...
- java判断是否是合法IP
public boolean ipCheck(String text) { if (text != null && !text.isEmpty()) { // 定义正则表达式 Stri ...
- 两圆相交求面积 hdu5120
转载 两圆相交分如下集中情况:相离.相切.相交.包含. 设两圆圆心分别是O1和O2,半径分别是r1和r2,设d为两圆心距离.又因为两圆有大有小,我们设较小的圆是O1. 相离相切的面积为零,代码如下: ...
- CF808E Selling Souvenirs
题目链接: http://codeforces.com/contest/808/problem/E 题目大意: Petya 有 n 个纪念品,他能带的最大的重量为 m,各个纪念品的重量为 wi,花费为 ...
- Poj2109 (2) k^n = p.
二分法,由p最大值最小值的中间值开始猜k,通过比较pow(k,n)与p的大小来进一步精确k,直到找到. #include<stdio.h> #include<math.h> # ...
- Verilog语言中的系统任务和系统函数
Verilog语言中预先定义了一些任务和函数,用于完成一些特殊的功能,它们被称为系统任务和系统函数,这些函数大多数都是只能在Testbench仿真中使用的,使我们更方便的进行验证. `timescal ...
- 手把手教你Windows Linux双系统的安装与卸载
作者:-叶丶知秋 链接:https://blog.csdn.net/fanxueya1322/article/details/90205143 转载请保留出处 良许前言: 后台突然有很多小伙伴留言想看 ...
- 实验四:Linux系统C语言开发环境学习
项目 内容 这个作业属于哪个课程 班级课程主页链接 这个作业的要求在哪里 作业要求 学号-姓名 17043133-木腾飞 作业学习要求 1.学习Linux系统中如何查看帮助文档:2.在Linux系统中 ...
- Java基本语法---标识符、变量、数据类型转换及进制
Java基本语法 标识符 标识符:凡事可以自己起名字的地方,都可以叫做标志符 标识符命名规则: 26个字母大小写,数字0-9,下划线_,美元符号$ 数字不能开头 不能使用关键字和保留字,但是可以包含 ...