我使用Vue2写诗恭贺中秋佳节

529 阅读4分钟

我正在参加「码上掘金挑战赛」详情请看:码上掘金挑战赛来了!

大家好,我是小七月,虽然中秋已经过去了,但是我仍然想为今天的中秋写一篇文章。在这篇文章中我主要实现的有三件事: ① 使用CSS绘制了一轮带有光晕的满月。 ② 使用CSS绘制了一朵移动的云朵。 ③ 写了一首苏轼的《水调歌头》这首诗。下面来看看我是怎么实现的吧。

项目地址如下:

绘制月亮

月亮的绘制比较简单,主要使用到了border-radius属性,绘制一个圆即可。对于光晕,我们则使用box-shandow以及animation动画来实现。下面我们来熟悉一下这三个属性。

border-radius

允许你设置元素的外边框圆角,该属性是一个简写属性,是为了将这四个属性 border-top-left-radiusborder-top-right-radiusborder-bottom-right-radius,和 border-bottom-left-radius 简写为一个属性。 即使元素没有边框,圆角也可以用到 background 上面,具体效果受 background-clip 影响。 当 border-collapse 的值为 collapse 时,border-radius 属性不会被应用到表格元素上。

你既可以使用准确的数值来设置元素的外边框弧度,也可以使用百分比。一共有下面几个方位使用有下面几种情况:

① 当传入一个值时,表示的是四个角的弧度。

② 当传入两个值时,第一个值表示的是左上,右下的弧度,第二个值表示的是右上,左下的弧度。

③ 当传入三个值时,第一个值表示的是左上,第二个值表示的是右上和左下,第三个值表示的是右下。

④ 当传入四个值时,分别表示左上、右上、右下、左下(顺时针)

image.png

总结:一般用的比较多的是只传入一个值,当元素的宽高相同时,传入50%则会绘制一个圆,否则为椭圆。

box-shadow

该属性用于绘制阴影,向元素添加单个 box-shadow 效果时使用以下规则(解释来自于MDN):

  • 当给出两个、三个或四个 <length>值时。

    • 如果只给出两个值,那么这两个值将会被当作 <offset-x><offset-y> 来解释。表示阴影偏移量,x为正值,将在元素的右边,为负值,将在元素的左边。y为正值,表示在元素的下方,为负值,在元素的上方。
    • 如果给出了第三个值,那么第三个值将会被当作<blur-radius>解释。值越大,模糊面积越大,阴影就越大越淡。不能为负值。默认为 0,此时阴影边缘锐利。
    • 如果给出了第四个值,那么第四个值将会被当作<spread-radius>来解释。取正值时,阴影扩大;取负值时,阴影收缩。默认为 0,此时阴影与元素同样大
  • 可选,inset关键字。

  • 可选,<color>值。

若要对同一个元素添加多个阴影效果,请使用逗号将每个阴影规则分隔开。

实现月亮的代码如下:

.moon {
  background: #fcf0bc;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  box-shadow: 0 0 40px #b69e28;
  position: absolute;
  left: 20px;
  top: 10px;
  animation: nucleus 2s infinite linear;
}
/**
 * 光晕效果
 */

@keyframes nucleus {
  0% {
    box-shadow: 0 0 0 transparent;
  }
  50% {
    box-shadow: 0 0 10px #b69e28;
  }
  100% {
    box-shadow: 0 0 0 transparent;
  }
}

实现云朵

云朵主要也是使用box-shadow属性来实现,该实现比较精妙。仔细观察,云朵可以由五个圆来拼凑而成,所以此处我利用box-reduis来绘制一个圆,然后为该元素添加了四个阴影,调式阴影的位置和大小,然后就绘制处了一朵云,也可以自己画四个圆,使用绝对定位来调节圆的位置。代码实现如下:

/*云*/
.cloudy {
  background: #dfe7f2;
  border-radius: 50%;
  box-shadow: #dfe7f2 120px -20px 0 -10px, #dfe7f2 50px -50px, #dfe7f2 80px 20px,
    #dfe7f2 150px 20px 0 -20px;
  height: 100px;
  width: 100px;
  position: absolute;
  left: -10px;
  top: 200px;
  z-index: 5;
  animation: cloudy 5s ease-in-out infinite;
}

实现诗歌的绘制

因为效果为一个字一个字的回显,所以我们需要维护一个二维数组,数组结构为:

ch:{name:字,display:false}
item:[ch] 一个item为一句诗歌
list:[item]
eg: [[{"name":"明","display":true},{"name":"月","display":true},{"name":"几","display":true},{"name":"时","display":true},{"name":"有","display":true}],
[{"name":"把","display":true},{"name":"酒","display":true},{"name":"问","display":true},{"name":"青","display":true},{"name":"天","display":true}]]

然后我们通过控制display的值,来使文字显示。若display值为false,那么字的opacity为0,否则为1,再添加一点点的动画即可。最后需要一个定时器来不断更新这个数组里的display。记得当所有的字都回显之后要把定时器清除。实现代码如下:

<script>
export default {
  name: 'mid-autumn',
  components: {},
  props: {},
  data() {
    return {
      poetry: `明月几时有?把酒问青天。
        不知天上宫阙,今夕是何年。
        我欲乘风归去,又恐琼楼玉宇,高处不胜寒。
        起舞弄清影,何似在人间?转朱阁,低绮户,
        照无眠。不应有恨,何事长向别时圆?人有悲欢离合,
        月有阴晴圆缺,此事古难全。但愿人长久,千里共婵娟`,
      portryList: [],
      position: {
        x: 0,
        y: 0
      },
      timer: null
    };
  },
  computed: {},
  mounted() {
    this.getArrayFromPoetry();

    this.timer = setInterval(() => {
      this.showFont();
    }, 500);
  },
  destroyed() {
    // 组件销毁,关闭定时执行
    if (this.timer) cancelAnimationFrame(this.timer);
  },
  methods: {
    getArrayFromPoetry() {
      const pattern = /[\u4e00-\u9fa5]+/g;
      let matchList = this.poetry.match(pattern);
      matchList.forEach((str) => {
        let piece = [];
        for (let ch of str) {
          piece.push({
            name: ch,
            display: false
          });
        }
        this.portryList.push(piece);
      });
    },
    showFont() {
      let { x, y } = this.position;
      console.log([x, y]);
      let piece = this.portryList[x];
      piece[y].display = true;
      if (y + 1 < piece.length) {
        y += 1;
      } else {
        x += 1;
        y = 0;
      }
      this.position = { x, y };
      if (x >= this.portryList.length) {
        clearInterval(this.timer);
      }
    }
  }
};
</script>