我正在参加「码上掘金挑战赛」详情请看:码上掘金挑战赛来了!
大家好,我是小七月,虽然中秋已经过去了,但是我仍然想为今天的中秋写一篇文章。在这篇文章中我主要实现的有三件事: ① 使用CSS绘制了一轮带有光晕的满月。 ② 使用CSS绘制了一朵移动的云朵。 ③ 写了一首苏轼的《水调歌头》这首诗。下面来看看我是怎么实现的吧。
项目地址如下:
绘制月亮
月亮的绘制比较简单,主要使用到了border-radius属性,绘制一个圆即可。对于光晕,我们则使用box-shandow以及animation动画来实现。下面我们来熟悉一下这三个属性。
border-radius
允许你设置元素的外边框圆角,该属性是一个简写属性,是为了将这四个属性 border-top-left-radius、border-top-right-radius、border-bottom-right-radius,和 border-bottom-left-radius 简写为一个属性。
即使元素没有边框,圆角也可以用到 background 上面,具体效果受 background-clip 影响。
当 border-collapse 的值为 collapse 时,border-radius 属性不会被应用到表格元素上。
你既可以使用准确的数值来设置元素的外边框弧度,也可以使用百分比。一共有下面几个方位使用有下面几种情况:
① 当传入一个值时,表示的是四个角的弧度。
② 当传入两个值时,第一个值表示的是左上,右下的弧度,第二个值表示的是右上,左下的弧度。
③ 当传入三个值时,第一个值表示的是左上,第二个值表示的是右上和左下,第三个值表示的是右下。
④ 当传入四个值时,分别表示左上、右上、右下、左下(顺时针)
总结:一般用的比较多的是只传入一个值,当元素的宽高相同时,传入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>