Liby.me V2.0 发布
开发摘要
Developement Liby.me
Liby99
Oct 22, 2016 632 0

好,这个个人主页的完全版终于做完了,接下来说一下其中的开发细节

(咦网址哪里不对?

(坑爹的阿里云封死了我远古时期的账号,神**要我拿着身份证拍照验证。只能回国再搞这事了。

整个网站都是完全用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真是整的心累。

嘛,就这样吧,大部分有趣的技术细节也都说到了,如果还对什么部分感兴趣的话,一定直接发邮件来问我哦~

开发这个网站真的很开心,也非常感谢所有向这个网站提出过建议的民那桑~下次再见~(咦?下次?

Be the first one to comment