整合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) %> 已綁定 未綁定
在.ejs裡可以寫javascript代碼,經過ejs引擎渲染之後,產生html頁面到用戶端,response body是:
<script src="/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> {{ name }}
但是這種方式我並不推薦,主要是有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裡