angular1.x + ES6开发风格记录
angular1.x和ES6开发风格
一、Module
- 把各功能模块的具体实现代码独立出来。
- module机制作为一个壳子,对功能模块进行封装。
- 每个功能分组,使用一个总的壳子来包装,减少上级模块的引用成本。
- 每个壳子文件把module的name属性export出去。
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
<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)
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对象,然后传给指令
// 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版本还给组件定义了相对完整的生命周期钩子,而且提供了单向数据流的方式,以上例子可以写成下面这样子:
//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、服务
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;
对于依赖注入我们可以通过以下方式来实现:
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,可以直接使用一个常量来代替。
export const VERSION = '1.0.0';
5、filter
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的注入
<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("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、总结
参考链接:
angular1.x + ES6开发风格记录的更多相关文章
- ES6深入学习记录(三)编程风格
今天学习阮一峰ES6编程风格,其中探讨了如何将ES6的新语法,运用到编码实践之中,与传统的JavaScript语法结合在一起,写出合理的.易于阅读和维护的代码. 1.块级作用域 (1)let 取代 v ...
- [webpack] 配置react+es6开发环境
写在前面 每次开新项目都要重新安装需要的包,简单记录一下. 以下仅包含最简单的功能: 编译react 编译es6 打包src中入口文件index.js至dist webpack配置react+es6开 ...
- webpack+react+redux+es6开发模式
一.预备知识 node, npm, react, redux, es6, webpack 二.学习资源 ECMAScript 6入门 React和Redux的连接react-redux Redux 入 ...
- iOS开发之记录用户登录状态
iOS开发之记录用户登录状态 我们知道:CoreData的配置和使用步骤还是挺复杂的.但熟悉CoreData的使用流程后,CoreData还是蛮好用的.今天要说的是如何记录我们用户的登陆状态.例如微信 ...
- 开发错误记录8:Unable to instantiate application com
开发错误记录8:Unable to instantiate application com.android.tools.fd.runtime.BootstrapApplication 这是因为在And ...
- 【转】使用gulp 进行ES6开发
原谅地址:https://segmentfault.com/a/1190000004394726 一说起ES6,总会顺带看到webpack.babel.browserify还有一些认都不认识的blab ...
- Arduino单片机使用和开发问题记录(转)
源:Arduino单片机使用和开发问题记录 1.将程序上传到板子时Arduino IDE提示“avrdude: stk500_getsync(): not in sync: resp=0x00” 网上 ...
- webpack+react+redux+es6开发模式---续
一.前言 之前介绍了webpack+react+redux+es6开发模式 ,这个项目对于一个独立的功能节点来说是没有问题的.假如伴随着源源不断的需求,前段项目会涌现出更多的功能节点,需要独立部署运行 ...
- IOS开发之记录用户登陆状态,ios开发用户登陆
IOS开发之记录用户登陆状态,ios开发用户登陆 上一篇博客中提到了用CoreData来进行数据的持久化,CoreData的配置和使用步骤还是挺复杂的.但熟悉CoreData的使用流程后,CoreDa ...
随机推荐
- Day-1:初识开发板与基础知识
买的这款51,ARM,AVR三合一的单片机,也不知道后面具体使用会不会有问题,先玩玩看吧. ------------------------------------------------------ ...
- MySQL高级查询(二)
EXISTS 和NOT EXISTS子查询 EXISTS子查询 语法: SELECT ……… FROM 表名 WHERE EXISTS (子查询); 例: SELECT `studentNo` A ...
- 第6章 Overlapped I/O, 在你身后变戏法 ---被激发的 Event 对象 -4
以文件 handle 作为激发机制,有一个明显的限制,那就是没办法说出到底是哪一个 overlapped 操作完成了.如果每个文件 handle 只有一个操作等待决定,上述问题其实并不成为问题.但是如 ...
- Egg + Vue 服务端渲染工程化实现
在实现 egg + vue 服务端渲染工程化实现之前,我们先来看看前面两篇关于Webpack构建和Egg的文章: 在 Webpack工程化解决方案easywebpack 文章中我们提到了基于 Vue ...
- Elasticsearch 数据搜索
ES即简单又复杂,你可以快速的实现全文检索,又需要了解复杂的REST API.本篇就通过一些简单的搜索命令,帮助你理解ES的相关应用.虽然不能让你理解ES的原理设计,但是可以帮助你理解ES,探寻更多的 ...
- zoj1109 水题(大神绕道) Language of FatMouse
Language of FatMouse Time Limit: 10 Seconds Memory Limit:32768 KB We all know that FatMouse doe ...
- var let const 的区别
Var let const 的区别 1.Var 定义的变量存在变量提升,而了let和const不存在变量提升.即在定义的变量代码上使用该变量,var的会输出undefined,而let的会报错. 2. ...
- wampserver里面出现403错误的问题解决方法
今天再装wampserver的时候,不能进入localhost和phpmyadmin,提示403错误,我自己是win10系统,已通过以下方法解决了: 1.第一个问题,就是wampserver没有切换到 ...
- 学习笔记之09小练习题(js:从小到大输出三个任意数,查成绩,相亲题,查体重,一元二次方程求根)
<script type="text/javascript"> /*第一题.输入三个整数,x,y,z,最终以从小到大的方式输出. 注意小点:1 字符串的拼接是用+,数学 ...
- 51nod 1510 最小化序列 | DP 贪心
题目描述 现在有一个长度为n的数组A,另外还有一个整数k.数组下标从1开始. 现在你需要把数组的顺序重新排列一下使得下面这个的式子的值尽可能小. ∑|A[i]−A[i+k]| 特别的,你也可以不对数组 ...