前言
去年用了一个小的 app
,叫做 一个木函
,本来想着用来做动画优化就删掉了的,不过看到他有个时间屏幕的小工具,就点进去看了下,觉得挺好玩的,就想着能不能自己实现一下。
ps: 闲话不多说,先上例子点我查看,觉得没啥意思的就不需要再往下看了
简单的搭建一下
初始化一个 vue
项目
然后无脑下一步就好了(回车),这里我打算用 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}`, }; }
function toDou(str) { const num = ~~str; return num > 9 ? num : "0" + str; }
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() { 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) => { if (val == 0) { if (this.numStyle[idx] !== style) { 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) { 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() { 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,希望大家可以一起进步