动态公告牌 - 使用 Vue 和 JavaScript 实现

本文介绍了一种... 极其无聊的 Vue 单页应用 —— 公告牌 —— 包含一个漂亮的动态渐变背景和动态数字大小的单页应用。可以用来计数,以及任何对外显示数字、简要信息的地方。关键是,动态渐变背景很漂亮。

JavaScript 是 Web 前端的核心,尤其是当你希望自己的 CSS 渐变背景能自己动,但是使用 CSS 内置的动画又无法完成的时候。从某种角度来看,这是 HTML 和 CSS 标准 —— 更多的是历史的问题。Web 文档陈旧、笨重,但是似乎不可或缺 —— 从来没有过这样的便捷性,在几乎任何设备上,通过网址就可访问一个应用程序 —— Java 试图做,但是失败了。

这个公告牌的展示如下所示:

面临的问题

背景问题

动态背景参照了 渐变精选 这个网站。但是,如何动态的展示渐变,让它有种流动的感觉,我开始想要使用的是 CSS 的 Translate 动画,当 hover 时自动触发背景的变换,但是发现渐变过渡是被当做 background-image 处理的,这意味着不能通过动画实现。

最后我解决方法是使用 JavaScript 定时器,定时重写 CSS 样式。

至于背景平铺的问题,因为 Vue 难以获取 HTML 元素,因此,我使用的是 Absolute 定位。

数字问题

至于垂直水平居中,这个问题,我使用的是 Flex 来解决的。同时为溢出的部分进行裁剪。

循环动画实现问题

因为动画是用 JavaScript 模拟的,因此,需要手动完成循环往复的动画效果,而不能每次动画完毕之后,立刻回到起始位置,我们想要有一种流畅感 —— 使用了一个中间状态来执行循环往复的判断。

根据屏幕自适应问题

中间的数字要根据屏幕大小自适应,这个不好办,我使用的简单粗暴的方法,直接通过 ComputedStyle 获取在 Window 显示的整个 div 高度,然后重写数字的大小。

最终的实现

代码如下:

<template>
  <div id="app">
    <div id="number">
      {{number()}}
    </div>
    <span class="link">
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Host by abc.mazhangjing.com
    </span>
  </div>
</template>

<script>
import moment from 'moment';
export default {
  name: 'App',
  data() {
    return {
      a: 0,
      left_to_right: true
    }
  },
  methods: {
    number() {
      return moment().diff(moment('20180210','YYYYMMDD'), 'days');
    },
    updateBackground() {
      const app = document.querySelector("#app");
      if (this.a === 30) {
        this.left_to_right = false
      } else if (this.a === 0) {
        this.left_to_right = true
      }
      if (this.left_to_right) {
        this.a = this.a + 2;
      } else {
        this.a = this.a - 2;
      }
      app.style.background='linear-gradient(120deg, #a6c0fe ' + this.a + '%, #f68084 ' + (this.a + 100) + '%)';
    },
    setNumberSize() {
      const number = document.querySelector("#number");
      const appHeight = parseInt(window.getComputedStyle(document.querySelector("#app")).height);
      if (appHeight !== null && appHeight !== 0) number.style.fontSize = appHeight/2 + 'px'
    }
  },
  mounted() {
    setInterval(this.updateBackground, 500);
    this.setNumberSize();
  }
}
</script>

<style>
  #app {
    position: absolute;
    bottom: 0;
    top: 0;
    left: 0;
    right: 0;
    display: flex;
    justify-content: center;
    flex-direction: column;
    align-items: center;
    background: linear-gradient(120deg, #a6c0fe 0%, #f68084 100%);
    overflow: hidden;
  }
  #number {
    font: 30em sans-serif;
    text-align: center;
    color: white;
    opacity: .5;
  }
  .link {
    color: white;
    opacity: 0.3;
    font: 1.2em sans-serif;
    letter-spacing: 1px;
  }
</style>

吐槽

没什么吐槽的,HTML 和 CSS 是 Web 标准,虽然,居中这种事情,在现代浏览器上已经很方便了,但是,动态调整高度,更加强大的动画,相比较客户端技术,比如 Qt/C++/Python 和 Flutter/Dart、JavaFx/Java/Scala/Kotlin/Conjure/Groovy 还是很差。