前言
前段時間做了一個項目,前端開發頁面,然后把代碼給到后端同學,后端同學通過vm再來渲染頁面。后來才發現,這種方式簡直是太low了,因為前端代碼在服務端同學那里,每次前端需要更改的時候都需要去到服務端同學那里修改代碼,維護成本高,賣力不討好==
工作了這么久,深深的感受到了那句名言的魅力,時間就是金錢呀!后來我發現,現在的web開發,誰還用這種低級的方法,大家都已經開始搞前后端分離了
!
前后端分離的目的和作用
要弄清前后端分離的目的和作用,首先要知道什么是前后端分離。
現在的web前端越來越偏向於獨立的技術種類,在不久的將來,服務端的活都會被我們給承包了。我曾經在某個網站讀到這樣一句話,假如有一個大型網站,例如淘寶網,它肯定不止是一個web項目,而是多個web項目的集合,那么如果前端不作整合、封裝,那么不同的項目開發必然會有大量的重復勞動。從這句話和我在前言中舉的例子中可以看出,前端開發單獨封裝組件,單獨開發項目,單獨維護,前端代碼不和服務端邏輯揉在一起,這就是我理解的前后端分離。唯一需要和服務端交互的,就是通過ajax去請求他們提供的接口。
所以,從另一個角度看,我們在開發的時候,只要和服務端約定好接口格式,從項目開工到結束,我們都不需要和服務端開發打交道,這無疑提高了項目質量和開發效率。前后端分離的終極目標應該是前端和服務端是完全獨立的項目,一個項目開始之后,前端開發前端的,服務端開發服務端的,並且最后還需要獨立部署,這樣才真正實現了前后端解耦分離,前后端的溝通主要集中在數據接口的格式上。
前端項目構建
現在要做到前端項目獨立,這時候為了項目便於管理維護,我們就需要項目化,工程化,開發規范,自動化壓縮混淆,自動化發布,前端優化等等。
現在前端框架這么豐富,一個項目要引入哪些框架,就因人而異了,工作以來一直在學習angular,所以最近自己嘗試着搭了一套基於grunt+requireJs+angularJs的應用。
-
grunt: 操作項目文件:比如文件轉換、壓縮、打包部署等等。
-
requireJs: js庫加載管理,支持按需加載,模塊化引入。
-
angularJs: js前端MVC框架,支持依賴注入、雙向綁定等主要特性。
這幾個庫是現在中大型前端項目比較適合的搭配,很有必要去學習並掌握他們。
創建項目目錄
mkdir myProject
cd myProject
創建項目文件夾,然后進入文件夾,一下操作均在此文件夾下執行。
創建package.json
首先我們需要為npm提供一個package.json,告訴它我們的項目信息,特別是項目中將會使用的插件。
可以用命令生成,后續也能夠手動修改。
npm init
他會問我們一些問題,一路使用默認值,創建完畢。
安裝grunt
npm install grunt --save-dev
使用npm安裝grunt插件,它將被安裝到根目錄的node_modules
文件夾下,所有npm插件都會放到這里。
--save-dev
: 意思是安裝插件的同時,也把它添加到項目信息文件package.json
中的devDependencies
字段里,意思是這個項目依賴於這些插件。下次使用npm install
的時候就會自動安裝這些插件。
為grunt創建配置文件Gruntfile.js
Gruntfile.js文件用於定義任務、任務組。它可以用來執行文件的類型轉換、壓縮、合並等等操作,為開發大大提高了效率。
-
安裝grunt-init
npm install grunt-init -g //全局安裝grunt-init
-
下載grunt模板
git clone https://github.com/gruntjs/grunt-init-gruntfile.git ~/.grunt-init/gruntfile
-
生成Gruntfile
grunt-init gruntfile
在項目根目錄下生成Gruntfile.js文件,跟package.json文件一下,按需回答一些文件,就創建好了,后續能手動修改(其實大部分都是自己手寫的)。
安裝bower
bower是用來管理js庫的一個工具,比如下載jquery、angularjs等庫。並且下載的時候還能指定庫的版本。
同樣適用npm進行安裝。
npm install bower -g
為bower生成配置文件bower.json
整個項目的信息文件是package.json
,執行任務插件grunt的信息文件是Gruntfile.js
,那么bower當然也有自己的信息文件了,那就是bower.json
。
bower init
不過我覺得bower.json基本沒有什么作用,它最大的作用就是用來下載我們需要的各種技術庫。
比如使用bower下載angularjs:
bower install angularjs
這行命令將會把angular下載下來,放在根目錄下的bower_components
文件夾下,不過它默認下載的是angular的最新版,有時候,我們可能不需要最新版。假如,我想下載angularjs 1.2.2版本該怎么辦呢?
bower install angularjs#1.2.2
另外,bower只負責下載文件到bower_components
目錄下,但是我們項目中可能並不想把庫放在這里,所以我們可以選擇使用grunt的插件grunt-bower-task
,在Gruntfile.js中定義一個任務來移動文件到想要的目錄下。
關於Requirejs
官網上是這樣說的:
RequireJS的目標是鼓勵代碼的模塊化。
它使用了不同於傳統的腳本加載步驟。可以用它來加速、優化代碼,但其主要目的還是為了代碼的模塊化,按需加載。
使用Requirejs
<script data-main="scripts/main" src="scripts/require.js"></script>
一般在首頁加載requiejs文件,然后屬性data-main
指定的文件就是接下來要加載的文件,然后我們再看main.js
文件:
require.config({
baseUrl: 'script/lib',
paths: {
app: 'app',
jquery: '/jquery/jquery-min',
angular: '/angularjs/angular-min'
},
shim: {
'angular': {
exports: 'angular'
}
}
});
require([
'app'
], function(app) (
app.hello();
))
-
我們在
paths
中聲明了3個模塊,app、jquery和angular,后面的路徑是模塊對應的文件路徑。 -
shim
中用來處理一些沒有遵守requirejs規范的js庫,比如angularjs庫,所以要手動配置一個叫angular
的模塊。 -
最后用require來導入我們自己的模塊,可在后面的callback中拿到對應模塊的實例,並對它進行一些操作,比如我們調用了
app.hello()
方法。
AngularJs實例
上面的步驟只是簡單說了下大體步驟,紙上談兵之后,就可以開始實際操作了。
目錄結構
項目文件夾結構如下圖(當然目錄結構因人而異):
-
node_modules
: 用來存放項目依賴的grunt插件。 -
bower_components
: 用來存放bower下載的庫。 -
build
: 用來存放經過build處理之后的js文件。 -
app
: 是真正的開發需要的文件。-
data
: 用來存放mock數據用的json文件。 -
images
: 用來存放靜態圖片。 -
scripts
: 用來存放所有js文件。-
controller
: 用來存放控制器文件。 -
directive
: 定義的指令文件。 -
filter
: 定義的過濾器文件。 -
route
: 路由文件。 -
service
: 服務文件。 -
vendor
: 公共庫文件,比如angular,jquery,bootstrap等等。
-
-
styles
目錄用來存放樣式文件。 -
views
目錄用來存放頁面
html文件。 -
partials
目錄用來存放頁面片段
的html文件。
-
目錄創建好了,現在來寫一些代碼,讓項目能夠運行起來。
views/index.html
<html>
<head>
<meta charset="UTF-8">
<title>grunt+requirejs+angular項目構建</title>
<script src="../scripts/vendor/requirejs/require.js" data-main="../scripts/config"></script> <!-- 先引入requirejs, 然后引入config.js -->
</head>
<body>
<div ng-controller="testController">
{{app}}
</div>
</body>
</html>
上述index中,先引入了require.js,然后加載data-main對應的config.js文件。
scripts/config.js
var vendorPath = 'vendor/';
require.config({ //配置模塊
baseUrl: '../scripts/',
paths: {
'app': 'app',
'angular': vendorPath + 'angular/angular',
'jquery': vendorPath + 'jquery/jquery'
},
shim: { //處理沒有遵守requirejs規范的js庫
'angular': {
exports: 'angular'
}
}
});
require(['./bootstrap'], function(bootstrap) {
// ...
});
然后通過require引入了bootstrap.js文件。
scripts/bootstrap.js
define([
'angular',
'app',
'jquery',
'./controller/_base'
], function(angular) {
// 手動將angular模塊綁定到document對象
angular.element(document).ready(function() {
angular.bootstrap(document, ['myProject']);
});
});
注意:function的內容是requirejs引入所有文件之后的回調函數。
bootstrap是angular對象的一個方法,用於手動啟動。上述代碼除了引入了angular等js庫外,還引入了app.js文件。
scripts/app.js
define([
'angular',
'./controller/controllers'
], function(angular) {
//定義將要綁定到document上的模塊名稱
return angular.module('myProject', ['projectController']);
});
定義模塊名myProject
的時候,同時指定它依賴於另一個模塊projectController
。
同時在./controller/controllers.js
中定義這個模塊:
define(['angular'], function(angular) {
return angular.module('projectController', []);
});
這里是給所有的控制器定義了一個單獨的模塊,然后讓主要模塊依賴於這個模塊,這樣做的目的是方便管理維護,我們還可以給所有的服務、路由、過濾器都添加一個單獨的模塊,然后在app.js中添加注入即可。
controller/testController.js
如果想要讓視圖文件views/index.html
能夠看到效果,我們就要開始編寫控制器文件了,
define([
'./controllers'
], function(mod) {
var controllerFn = function($scope, $location) {
$scope.app = 'hello, world';
};
controllerFn.$inject = ['$scope', '$location'];
mod.controller('testController', controllerFn);
});
引入控制器的單獨模塊文件'./controllers',然后在模塊上新建一個名為testController
的控制器,並在$scope上綁定了一個值為‘hello, world’的變量app
。
查看效果
使用python -m SimpleHTTPServer
啟動一個簡單的web服務器,默認監聽8000端口。在瀏覽器輸入正確地址就能看到效果了。
hello, world
結語
現在,我們需要做的就是,和服務端約定好接口格式,自己根據格式mock需要的數據,然后,我們可以隨心所欲的開發我們的項目了,不用再和人打交道了。開發完畢之后,再通過grunt壓縮、合並、打包文件等操作,暴露給外部的只需一個js文件,另外還可以通過git等版本管理工具來迭代項目。有了這種開發方式,你再也不用擔心服務端開發隨時來煩你,自己也有更多時間來鑽研前端本身的技術了,哈哈。