使用Angularjs和Vue.js對比
首先需要說明的是:現在預設angularjs指angular1.0+版本,angular預設指2.0以上版本。本文的名詞也預設指定angular的1.0+版本。
先讓我們看一下 這兩個架構的設計上的一些不同。
Angularjs
1,MVC架構
2,子產品化(Module)控制器(Contoller)依賴注入:這種子產品話的注入,其實在代碼層面上顯得并不夠整潔,比如我任何一個控制器controller 裡面其實要注入很多的服務。
3,雙向資料綁定:界面的操作能實時反映到資料,資料的變更能實時展現到界面。
4,指令(ng-click ng-bind ng-model ng-href ng-src ng-if/ng-show...),可以自定義指令Directive,比jQuery插件要靈活,但是需要深入了解Directive的一些特性,簡單的封裝容易,複雜一點官方沒有提供詳細的介紹文檔,我們可以通過閱讀源代碼來找到某些我們需要的東西,如:在directive使用 $parse;
5,服務Service($compile $filter $interval $timeout $http...)
6,路由(ng-Route原生路由),ui-router(路由元件)
7,Ajax封裝($http)
8,使用于一些增删改查的管理系統開發。
缺點:
1:其中雙向資料綁定的實作使用了$scope變量的髒值檢測,使用$scope.$watch(視圖到模型),$scope.$apply(模型到視圖)檢測,内部調用的都是digest,當然也可以直接調用$scope.$digest進行髒檢查。值得注意的是當資料變化十分頻繁時,髒檢測對浏覽器性能的消耗将會很大,官方注明的最大檢測髒值為2000個資料。
2:ngView隻能有一個,不能嵌套多個視圖,雖然有 angular-router解決,但是貌似ui-router 對于URL的控制不是很靈活,必須是嵌套式的。
3:ng提倡在控制器裡面不要有操作DOM的代碼,對于一些jQuery 插件的使用,如果想不破壞代碼的整潔性,需要寫一些directive去封裝插件。但其實我們在tms裡,控制器對dom的操作還是有不少的,其實按理說 這些操作應該被封裝為指令去進行。
4:Angular 太笨重了,沒有讓使用者選擇一個輕量級的版本,當然1.2.X後,Angular也在做一些更改,比如把route,animate等子產品獨立出去,讓使用者自己去選擇。像animate 這個是一個動畫的插件,我們在tms裡用的還是比較少的。
Vue
vue.js官網:是一套建構使用者界面的 漸進式架構。與其他重量級架構不同的是,Vue 采用自底向上增量開發的設計。Vue 的核心庫隻關注視圖層,并且非常容易學習,非常容易與其它庫或已有項目整合。另一方面,Vue 完全有能力驅動采用單檔案元件和 Vue 生态系統支援的庫開發的複雜單頁應用。
Vue.js 的目标是通過盡可能簡單的 API 實作響應的資料綁定群組合的視圖元件。
(1)子產品化,目前最熱的方式是在項目中直接使用ES6的子產品化,結合Webpack進行項目打包
(2)元件化,創造單個component字尾為.vue的檔案,包含template(html代碼),script(es6代碼),style(css樣式)
(3)雙向資料綁定:界面的操作能實時反映到資料,資料的變更能實時展現到界面。
(4)指令(v-html v-bind v-model v-if/v-show...)
(5)路由(vue-router)
(6)vuex 資料共享
(7)Ajax插件(vue-resource,axios)
vue非常小巧,壓縮後min源碼為72.9kb,gzip壓縮後隻有25.11kb,想比Angular為144kb,可以自駕搭配使用需要的庫插件,類似路由插件(Vue-router),Ajax插件(vue-resource,axios)等
子產品引入的對比:
//比如:angularjs 舉一個service服務的栗子
(function() {
ydCreditApp.factory('myCarService', function($resource, configuration, $http) { //其實能夠在這裡看到,$resource 等的依賴注入了。
var myCarList=$resource(configuration.apiBaseUrl+'/api/tms/car/listCars',{
},{
get:{
method:'GET'}
});var carDetail=$resource(configuration.apiBaseUrl+'/api/tms/car/getCar',{
},{
get:{
method:'GET'}
});return{
myCarList:myCarList,
carDetail:carDetail
})
})()//在這個栗子中,我們啟用了一個名為myCarService的服務。然後在需要的地方,比如myCarCtr.js檔案裡,即控制器裡,調用這個myCarService子產品時:
(function() {
ydCreditApp.controller('myCarController', function($scope,myCarService) {
myCarService.myCarList.get({ params },function(data) {
console.log(data)//背景傳回的資料
}
}
});//vue 比如我想把vue裡的一個元件 或者說某個單獨的js檔案裡的一些資訊給輸出,想在别的地方調用 。舉一個api檔案栗子 檔案位置是:api/index.js
exportdefault{//報帳主體
getCompany(params) {return fetchGet('/api/oa/reimburse/getAllCompanyName', params)
},//使用者登入
Login(params) {return fetchPost('/api/oa/login', params)
},
...
}//在想引入的檔案裡這樣寫
import API from'api檔案的路徑'
//這樣在欲使用這個api檔案裡 就可以使用 API.getCompany() API.Login() 等方法
當然 至于 export與import的寫法并不止這一個,可以在需要的時候,看看其他檔案 比如 mian.js檔案 ,或者是router下的indexjs檔案,項目裡很多檔案也都會有這種寫法 能夠看懂 并且将想要的子產品引入即可。
另外:對于前端子產品化的解釋 是這樣的:
前端子產品化其實就是将一個完整的單一的功能整合起來形成單獨的一個功能元件,當需要用的的時候隻需要加載這個元件,然後便可以通過該元件唯一的名稱去使用其中的内容。 像我們的angularjs裡的myCarService myCarCtr 其實都是一個子產品。vue裡的那個Api/index.js 也是一個子產品。其實關于前端子產品化 還有幾個子產品化架構的 比如:commomJs AMD CMD ES6規範。像剛才介紹的angularjs的那種 包含 依賴 回調 特征的 采用的是異步子產品定義 (AMD) 像我們的vue 采用的就是現在最新的ES6子產品化。
Vue與 Angular 雙向資料綁定原理
angular.js :髒值檢查
angular.js 是通過髒值檢測的方式比對資料是否有變更,來決定是否更新視圖,我們知道,更新頁面最簡單的方法莫過于設定一個定時器,規定多久時間之後去進行更新頁面,angularjs作為一個google開發的架構,肯定也不會這樣做,angular實作雙向綁定,是在一些特定的事件觸發下進行的,比如
DOM事件,譬如使用者輸入文本,點選按鈕等。( ng-click )
XHR響應事件 ( $http )
浏覽器Location變更事件 ( $location )
Timer事件( $timeout , $interval )
執行 $digest() 或 $apply()
vue :資料劫持
vue.js 則是采用資料劫持結合釋出者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個屬性的setter,getter,在資料變動時釋出消息給訂閱者,觸發相應的監聽回調。
寫法上的一些比較
首先當然是Hello World了
1:資料的綁定
在資料的綁定層面 都可以使用 {{ }} 這個特殊的字元來代表某個要被綁定的資料 這個像jsp裡的 ${ messgae }
vue
{{ message }}
newVue({
el:'#app',
data: {
message:'Hello Vue.js!'}
})
Angularjs
{{message}}
var app = angular.module('myApp', []); // 在我們的tms裡 這個app 就是 我們的 ydapp
app.controller('myCtrl', function($scope) {
$scope.message= "Hello world";
});
相比較來看,vue采用了json的資料格式進行dom和data的編寫,編寫風格更加靠進js的資料編碼格式,通俗易懂。
2:資料的雙向綁定
二者在實作的原理上是有差距的,剛才也已經介紹
vue的雙向資料綁定
{{ message }}
newVue({
el:'#app',
data: {
message:'Hello Vue.js!'}
})
Angularjs的雙向資料綁定
{{message}}
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.message= "Hello world!";
});
在雙向綁定這一個層面上,其實也是差不多的,隻是,angularjs需要引入一個$scope 作用域,所有的資料都綁定在$scope這一個特殊的符号上。
3:事件綁定方面
我們知道 在angular裡,官方提供的指令的形式都是形如 ng-事件的形式,但vue裡,支援一些簡寫的方式
angularjs
vue:
簡寫方式:
不過在vue裡,我們需要知道一個vue的周期函數 ,比如這個方法greet要被寫在一個名為methods的執行個體屬性。就像上面的data屬性寫法一樣。
Greet
//example2 就是一個執行個體
var example2 = newVue({
el:'#example-2',
data: {
name:'Vue.js'},//在 `methods` 對象中定義方法
methods: {
greet:function(event) {//`this` 在方法裡指向目前 Vue 執行個體
alert('Hello ' + this.name + '!')//`event` 是原生 DOM 事件
if(event) {
alert(event.target.tagName)
}
}
}
})//也可以用 JavaScript 直接調用方法
example2.greet() //=> 'Hello Vue.js!
當然 vue裡面還有其他很多的簡寫方式,但是基本上也能像angularjs裡面的一樣 , 将 ng- 改為 v- 也就行了。
自定義指令:
angularjs
angular.module('app', []).directive('myDirective', function() {return{
restrict:String,
priority:Number,
terminal:Boolean,
template:String or Template Function,
templateUrl:String or Template Function,
replace:Boolean or String,
transclude:Boolean,
scope:Boolean or Object,
controller:String orfunction(scope, element, attrs, transclude, otherInjectables) { ... },
controllerAs:String,
require:String,
link:function(scope, iElement, iAttrs) {//進行一些時間的綁定渲染等
},
compile:function(tElement, tAttrs, transclude) {return{
pre:function(scope, iElement, iAttrs, controller) { ... },
post:function(scope, iElement, iAttrs, controller) { ... }
}return functionpostLink(...) { ... }
}
};
vuejs
//注冊一個全局自定義指令 `v-focus`
Vue.directive('focus', {//當被綁定的元素插入到 DOM 中時……
inserted: function(el) {//事件
}
})
4:渲染清單的寫法
vue.渲染清單
- {{ name.first }}
newVue({
el:'#app',
data: {
names: [
{ first:'summer', last: '7310'},
{ first:'David', last:'666'},
{ first:'Json', last:'888'}
]
}
})
Angularjs渲染清單
{{name.first}}
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.names=[
{ first:'summer', last: '7310'},
{ first:'David', last:'666'},
{ first:'Json', last:'888'}
]
});
看的出來 其實也是沒有多大的差別的
5:循環寫法
vue的循環
- {{item.title}}
angularjs循環
{{news.title}}
vue和Angular處理使用者輸入
{{ message }}
Reverse Message
newVue({
el:'#app',
data: {
message:'Hello Vue.js!'},
methods: {
reverseMessage:function() {this.message = this.message.split('').reverse().join('')
}
}
})
{{ message }}
Reverse Message
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.message= "Hello world!";
$scope.reverseMessage= function() {this.message = this.message.split('').reverse().join('')
}
});
以上也基本上是一些寫法上的比較。
6:路由
angularjs
angularjs自帶的路由是ngRouter 但是這個路由不能完成多視圖 與 嵌套視圖 。原因是在于,ngRouter的每個視圖 不能有唯一的标志,當視圖發生變化時,所有的視圖都會變為一樣的視圖。
後來有了ui.router 幫助來完成這些功能。
多視圖:頁面可以顯示多個動态變化的不同區塊。
$stateProvider
.state('home', {
url:'/',
views: {'': {
templateUrl:'views/home'},'main': {
template:'views/main'}
}
嵌套視圖:在main視圖裡,繼續添加其他的視圖,該視圖是一個獨立的區域。
我是父視圖
$stateProvider
.state('main', {
abstract:true,
url:'/main',
templateUrl:'views/main.html'})
.state('main.home', {
url:'/home',
templateUrl:'views/home.html'});
傳參:
.state('main.myWork', {
url:'/myWork/:page/:mobile/:name/:sendCity/:arriveCity',
params: { page:null, mobile: null,name:null,arriveCity:null,sendCity:null},
templateUrl:'views/myWork/myWorkList.html',
controller:'myWorkController',
ncyBreadcrumb: {
label:'審批待辦',
parent:'main'},
data: {
requiredLogin:true}
})
在ui.router裡面,通過 parent.child 确定父子視圖的關系。
vue
vue所提倡的官方路由是:vue-route,也可以自己選擇自己的路由。
首先來看這個圖檔,這個圖檔 包括了 三個同級的視圖。在内容部分 也有三個視圖元件被引入。可以說 是展現出了vue的視圖的嵌套與多視圖的特性。
多視圖:
App.vue
import Vue from 'vue'import Router from'vue-router'import HelloWorld from'@/components/HelloWorld'const Data= () => import('../components/Data.vue')
const Bar= { template: '
子路由 '};
const car= { template: '
孫子路由 '};
const d= { template: '
我是頭部 '};
const f= { template: '
我是底部 '};
Vue.use(Router)
exportdefault newRouter({
routes: [
{
path:'/',
name:'首頁',
components: {default: HelloWorld,
a:d,
b:f
}
}
,{
path:'/content',
name:'資料',
component:Data,
children:[{
path:'h',
component:Bar
}]
}
]
})
router/index.js
我是内容
我是内容引入的元件部分
name:'HelloWorld',
data () {return{
msg:'Welcome to Your Vue.js App'}
},
components:{
headTop,
contentView,
footerView
}
}
font-weight: normal;
}
ul {
list-style-type: none;
padding:0;
}
li {
display: inline-block;
margin:010px;
}
a {
color: #42b983;
}
内容部分的vue檔案
路由的嵌套
一般來說
就拿上面的代碼來說 ,其中的name屬性是路由的名稱,path:‘h’ 指定的是路由位址 /content/h component 就是你注冊引入的元件子產品
7:與伺服器的通信
angularjs
angularjs提供了對ajax請求的封裝 $http 服務 當然 這個params可以傳遞的參數有很多,可以根據需要去定義一些傳值。
比如:
var app = angular.module('myApp', []);
app.controller('siteCtrl', function($scope, $http) {
$http.get("http://www.runoob.com/try/angularjs/data/sites.php",{params})
.then(function (response) {$scope.names =response.data.sites;});
});
我們在tms裡,大多數使用的是$resource服務,這個是引入的一個子產品
我們在現在的tms實際的打包時,也經常會由于這個包拉不下來 導緻打包失敗,這個我們也已經有了優化的方案。這裡也不再細說。
下面時$resource在tms系統裡使用的一個栗子
var myCarList=$resource(configuration.apiBaseUrl+'/api/tms/car/listCars',{
params
},{
get:{
method:'GET'}
});
vue
vue跟服務端的通信 有 vue-resource插件,但是在vue2.0之後 就不再維護這個插件,官方也推薦使用axios。一款基于promise(‘承諾于未來發生’的一個對象)的http請求用戶端,可同時在浏覽器和nodejs中使用。
同樣 我們也需要引入這個插件子產品。
//安裝 axios
$ npm install axios//在要使用的檔案中引入axios
import axios from 'axios'
看一下axios的寫法把 一個基于promise的新寫法:
axios.get('/user', {//params也可以不要的
params: {
ID:12345}
})
.then(function(response) {
console.log(response);
})
.catch(function(error) {
console.log(error);
});
當然 對應的還有post請求 都是類似的寫法。
vuex 是vue的一個狀态管理工具
為什麼vue 需要一個這樣的工具
這個工具怎麼使用
待續...
父子元件之間的通信
vue
angularjs