首页 > 代码库 > 集成ejs和angular

集成ejs和angular

我们另一个系统是把angular用在单页面应用里,对angular做了一些定制,集成了seajs,没有用angular自己的模块管理。不过angular单独使用也是可以的,新开发的一个较小的系统,就没有使用前端js的模块管理,而是简单集成了ejs和angular,本文是一个简单的demo

流程

首先是express的一个服务,用于跳转到ejs。该服务类似于struts2里的action类:

function myAccount(req, res, next){

    res.render("binding_list", {layout:"storeadmin_layout", menu:"myAccount"});
}

通过http client发送GET请求到地址/svc/weixin/myAccount,就会调用该服务,该服务在服务端准备数据之后,调用express的render函数,跳转到ejs,下面是ejs的代码。.ejs相当于jsp文件,都是一个服务端模板

<%- Loader().js('/weixin/weixin.js').done(config) %>

<div ng-controller="WeixinController">

    <span ng-if="hasBinding">已绑定</span>
    <span ng-if="!hasBinding">未绑定</span>

</div>

在.ejs里可以写javascript代码,经过ejs引擎渲染之后,生成html页面到客户端,response body是:

<script src=http://www.mamicode.com/"/weixin/weixin.js?v=1407754967801"></script>>
上面这段html片段,里面已经包含了angular标签,但是angular还没有在客户端(浏览器里)执行。然后浏览器解析到<script>标签,又去请求加载weixin.js文件,这个文件里放的才是angular的代码:

function WeixinController($scope){

    $scope.name = "kyfxbl";

    $.get("/svc/weixin/checkBinding", function(res){
        $scope.hasBinding = res.flag;
        $scope.$digest();
    });
}

这时候,浏览器已经加载了angular.js和weixin.js,这2个文件里的代码,都是在浏览器里执行的,和服务端的express和ejs已经没有关系了 。后面就是angular在起作用,对html文件再次编译,得到的就是最终呈现给用户的界面

这个过程分为2个阶段,第一个阶段跑在node里,主要是ejs引擎起作用,把.ejs文件渲染成html文件,发响应给回浏览器。第二个阶段跑在浏览器里,主要是angular起作用,把html里的变量,替换为$scope中的模型。所以这里有2次变量替换的过程,在服务端是把<%= %>替换成render函数传递的模型;在客户端是把{{ }}替换成&scope上挂载的模型

server端传递变量

主要容易混淆的地方在于,如果想在server端把值写到weixin.js里该怎么做

比如说,在.ejs里有这么一个表达式:

{{ name }}

name是在浏览器里由angular编译替换的,所以weixin.js里,就需要有这样的代码:

$scope.name = "kyfxbl";

但是如果name是需要node从数据库中读出来的,那么就有2种做法:

一种是把js嵌入到.ejs中(就不需要单独的weixin.js了):

<script>

    function WeixinController($scope){
        $scope.name = "<%= name %>";
    }
</script>

<div ng-controller="WeixinController">

    {{ name }}

</div>

但是这种方式我并不推荐,主要是有2个问题:

1、把js代码直接嵌在html里,这种做法很不好。因为复杂一点的页面,<script>里的内容会变得很长,很难维护。而且js压缩工具,也不好处理这种情况。最佳实践是把js和html分离开

2、render传过来的name变量,还需要手工地加上"",否则的话就会报错。<script>里到处都需要这么处理,非常容易出错,定位起来也很麻烦

所以最好是采用第二种方式,还是把.ejs和weixin.js分离开,weixin.js里初始化angular controller的时候,再次去服务端请求需要的变量:

function WeixinController($scope){

    $scope.name = "kyfxbl";

    $.get("/svc/weixin/checkBinding", function(res){
        $scope.hasBinding = res.flag;
        $scope.$digest();
    });
}

这样做的坏处是http的请求数会变得比较多(第一种方式可以在接受请求的时候,把需要的变量都准备好写到.ejs里),不过可以通过合并接口等方式,减少http请求的次数。我认为也好过把js代码嵌在html里