使用koa+mysql写一个简易论坛(完)

作者 : 开心源码 本文共6833个字,预计阅读时间需要18分钟 发布时间: 2022-05-12 共193人阅读

一、本期目标

给本系列文章画上一个相对圆满的句号
  • Admin —- 帖子管理的无刷新解决
  • Admin —- 客户管理
  • Admin —- 小黑屋(相当于回收站
  • User —- 简单的搜索功能
  • User —- 留言功能
  • User —- 个人信息设置
  • User —- 更换头像
  • 扩展

二、帖子管理(无刷新) —- Admin

这个其实很简单,说究竟也就是Fetch的使用而已

1、思路
  • 点击对应按钮,使用fetch发送数据到后台
  • 后台通过该数据进行相关操作,判断要返回什么到前台
  • 前台再根据后台返回的数据来进行页面解决
2、实现
  • 对页面标签进行解决:将<a>换成<button>,删除href属性,只保留type和class,而后新添加data-id属性,其值设置为topic的id,我们后面要根据data-id的值来进行相关操作 =>
<button type="button" data-id="<%= topic.id %>"  ><p>64px*64px</p>');            $('.cropped').append('<img id="img2" src="'+img+'" align="absmiddle" style="width:128px;margin-top:4px;border-radius:128px;box-shadow:0px 0px 12px #7E7E7E;"><p>128px*128px</p>');            $('.cropped').append('<img id="img3" src="'+img+'" align="absmiddle" style="width:180px;margin-top:4px;border-radius:180px;box-shadow:0px 0px 12px #7E7E7E;"><p>180px*180px</p>');            var img1Src = document.getElementById('img3').src;            // 获取input, 隐式上传数据到后台            var upload_base = document.getElementById('upload_base');            // 将img的src赋给type为hidden的input,以便将其上传到后台            upload_base.value = img1Src;        });    });
  • 后台解决
router.post("/settings/profile/changeImage", upload.single('image'), async (ctx) => {    // 获取前台上传过来的base64数据    const value = ctx.req.body.upload_base;    // 使用正则表达式截取有用的信息    const base64Data = value.replace(/^data:image\/\w+;base64,/, "");    // 使用Buffer.from()函数解决数据    const dataBuffer = Buffer.from(base64Data, 'base64');    // 获取客户的id    const userId = ctx.session.user.id;    // 定义客户新头像的存储路径及名称    const newUserPicturePath = `public/uploads/${userId}.png`;    // 写文件,保存头像文件    fs.writeFile (newUserPicturePath, dataBuffer, function(err) {        if (err) {            console.log(err);        }else{            console.log("保存成功!");            if(ctx.req.file) {                // 删除base64的头像文件,没有这一部分的话,每一次换头像都会多一个你选取的图片文件                const filename = ctx.req.file.filename;                const savedFilePath = `public/uploads/${filename}`;                fs.unlinkSync(savedFilePath);            }        }    });    // 获取客户id    const id = ctx.session.user.id;    const data=[newUserPicturePath, id];    // 升级客户头像地址    const resetPicturePromise = editUser.resetPicture(data);    await resetPicturePromise; //新的头像路径保存完成,但是要升级session才能使头像立即生效    // 获取客户信息    const getUserInformationPromise = editUser.getUserById(id);    const userArray = await getUserInformationPromise;    const user = userArray[0];    // 升级session    ctx.session.user = user;    // 在客户升级头像完成后,我们要将数据库中该客户发表的所有话题的topic_image_path    // 换成该客户当前头像的路径,即 --> newUserPicturePath    // 根据数据表topic中的每条topic的post_man字段我们可以得到发表该话题的客户,由于客户名唯一    // 其实在这里客户名就是当前客户的username属性,由于session、升级,所以我们也用新的,    // 即ctx.session.user.username. 其实它 === user.username    const userName = ctx.session.user.username;    const data2 = [newUserPicturePath, userName]    const updateTopicImagePathByPostManPromise = editTopic.updateTopicPic(data2);    await updateTopicImagePathByPostManPromise;    // 同上,客户更换头像,该客户留言前的图片也应该换    const data3 = [newUserPicturePath, userName];    const updateMessagePicPromise = editMessage.updateMessagePic(data3);    await updateMessagePicPromise;    ctx.redirect('/userHome');});

七、User —- 留言功能

一个论坛,当然得有留言评论功能
这里同样使用fetch

  • 思路

1、客户点击按钮
2、获取文本域中客户输入的文本text
3、获取button的data-id的值id,用id作为判断帖子的依据,id为帖子的id
4、使用fetch将text、id上传到后台
5、后台根据这些数据来进行相应的解决:将留言内容存储到数据库中,并指定其属于哪个帖子
6、后台返回数据到前台,前台再进行相应解决:将留言展现到页面,并为新的留言增加样式,删除之前留言的特殊样式

  • 实现代码及解析
// 获取留言的数量,即id="messages"的ul中li的个数    const length = document.getElementById("messages").getElementsByTagName("li").length;    $("#btn").click(function(event){        // 获取id , 此id === topic的id        let id = $("#btn").attr("data-id");        // 获取客户输入的留言内容        let userMessage = $("#userMessage").val();        const url = '/showTopics/all/' + id;        fetch(url, {            method: 'POST',            headers: {                'Accept': 'application/json',                'Content-Type': 'application/json',                'X-Requested-With': 'XMLHttpRequest'            },            body: JSON.stringify({                id: id,                message: userMessage,            })        })        .then(function(response) {            return response.json();        })        .then(function(myJson) {            // 假如有留言            if(length !== 0) {                // 设置背景颜色为空                document.getElementsByTagName("li")[6].style.background = "";                // 移除字体样式                document.getElementsByTagName("li")[6].classList.remove("text-danger", "font-weight-bold");            }            // 新定义一个标签li,用来存储新的留言            const newMessageLi = `                <li class="list-group-item text-danger font-weight-bold" style="background:greenyellow">                    <a class="user_avatar pull-left" href="/userHome" style="width:28px;height:28px">                        <img src="../../${myJson[3]}" title="${myJson[2]}" style="width:28px;height:28px">                    </a>                    ${myJson[1]}                </li>            `;            // 将留言加入到页面中            $("#messages").prepend(newMessageLi);        });        // 使留言的数量 ++        document.getElementById("num_msg").innerHTML ++;        // 清空文本域        document.getElementById("userMessage").value = '';    });

八、User —- 简单的搜索功能

  • 思路

1、获取客户在输入框中输入的字符串string
2、获取数据库中所有useful=1的帖子
3、定义一个数组来保存的结果resultArray
4、遍历topic的title,使用indexOf找出title中包含string的帖子topic,将其存入resultArray中
5、而后将结果string与result传输到前台,前台再进行解决

  • 后台
router.post("/allTopic/results", async (ctx) => {    // 需求: 拿到客户在搜索框中输入的字符串,将其与Topic表中所有topic的title进行比照,    // 有相等的就展现出来,没有则提醒客户说:未找到符合条件的内容,搜索的显示页面可以是另外一个页面    // 拿到客户在搜索框中输入的字符串    const userInputString = ctx.request.body.user_input_string;    const listAllTopicFromBBSPromise = editTopic.listAllTopic();    const allTopic = await listAllTopicFromBBSPromise;    // 定义一个结果数组,用来存储找到的结果    let resultArray = [];    // 将符合条件的增加到results里面    for(let i = 0; i < allTopic.length; i++) {        if(allTopic[i].title.indexOf(userInputString) !== -1) {            resultArray.push(allTopic[i]);        }    }    const user = ctx.session.user;    await ctx.render("/topics/show_results", {        user: user,        resultArray: resultArray,        userInputString: userInputString    });});
  • 前台
<% if (resultArray.length === 0) { %>     <li class="list-group-item list-group-item-action cell form-inline" style="font-size: 24px">         <h4> 抱歉,找不到和您查询的“ <span class="text-danger"> <%= userInputString %> </span> ”相符的内容或者信息。</h4>         <h5> 建议: </h5>         <p> ? 请检查输入字词有无错误。 </p>         <p> ? 请尝试其余查询词。 </p>         <p> ? 请改用较常见的字词。 </p>     </li><% } %><% resultArray.forEach(topic => { %>      <li class="list-group-item list-group-item-action cell form-inline" style="font-size: 24px">          <a class="user_avatar pull-left" href="/userHome" style="width:28px;height:28px">              <img src="../<%= topic.topic_image_path %>" title="<%= topic.post_man %>" style="width:28px;height:28px">          </a>          <span class="text-center bg-primary mr-1"> <%= topic.board_name%> </span>          <a class="topic-link text-lg-center" href="/showTopics/all/<%= topic.id %>">话题:<%= topic.title %></a>      </li><% })%>
  • 未找到

image.png

九、扩展

1、 帖子后面显示留言数量
  • 实现方法

  • 在帖子标题后新添加一个span,用来展现留言数msg_num

  • 为了方便一点,在topic表新添加字段msg_num,而后在留言的时候升级此字段

  • 实现

    image.png

2、客户中心 —- 上次发帖内容可点击跳转到该帖子页面
  • 实现方式
    将topic的标题用a标签包裹就可,而后设置好href
3、客户中心 —- 上次留言内容可点击跳转到对应的帖子页面,并将客户的上次留言设置为特殊样式
  • 新添加留言的时候为其设置好样式,并取消上个留言的特殊样式,代码前面贴出来了,源码里也有
  • 在客户中心将留言内容包裹在a标签里,设置好href,使链接到对应的topic页面
  • 其实还可以加个页面定位功能,例如点击留言内容,跳转到该页面,而后使留言位于浏览器的中间,不过我没做
4、帖子的所属子论坛显示
  • 在表topic中新添加字段board_name,存储对应的子论坛名字,在展现页面的时候将其使用span包裹并渲染出来就可,样式自定 =>
<span class="put_top"><%= topic.board_name %></span>

?? 由于置顶与精华并非子论坛,所以要特殊解决 =>

<span class="put_top">精华</span><span class="put_top">置顶</span>
5、帖子的发表人头像
  • 跟所属子论坛差不多,定义一个新的字段,存储头像的路径,而后再渲染出来就可
  • PS: 其实这一类问题并不应该这样解决,而是应该使用mysql的关联表查询,大家可以试试,由于现在这种解决方式有点low
6、帖子展现优先级

这个难道是不难,但是在展现页面的时候会显得有点麻烦,由于要用模版语法

1、优先级 置顶 > 精华 > 普通
2、当某个帖子既是精华贴又被置顶,则显示置顶
PS:具体代码就不贴了,有兴趣的看源码吧

image.png

十、结束语

1、概括

此系列文章共计5篇文章,总用时5个星期

2、感想

原本以为写这个很简单,结果完全不是那么回事,我大概预计了下平均每篇文章用时4.5小时,甚至还不止。
期间我有怀疑过写这个有没有意义,想过能否要放弃写这个,毕竟花的时间太长了,好处说是可以梳理自己的知识体系,只不过并没有什么特别大的效果,懂的仍旧懂,印象的深刻程度也没怎样变。
但作为一个有始有终的人,是坚决不会做“太监”的。经过少量思考、搜索、讯问之后,我觉得文章好处一定是有的,只不过短期内不是很显著而已,就跟运动一样,坚持下去,自然会收获。
第一次写这种文章,感觉自己的文笔不咋地、条理不是很清楚、周密性可能也不是很好,还会遗漏不少东西、写点错别字什么的,敬请各位读者大大见谅吧!
假如诸位有什么疑惑或者者建议什么的欢迎留言,或者者联络我也可以,万分感谢!

附:

1、分期项目地址

ShyGodB/Forum-Code-Synchronize-

2、完整项目地址

ShyGodB/BBS-by-Koa-Mysql

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 使用koa+mysql写一个简易论坛(完)

发表回复