用CSS绘制一个荷花灯
本小节所示内容来自codepen
首先用svg来绘制一个花瓣
<svg viewBox='0 0 72 200'> <path d='M0,100 C0,66.6666667 12,33.3333333 36,0 C60,33.3333333 72,66.6666667 72,100 C72,133.333333 60,166.666667 36,200 C12,166.666667 0,133.333333 0,100 Z'></path> </svg>
渲染出来它长这个样子
由于还得玩点花里胡哨的动画,所以我们不能在svg
里把所有花瓣都画出来,而是需要在不同的dom节点里画,然后对dom应用动画。
比如下面这个三片花瓣
<div class='lotus'> <ul> <li> <svg viewBox='0 0 72 200'> <path d='M0,100 C0,66.6666667 12,33.3333333 36,0 C60,33.3333333 72,66.6666667 72,100 C72,133.333333 60,166.666667 36,200 C12,166.666667 0,133.333333 0,100 Z'></path> </svg> </li> <li> <svg viewBox='0 0 72 200'> <path d='M0,100 C0,66.6666667 12,33.3333333 36,0 C60,33.3333333 72,66.6666667 72,100 C72,133.333333 60,166.666667 36,200 C12,166.666667 0,133.333333 0,100 Z'></path> </svg> </li> <li> <svg viewBox='0 0 72 200'> <path d='M0,100 C0,66.6666667 12,33.3333333 36,0 C60,33.3333333 72,66.6666667 72,100 C72,133.333333 60,166.666667 36,200 C12,166.666667 0,133.333333 0,100 Z'></path> </svg> </li> </ul> </div>
使用transform
,结合rotateZ
,rotateX
,rotateY
将花瓣旋转指定角度
transform: rotateZ(0deg) rotateX(0deg) rotateY(0deg);
花瓣现在有点少,我们多加三层,每一层花瓣的倾斜角度都比上一层大一点
继续升级,花瓣颜色得是红里透白呀。
<svg class='gradient'> <defs> <radialGradient cx='50%' cy='5%' fx='50%' fy='5%' id='gradient' r='110%'> <stop offset='0%' stop-color='#ffffff'></stop> <stop offset='100%' stop-color='#ff0000'></stop> </radialGradient> </defs> </svg>
放个俯视视角,方便大家更好的理解
莲花灯我们已经完成,现在写一个简单的页面,让莲花灯在静谧的湖面上飘起来~
让花灯转起来
和刚才花瓣倾斜的方法一样,用transform
,但这次我们创建一个css动画animation
@keyframes rotate { from { transform: rotateX(0deg) rotateZ(0deg); } to { transform: rotateX(0deg) rotateZ(360deg); } }
加上rotateX
@keyframes rotate { from { transform: rotateX(70deg) rotateZ(0deg); } to { transform: rotateX(70deg) rotateZ(360deg); } }
漂在水面上
其实现在让花灯产生位移,就很有漂在水面的感觉了
当然我们可以再细节一点,从右下角漂到左上角,并加入一些近大远小的视觉差,这个我们后面再完善。
静谧的湖面
作为一个写意
流程序员,重要的是意境,要合理的激发用户的想象力,不要什么都靠视觉
哈哈哈
哈哈哈哈
哈哈哈哈哈
主要原因是我试了几种波光粼粼的湖面,搭起来太难看了,还不如不要,就此作罢
云开发建站
为什么推荐大家用uniCloud
呢
因为DCloud打钱了??
真没有!
其实用任意免费的云开发服务都可以,我看重的就是免费,免费静态网页托管,免费CDN....说白了就是一分钱不用掏,就可以搭建一个网站。还不是一个,uniCloud阿里云免费服务空间最多可以创建50个。
扫小程序码登录
我自研了一个基于扫小程序码登录Web网站的机制,会另起文章再给大家分享。目前我还没见过其他有扫小程序码扫码登录的网站,如果大家知道的话,请在评论区发给我瞅瞅。
新建心愿
if(event.action==="create"){ //使用JWT对用户身份鉴权,心愿和用户的openid绑定 try{ var payload = utils.verifyToken(event.token); }catch(err){ return utils.responseData(4001,"token校验失败"); } //UGC内容走微信小程序的内容安全审查接口 var res = await msgSecCheck(payload.openid,event.content); if(res.result.suggest!="pass"){ return utils.responseData(1,"该内容无法通过内容安全审查"); } //在数据表(集合)wish中插入数据 var content = event.content; await db.collection("wish").add({ owner:payload.openid, content:content, createtime:Date.now() }) //统一响应格式 return utils.responseData(0,"发布成功",{ content:content, color:color }); }
随机获取心愿
这里我使用聚合操作aggregate随机获取100条心愿,然后在前端显示。
else if(event.action==="get100"){ var dbRes = await db.collection("wish") .aggregate()//进入聚合操作 .sample({ size: 100//随机取100条数据 }) .project({ owner:0//返回的字段里去除owner字段 }) .end();//结束聚合操作 return utils.responseData(0,"",dbRes.data); }
我们应该基于以下两点保护用户的openid
- 用户不应该了解什么是
openid
- 如果万一要知道,最多只能知道自己的,决不允许知道他人的
openid
所以我们在返回的数据中使用field
来剔除掉指定字段
心愿点赞
uniCloud的数据库是MongoDB
,我接触这个的时间也不长。设计这个点赞系统废了不少脑细菌。-_-!
- 点赞/取消赞
else if(event.action==="like"){ //赞肯定是需要用户登录的,所以要鉴权,代码同上为节省空间被我删掉了 //先查询是否有指定id的心愿,查不到就返回错误 dbRes = await db.collection("wish").doc(event.wishid).get(); if(dbRes.affectdDocs<=0)return utils.responseData(1,"心愿id错误"); //先查询有没有点赞记录 dbRes = await db.collection("likes").where({ owner:dbCmd.eq(payload.openid), wishid:dbCmd.eq(event.wishid) }).limit(1).get(); if(dbRes.affectedDocs>0){ //赞过了,取消赞 await db.collection("likes").doc(dbRes.data[0]._id).remove(); return utils.responseData(0,"",{liked:false}); }else{ //没赞过,新建赞记录 await db.collection("likes").add({ wishid:event.wishid, owner:payload.openid }); return utils.responseData(0,"",{liked:true}); } }
由于加入了点赞系统,所以在查询心愿数据的时候,我们还需要通过联表查询来获取点赞总数和当前用户是否已点赞
const $ = db.command.aggregate; var dbRes = await db.collection("wish") .aggregate() .sample({ size: 100 }) .lookup({ from:'likes',//需要联合查询的表名 localField:'_id',//当前表中的哪个字段去匹配 foreignField:'wishid',//外部表中的哪个字段 as:'likes'//新字段名称用于赋值返回结果 }) .addFields({ "likecount":$.size("$likes"),//获取数组的长度,也就是点赞总数 "liked": payload.openid?$.size($.filter({ input:'$likes', as:"item", cond:$.eq(["$$item.owner",payload.openid]) })):false }) .project({ owner:0, likes:0 }) .end()
这里还有个复杂的聚合表达式,我单独拿出来和大家解释下
- 第一部分
$.filter({ input:'$likes', as:"item", cond:$.eq(["$$item.owner",payload.openid]) })
刚才我们已经通过联表查询获得了字段名为likes
的数组,现在我们要从中取得指定openid
是否存在其中,也就是某用户对该条心愿是否点过赞了。这里返回的结果仍然是数组,所以在第二部分,我们继续对它使用size
命令,由于每个人只允许对一条心愿点赞一次,所以我们会获得 0,1,用于
- 第二部分
payload.openid?$.size(filter):false
由于我们允许不登录也可以访问网站,所以要对请求时用户还没登录,也就是没有token
解码的情况兼容。有openid
才去做filter
,没有就直接给false。
至此我们就完成了一个给大家中秋许愿的小网站的前后端开发,把思路打开,你还可以把它变成是树洞,留言板,心愿墙.....期待大家的创意
后记
这个许愿网站是专门为掘金中秋征文活动而开发的,从设计到前后端开发大概一共花了2
天左右,在这个case
中我也得以深入的学习了一下MongoDB
的联表查询,更重要的是可以让大家帮我测试一下扫小程序码登录网站的机制。
如果测试下来没什么问题,我后续还会基于此开发很多有意思的东西。