日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

angular1.x + ES6开发风格记录

發布時間:2023/10/11 综合教程 87 老码农
生活随笔 收集整理的這篇文章主要介紹了 angular1.x + ES6开发风格记录 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

angular1.x和ES6開發風格

一、Module

ES6有自己的模塊機制,所以我們要通過使用ES6的模塊機制來淡化ng的框架,使得各業務邏輯層的看不出框架的痕跡,具體的做法是:
  • 把各功能模塊的具體實現代碼獨立出來。
  • module機制作為一個殼子,對功能模塊進行封裝。
  • 每個功能分組,使用一個總的殼子來包裝,減少上級模塊的引用成本。
  • 每個殼子文件把module的name屬性export出去。
舉例來說,我們有一個moduleA,里面有serviceA,serviceB,那么,就有這樣一些文件:
serviceA的實現,service/a.js
export default class ServiceA {}

serviceB的實現,service/b.js

export default class ServiceB {}

moduleA的殼子定義,moduleA.js

import ServiceA from './services/a';
import ServiceB from './services/b';
export default angular.module('moduleA'[])
.service('ServiceA', ServiceA)
.service('ServiceB', ServiceB)
.name;

存在一個moduleB要使用moduleA:

import moduleA from './moduleA';
export default angular.module('moduleB', [moduleA]).name;

二、Controller

ng1.2開始提供了controllerAs的語法,自此Controller終于能變成一個純凈的ViewModel(視圖模型)了,而不像之前一樣混入過多的$scope痕跡。
例如:
HTML
<div ng-controller="AppCtrl as app">
<div ng-bing="app.name"></div>
<button ng-click="app.getName">get app name</button>
</div>

controller AppCtrl.js

export default class AppCtrl {
constructor() {
this.name = 'angualr$es6';
}
getName() {
return this.name;
}
}

module

import AppCtrl from './AppCtrl';
export default angular.module('app', [])
.controller('AppCtrl', AppCtrl)
.name;

三、Component(Directive)

指令主要包含了一個ddo(Directive Definition Object),所以本質上這是一個對象,我們可以給它構建一個類。
export default class DirectiveA {}

DDO上面的東西大致可以分為兩類,屬性和方法,所以就在構造函數里這樣定義:

constructor() {
this.template = template;
this.restrict = 'E';
}

接下來就是controller和link,compile等函數了,比如controller,可以實現一個普通的controller類,然后賦值到controller屬性上來:

this.controller = ControllerA;

寫directive的時候,盡量使用controllerAs這樣的語法,這樣controller可以清晰一些,不必注入$scope,而且還可以使用bingToController屬性,把在指令attr上定義的值或方法傳遞到controller實例上來。接下來我們使用三種方法來定義指令


1、定義一個類(ddo),然后在定義指令的工廠函數中返回這個類的實例。

我們要做一個日期控件,合起來就是這樣
import template from '../template/calendar.html';
import CalendarCtrl from '../controllers/calendar'; import '../css/calendar.css'; export default class CalendarDirective{
constructor() {
this.template = template;
this.restrict = 'E'; this.controller = CalendarCtrl;
this.controllerAs = 'calendarCtrl';
this.bingToController = true; this.scope = {
minDate: '=',
maxDate: '=',
selecteDate: '=',
dateClick: '&'
};
} link(scope) {
//這個地方引入了scope,應盡量避免這種做法,
//但是搬到controller寫成setter,又會在constructor之前執行
scope.$watch('calendarCtrl.selecteDate', newDate => {
if(newDate) {
scope.calendarCtrl.calendar.year = newDate.getFullYear();
scope.calendarCtrl.calendar.month = newDate.getMonth();
scope.calendarCtrl.calendar.date = newDate.getDate(); }
});
}
}

然后在module定義的地方:

import CalendarDirective from './directives/calendar';

export default angular.module('components.form.calendar', [])
.directive('snCalendar', () => new CalendarDirective())
.name;

2、直接定義一個ddo對象,然后傳給指令

同樣以datepicker組件為例,先定義一個controller
// DatePickerCtrl.js
export default class DatePickerCtrl {
$onInit() {
this.date = `${this.year}-${this.month}`;
} getMonth() {
...
} getYear() {
...
}
}

注意,這里先寫了controller而不是link/compile方法,原因在于一個數據驅動的組件體系下,我們應該盡量減少對DOM操作,因此理想狀態下,組件是不需要link或compile方法的,而且controller在語義上更貼合mvvm架構。

在模塊定義的地方我們可以這樣使用:
import template from './date-picker-tpl.html';
import controller from './DatePickerCtrl'; const ddo = {
restrict: 'E',
template, //es6對象簡寫
controller,
controllerAs: '$ctrl',
bingToController: {
year: '=',
month: '='
} }; export default angular.module('components.datePicker', [])
.directive('dataPicker', ddo)
.name;

在整個系統設計中只有index.js(定義模塊的地方)是框架可識別的,其它地方的業務邏輯都不應該出現框架的影子,這樣方便移植。


3、component

1.5之后提供了一個新的語法moduleInstance.component,它是moduleInstance.directive的高級封裝版,提供了更簡潔的語法,同時也是未來組件應用的趨勢。例如
bingToController -> bindings的變化,而且默認controllerAs = ‘$ctrl’,但是它只能定義自定義標簽,不能定義增強屬性,而且component定義的組件都是isolated scope。

1.5版本還給組件定義了相對完整的生命周期鉤子,而且提供了單向數據流的方式,以上例子可以寫成下面這樣子:

//DirectiveController.js
export class DirectiveController {
$onInit() { } $onChanges(changesObj) { } $onDestroy() { } $postLink() { }
} //index.js
import template from './date-picker-tpl.html';
import controller from './DatePickerCtrl'; const ddo = {
template,
controller,
bindings: {
year: '<',
month: '<'
}
}; export default angular.module('components.datepicker', [])
.component('datePicker', ddo)
.name;

4、服務

先來說一下在ES6中通過factory和service來定義服務的方式。
serviceA的實現,service/a.js
export default class ServiceA {}

serviceA的模塊包裝器moduleA的實現

import ServiceA from './service/a';

export angular.module('moduleA', [])
.service('ServiceA', ServiceA)
.name;

factoryA的實現,factory/a.js

import EntityA from './model/a';

export default function FactoryA {
return new EntityA();
}

factoryA的模塊包裝器moduleA的實現

import FactoryA from './factory/a';

export angular.module('modeuleA', [])
.factory('FactoryA', FactoryA)
.name;

對于依賴注入我們可以通過以下方式來實現:

controller/a.js
export default class ControllerA {
constructor(ServiceA) {
this.serviceA = ServiceA;
}
} ControllerA.$inject = ['ServiceA'];

import ControllerA from './controllers/a';

export angular.module('moduleA', [])
.controller('ControllerA', ControllerA);

對于constant和value,可以直接使用一個常量來代替。

Contant.js
export const VERSION = '1.0.0';

5、filter

angular中filter做的事情有兩類:過濾和格式化,歸結起來就是一種數據的變換工作,過度使用filter會讓你的額代碼在不自知的情況下走向混亂。所以我們可以自己去寫一系列的transformer來做數據處理。
import { dateFormatter } './transformers';
export default class Controller {
constructor() {
this.data = [1,2,3,4]; this.currency = this.data
.filter(v => v < 4)
.map(v => '$' + v); this.date = Date.now();
this.today = dateFormatter(this.date);
}
}

6、消除$scope,淡化框架概念

1、controller的注入

1.2之后有了controllerAS的語法,我們可以這么寫。
<div ng-controller="TestCtrl as testCtrl">
<input ng-model="testCtrl.aaa">
</div>

xxx.controller("TestCtrl", [function() {
this.aaa = 1;
}]);

實際上框架會做一些事情:

$scope.testCtrl = new TestCtrl();

對于這一塊,把那個function換成ES6的類就可以了。

2、依賴屬性的計算

在$scope上,除了有$watch,$watchGroup,$watchCollection,還有$eval(作用域上的表達式求值)這類東西,我們必須想到對它們的替代辦法。

一個$watch的典型例子
$scope.$watch("a", function(val) {
$scope.b = val + 1;
});

我們可以直接使用ES5的setter和getter來定義就可以了。

class A {
set a(val) { //a改變b就跟著改變
this.b = val + 1;
}
}

如果有多個變量要觀察,例如

$scope.$watchGroup(["firstName", "lastName"], function(val) {
$scope.fullName = val.join(",");
});

我們可以這樣寫

class Controller {

    get fullName() {
return `${this.firstName} ${this.lastName}`;
}
}

html

<input type="text" ng-model="$ctrl.firstName">
<input type="text" ng-model="$ctrl.lastName"> <span ng-bind="$ctrl.fullName"></span>

3、事件冒泡和廣播

在$scope上,另外一套常用的東西是$emit,$broadcast,$on,這些API其實是有爭議的,因為如果說做組件的事件傳遞,應當以組件為單位進行通信,而不是在另外一套體系中。所以我們也可以不用它,比較直接的東西通過directive的attr來傳遞,更普遍的東西用全局的類似Flux的派發機制去通信。

根作用域的問題也是一樣,盡量不要去使用它,對于一個應用中全局存在的東西,我們有各種策略去處理,不必糾結于$rootScope。

4、指令中$scope

參見上文關于指令的章節。

7、總結

對于整個系統而言,除了angular.module,angular.controller,angular.component,angular.directive,angular.config,angular.run以外,都應該實現成與框架無關的,我們的業務模型和數據模型應該可以脫離框架而運作,當做完這層之后,上層遷移到各種框架就只剩下體力活了。

一個可伸縮的系統構架,確保下層業務模型/數據模型的純凈都是有必要的,這樣才能提供上層隨意變化的可能,任何模式下的應用開發,都應具備這樣一個能力。

參考鏈接:






總結

以上是生活随笔為你收集整理的angular1.x + ES6开发风格记录的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。