好,这个个人主页的完全版终于做完了,接下来说一下其中的开发细节
(咦网址哪里不对?
(坑爹的阿里云封死了我远古时期的账号,神**要我拿着身份证拍照验证。只能回国再搞这事了。
整个网站都是完全用NodeJs开发出来的。之前写了一个老的版本,因为很难做框架,不想要每次都app.get("...", function () {}),所以完全采用了静态页的方式。可是这样的话各种代码量都超级超级大,而且写的一点都不Decent。当时开发各种碰壁,于是后来直接就弃坑了(噗噗
然后我就开始在各种方面研究NodeJs和Express这几个鬼东西。中间也做出来了几个自己的试验品,也包括MangaReader之类的,慢慢整出来了一套自己的NodeJs框架,然后页面的渲染就变得相当简单,而且代码也非常明了了。当然,经常还是会出现Callback Hell的状况,所以我总是在期待ES 2017的Await Async。中间还想去用Babel(简直作死)。不过果然还是算了。还是揪着原本的Express和NodeJs不放吧。
那么现在就来说说一些小细节(?
后台
自己写的框架的话,最主要的部分应该就是Router吧:
var file = req.path.substring(1, req.path.indexOf(".html")); try { //Check if there's a route written var route = require("../route/" + file + ".js"); //Call the router route(req, res, function (data) { //Render the data and the file res.render(file, data, function (err, html) { //Error handling }); }); }
把所有的html的链接都截下来,然后获取相应的Router来处理这个html的内容,而router将一定会给callback function返回这个页面所需的数据,从而直接调用res.render(data)来渲染这个文件。
(catch的部分则是可以直接发送静态的html的了,当然还要避免404的循环重定向。这个bug整了我挺久的)
于是比较简单的Router都会非常简洁地长成这样:
例:project.js
var Project = require("../api/project.js"); module.exports = function (req, res, callback) { Project.getThreeProjects(function (projects) { callback({ "projects": projects }) }); }
于是这就是一整个Router了,因为把获取project信息的方法封装在API里,所以只需要调用api里的方法,再把东西放回到callback就行。
(不行哈哈哈哈我越来越觉得这个Router真是太Decent了)
然后就是Ajax的请求(们),我也写了相当不错的Handler,于是Ajax的请求和撰写就变得非常简单啦!以下是Ajax的模组:
try { var handler = require("../handler/" + req.params[0] + ".js"); if (req.query["action"]) { if (typeof handler[req.query["action"]] === "function") { try { handler[req.query["action"]](req, res); } catch (ex) { console.log(ex); res.error(417, "Expectation Failed"); } } else { res.error(404, "Action " + req.query["action"] + " Not Found"); } } else { res.error(404, "No Action Specified"); } } catch (err) { if (err.code === "MODULE_NOT_FOUND") { console.log(err); res.error(404, "Handler " + req.params[0] + " Not Found"); } else { res.error(500, "Internal Server Error"); throw err; } }
以上的这些代码将会为一个格式的请求:
/ajax/<HANDLER>?action=<ACTION>
自动找到相应的handler然后调用其中的action方法。所以我们不需要一个一个写app.get()!
这些奇妙的res.error就是专门为Ajax请求封装的格式化的办法,这样在前端调用Ajax请求的时候也可以有封装方法,能做到自动处理异常呢,就不需要每次请求都一个个写了。
总之后台的理念就是,框架之外的代码越少越好,于是我写后台的时候一直都是处于速度飞快的状态。自己使用自己的框架真的很愉悦呢。
前端
哈哈哈到前端......其实......突然发现......好像没啥好说的?所有的html都是使用ejs这个渲染引擎来做的渲染(完全是以前开发Asp.net留下来的后遗症)。一般来讲的话,ejs的使用还算是挺不错的,但是这次遇到了一个博客页分页的问题,还有作品页要分月份和分列的问题。在这些问题上,ejs的做法都不怎么decent。不过我倒是有点想展示一下Pagination的代码:
<ul id="pagination"> <% if (page != 1) { %> <li class="page-btn op" id="page-prev"> <a href="article.html?p=<%= page - 1 %>"><i class="fa fa-angle-left"></i>Prev</a> </li> <% } %> <% if (max_page <= 5) { %> <% for (var i = 1; i <= max_page; i++) { %> <li class="page-btn<%= (i == page) ? " active" : "" %>"> <a href="article.html?p=<%= i %>"><%= i %></a> </li> <% } %> <% } else { %> <% if (middle || right) { %> <li class="page-btn"> <a href="article.html?p=1">1</a> </li> ... <% } %> <% for (var i = start; i <= start + 4; i++) { %> <li class="page-btn<%= (i == page) ? " active" : "" %>"> <a href="article.html?p=<%= i %>"><%= i %></a> </li> <% } %> <% if (left || middle) { %> ... <li class="page-btn"> <a href="article.html?p=<%= max_page %>"><%= max_page %></a> </li> <% } %> <% } %> <% if (page != max_page) { %> <li class="page-btn op" id="page-next"> <a href="article.html?p=<%= page + 1 %>">Next <i class="fa fa-angle-right"></i></a> </li> <% } %> </ul>
这样子就能产生,有首页,尾页,并且中间有五个相邻页,还有“上一页”,“下一页”的pagination。其中我觉得比较有趣的是left, middle和right三个变量。本来这个逻辑写得相当混乱,到处都是for和if。但是有了这三个变量——分别指代当前页码是否属于左,中,右部分——之后就只需要一点点多余的代码就可以了。看起来还算是比较舒服的。
嘛,然后就是我觉得这个个人主页最为有创意/技术含量的地方,那便是首页和作品页上的鼠标滑动效果。最开始见到这个效果是在苹果的官网,有个Start Something New的页面。但是很可惜现在已经找不到了。当时还相当认真地读过他混淆的代码,想要找到里面最关键的部分到底是啥,不过实在没有成果。于是我就只能自给自足了(其实是先有想法模仿这个效果然后才想做主页的我会告诉你们吗?)
嗯整个Module已经被封装的比较全,所以我就只取能表现它运动模式的代码出来吧:
bx += (mx - bx) * ANIMATION_SPEED; by += (my - by) * ANIMATION_SPEED; if (Math.pow(mx - bx, 2) + Math.pow(my - by, 2) > 1) { setBoardPosition(bx, by); }
铛铛!其实就这么点(甚至最后一个if都不需要去看它。
用到的是牛顿逼近法!(上几个学期才学的微分方程),这里ANIMATION_SPEED是一个0-1的double值,其实意思是,在下一帧,我将会走应该走的距离的几分之一。比如如果ANIMATION_SPEED是1/2的话,那么我第一帧就会走整个距离的1/2,第二次因为只剩1/2了,再乘以1/2就会变成1/4,第三次则是1/8,以此类推。我最后设置的速度是1/25,这样的速度应该不会很快也不算慢。
所以说如此流畅的动画其实就只用了这么一点微小的技巧( ´ ▽ ` )
再就是这每个页面的responsive真是整的心累。
嘛,就这样吧,大部分有趣的技术细节也都说到了,如果还对什么部分感兴趣的话,一定直接发邮件来问我哦~
开发这个网站真的很开心,也非常感谢所有向这个网站提出过建议的民那桑~下次再见~(咦?下次?