🎑提前祝大家中秋快乐,教你做一个【中秋花灯许愿】💖的网站

简介: 为了参加掘金社区的中秋征文活动专门策划了这么一个小站。但是物尽其用,我最近自研了一套Web网站基于扫小程序码登录的机制,正好借这个小站测试一下。

用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>


渲染出来它长这个样子


image.png



由于还得玩点花里胡哨的动画,所以我们不能在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,结合rotateZrotateXrotateY将花瓣旋转指定角度


image.png


transform: rotateZ(0deg) rotateX(0deg) rotateY(0deg);


花瓣现在有点少,我们多加三层,每一层花瓣的倾斜角度都比上一层大一点


image.png


继续升级,花瓣颜色得是红里透白呀。


<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>


image.png


放个俯视视角,方便大家更好的理解


image.png


莲花灯我们已经完成,现在写一个简单的页面,让莲花灯在静谧的湖面上飘起来~


让花灯转起来


和刚才花瓣倾斜的方法一样,用transform,但这次我们创建一个css动画animation


@keyframes rotate {
  from {
    transform: rotateX(0deg) rotateZ(0deg);
  }
  to {
    transform: rotateX(0deg) rotateZ(360deg);
  }
}


image.png


加上rotateX


@keyframes rotate {
  from {
    transform: rotateX(70deg) rotateZ(0deg);
  }
  to {
    transform: rotateX(70deg) rotateZ(360deg);
  }
}


image.png


漂在水面上


其实现在让花灯产生位移,就很有漂在水面的感觉了


image.png


当然我们可以再细节一点,从右下角漂到左上角,并加入一些近大远小的视觉差,这个我们后面再完善。


静谧的湖面


作为一个写意流程序员,重要的是意境,要合理的激发用户的想象力,不要什么都靠视觉


哈哈哈


哈哈哈哈


哈哈哈哈哈


主要原因是我试了几种波光粼粼的湖面,搭起来太难看了,还不如不要,就此作罢


云开发建站


为什么推荐大家用uniCloud


因为DCloud打钱了??


真没有!


其实用任意免费的云开发服务都可以,我看重的就是免费,免费静态网页托管,免费CDN....说白了就是一分钱不用掏,就可以搭建一个网站。还不是一个,uniCloud阿里云免费服务空间最多可以创建50个。


扫小程序码登录


我自研了一个基于扫小程序码登录Web网站的机制,会另起文章再给大家分享。目前我还没见过其他有扫小程序码扫码登录的网站,如果大家知道的话,请在评论区发给我瞅瞅。


新建心愿


image.png

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来剔除掉指定字段


心愿点赞


image.png


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的联表查询,更重要的是可以让大家帮我测试一下扫小程序码登录网站的机制。


如果测试下来没什么问题,我后续还会基于此开发很多有意思的东西。



相关文章
|
存储 弹性计算 缓存
阿里云服务器ECS实例选型与性能监控指南:从场景匹配到优化参考
随着云服务器的普及应用,越来越多的企业和个人用户选择将业务迁移到云端,以享受其带来的灵活性、可扩展性和成本效益。阿里云服务器(Elastic Compute Service,简称ECS)以其丰富的实例规格、卓越的性能和稳定的运行环境,赢得了广大用户的信赖。然而,对于很多初次接触云服务器产品的新手用户来说,面对阿里云多达几十种的云服务器实例规格,往往感到无从下手,不知道如何选择最适合自己业务需求的实例规格。本文旨在通过详细解析阿里云ECS实例规格的选择策略,并介绍如何有效监控云服务器性能,确保业务的高效运行。
721 63
|
5月前
|
人工智能 数据可视化 网络安全
2026年阿里云计算巢部署OpenClaw(Clawdbot)AI助手入门教程
在2026年AI自动化办公与轻量运维需求持续升温的背景下,OpenClaw(前身为Clawdbot、曾用名Moltbot)凭借轻量开源、自然语言驱动、多场景适配的核心优势,成为个人办公提效、中小企业轻量运维、团队协同管理的优选工具。与传统AI助手不同,OpenClaw无需复杂的代码开发能力,仅通过简单对话指令,即可完成文档生成、服务器巡检、网页抓取、插件扩展等自动化任务,真正实现“零基础上手、高效率落地”,其核心价值在于能够将自然语言需求转化为可落地的实操任务,摆脱了普通AI助手“只说不做”的局限。
643 1
|
11月前
|
算法 安全 量子技术
“RSA还能撑多久?”——聊聊量子计算下密码学的危与机
“RSA还能撑多久?”——聊聊量子计算下密码学的危与机
699 0
|
SQL 关系型数据库 MySQL
如何优化SQL查询以提高数据库性能?
这篇文章以生动的比喻介绍了优化SQL查询的重要性及方法。它首先将未优化的SQL查询比作在自助餐厅贪多嚼不烂的行为,强调了只获取必要数据的必要性。接着,文章详细讲解了四种优化策略:**精简选择**(避免使用`SELECT *`)、**专业筛选**(利用`WHERE`缩小范围)、**高效联接**(索引和限制数据量)以及**使用索引**(加速搜索)。此外,还探讨了如何避免N+1查询问题、使用分页限制结果、理解执行计划以及定期维护数据库健康。通过这些技巧,可以显著提升数据库性能,让查询更高效流畅。
|
自然语言处理 算法 搜索推荐
《当NLP邂逅GIS:跨界融合的无限可能》
自然语言处理(NLP)与地理信息系统(GIS)的融合正开启全新应用大门,带来智能地理信息检索、地理知识图谱构建、灾害预警优化及智能导航等创新。通过NLP理解复杂语义并转化为GIS指令,降低了用户门槛,提升了效率。然而,数据异构性、语义理解复杂性、计算资源瓶颈及复合型人才短缺等问题仍待解决。尽管面临挑战,未来NLP与GIS的深度融合将为各行业带来更多变革与发展机遇。
382 12
|
人工智能 API 开发者
通过宏实现Word接入DeepSeek
本文介绍如何在Microsoft Word中通过宏接入DeepSeek,实现自动化文本处理。首先确保具备Word 2016及以上版本、DeepSeek API密钥和VBA基础。接着,从豆包平台获取API密钥及模型ID,并在Word中启用开发者选项和宏功能。最后,编写VBA宏代码调用DeepSeek API,完成文本分析与处理。
1117 0
|
机器学习/深度学习 人工智能 自然语言处理
深度解析NLP文本摘要技术:详解与实战
深度解析NLP文本摘要技术:详解与实战
1366 0
|
机器学习/深度学习 人工智能 自然语言处理
LLM 系列 | 18:如何基于LangChain打造联网版ChatGPT?
今天这篇小作文是LangChain实践专题的第2篇,简单介绍LangChain的用途及如何利用LangChain将ChatGPT和搜索引擎(Google)结合起来,从而实现一个极简的联网版ChatGPT。
|
SQL Java 关系型数据库
elastic-job 定时任务集成
elastic-job 定时任务集成
974 0
elastic-job 定时任务集成