我是卡卡卡颂


  • 首页

  • 归档

  • 标签

angular--ngDialog最佳实践

发表于 2017-04-02

ngDialog是什么

ngDialog是一款ng1.*的第三方浮窗插件,其正确的使用方法可以说是MVVM思想的浓缩体现。

实现目标

  • 提供一个弹窗
  • 弹窗提供必要的模板,该模板(HTML结构)可复用
  • 对于具体业务逻辑(新增还是修改,在不同的controller中实现)

例子

  1. 首先我们定义一个打开操作弹窗的服务,或者在服务中定义一个打开弹窗的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    //可以用来新增 的弹窗
    function addDialog(data) {
    var defer=$q.defer();
    ngDialog.open({
    //模板地址
    templateUrl:'xxx.html',
    className: 'ngdialog-theme-default',
    width: 640,
    closeByDocument: false,
    showClose: true,
    //用来新增的ngDialog的controller
    controller: 'AddCtrl',
    //传入ngDialog controller的依赖
    resolve: {
    //依赖名为dep,依赖的对象为传入的参数
    dep: function() {
    return data;
    }
    },
    /**
    * 关闭弹窗前的回调
    * 区分是点击关闭按钮 还是保存按钮,返回promise的不同状态
    */
    preCloseCallback: function(data) {
    if (data==='$closeButton') {
    defer.reject();
    } else {
    defer.resolve(data);
    }
    }
    })
    return defer.promise;
    }
  2. 接下来定义新增的dialog的控制器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    angular.module('app').controller('AddCtrl',AddCtrl);
    AddCtrl.$inject=['$scope','dep','ngDialog'];
    function AddCtrl($scope,dep,ngDialog) {
    initStatus();
    function initStatus() {
    /*取到依赖的数据,也就是调用addDialog服务时传入的参数
    *浮窗中所有数据与$scope.data下的数据双向绑定
    * 所以可以通过传入的初始配置项改变模板中的数据(比如传入title字段 改变弹窗的title)
    */
    $scope.data={
    params:dep
    }
    }
    /**
    * 点击保存设置时触发
    * close的传参将传给preCloseCallback,
    * preCloseCallback再根据关闭窗口的类型(关闭还是保存)处理
    * 当为保存配置时,配置参数作为传参传给promise的resolve状态
    */
    $scope.submitForm=function() {
    ngDialog.close($scope.ngDialogId,$scope.data.params);
    }
    }
  3. 在需要打开浮窗的控制器中调用addDialog服务,传入初始配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
angular.module('app').controller('PermissionProjectCtrl',PermissionProjectCtrl);
PermissionProjectCtrl.$inject=['$scope','ngDialog','permissionService'];
function PermissionProjectCtrl($scope,ngDialog,permissionService) {
$scope.createNewPermission=function() {
//初始配置项
var params={
title:'新增项目权限',
type:'project'
}
permissionService.addDialog(params).then(function(data) {
//表单处理完成后 传出处理后的数据 data 这里再调用新建对应 对接口 所在的服务,继续后续处理
})
}
}

angular--用mock模拟数据

发表于 2017-03-30

应用场景

当前端写好页面,而后台没有提供接口和数据时,可以先把获取数据的service做好,传入json类型的mock数据
来模拟调取数据的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//模拟权限角色数据的获取
angular.module('app').factory('authRoleService', authRoleService);
authRoleService.$inject = ['$q', 'iHttpService'];
function authRoleService($q, iHttpService) {
return {
//根据类型获取角色列表
getRolesByType: getRolesByType,
};
function getRolesByType(_type) {
var defer = $q.defer();
//var url = "/api/v1/lawOffice/"+window.localStorage.officeid;
var url = "auth/mock/roles.json";
iHttpService.mockServer(url, {}, "get").then(function (data) {
defer.resolve(data.data);
}, function () {
defer.reject();
});
return defer.promise;
}
}

接下来提供mock数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{
"data": [
{
"description": "我是负责人的描述",
"id": 0,
"name": "负责人",
"officeId": "string",
"permission": {},
"subjectId": "string",
"subjectType": "string",
"type": "string",
"valid": true
},
{
"description": "我是参与人的描述",
"id": 1,
"name": "参与人",
"officeId": "string",
"permission": {},
"subjectId": "string",
"subjectType": "string",
"type": "string",
"valid": true
},
{
"description": "我是实习生的描述",
"id": 2,
"name": "实习生",
"officeId": "string",
"permission": {},
"subjectId": "string",
"subjectType": "string",
"type": "string",
"valid": true
}
],
"resultCode": "string",
"resultMessage": "string"
}

最后,我们只需要调用相应的服务,获取请求成功状态的数据就行了

Angular指令执行流程

发表于 2017-03-29

流程概览

整个流程分为两个阶段:$compile 和 nodeLinkFn

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//总体流程
// The compile phase
parent (compile)
..first-child (compile)
..second-child (compile)
// The link phase
parent (controller)
parent (pre-link)
..first-child (controller)
..first-child (pre-link)
..first-child (post-link)
..second-child (controller)
..second-child (pre-link)
..second-child (post-link)
parent (post-link)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//例子
<div ng-repeat="i in [0,1,2]">
<my-element>
<div>Inner content</div>
</my-element>
</div>
//指令如下
myApp.directive( 'myElement', function() {
return {
restrict: 'EA',
transclude: true,
template: '<div>{{label}}<div ng-transclude></div></div>'
}
});
  1. 首先进入$compile。其中tElement和tAttributes为指令传入的属性。如果指令内部有嵌套的子指令(如ng-repeat),
    则会遍历调用所有子指令的compile。在我们的例子里,三个子source template(通过ng-repeat)会被创建,所以compile会调用一共4次。

    1
    2
    //一个compile函数API类似
    compile: function compile( tElement, tAttributes ) { ... }
  2. 接下来进入nodeLinkFn阶段(link阶段)。经由$compile返回的link函数被提供一个scope。
    首先link函数创建一个子scope(scope:true),或者一个隔离作用域(scope:{…})。接着执行controller函数,传入scope。

    1
    2
    //一个controller函数API类似
    controller: function controller($scope, $element, $attrs,$transclude ) { ... }
  3. 接下来进入pre-link阶段,基本上在controller和preLink之间不会执行其他函数。在父级preLink被调用,紧接着会遍历调用子级preLink。

    1
    2
    //一个preLink函数API类似
    preLink: function preLink(scope, element, attrs,controller ) { ... }
1
2
//postLink与preLink API类似
postLink: function postLink(scope, element, attrs,controller ) { ... }

注意当一个
子级preLink函数执行完后会继续执行该子子级的postLink函数,接着再执行下一个子级的preLink与postLink。也就说当父级执行postLink时,其所有子级的link函数都已执行完毕。这意味着子级已经完成:

  • 数据绑定
  • transclusion已经应用
  • scope形成
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //这个阶段的DOM结构看起来如下
    <my-element>
    <div class="ng-binding">
    "{{label}}"
    <div ng-transclude>
    <div class="ng-scope">Inner content</div>
    </div>
    </div>
    </my-element>

js学习--事件循环机制

发表于 2017-03-29

基本概念

  • js作为单线程语言,线程中只拥有一个事件循环。
  • 代码的运行顺序取决于函数调用栈和队列。
  • 一个线程中,事件循环是唯一的,但是任务队列可以有多个。
  • 任务队列分为宏任务(macro-task,新标准中叫做task)和微任务(micro-task,新标准中叫做jobs)
  • macro-task包括:script(整体代码)、setInterval/setTimeout

js学习--函数柯里化

发表于 2017-03-26

定义

currying,又称部分求值。一个currying的函数首先会接受一些参数,接受了这些参数后,
该函数并不会立即求值,而是继续返回另一个函数,刚才传入的参数在函数形成的闭包中被保存起来。
待到函数真正需要求值时,之前传入的所有参数都会被一次性用于求值。

一个柯里化思想展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var cost=(function() {
var args=[];
return function() {
if (arguments.length===0) {
var money=0;
for (var i=0,l=args.length;i<l;i++) {
money+=args[i];
}
console.log(money);
return money;
} else {
[].push.apply(args,arguments);
}
}
})()
cost(100);
cost(200);
cost(300);
cost(); //600

一个通用的currrying函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var currying=function(fn) {
var args=[];
return function() {
if (arguments.length===0) {
return fn.apply(this,args);
} else {
[].push.apply(args,arguments);
return arguments.callee;
}
}
}
var cost=(function() {
var money=0;
return function() {
for (var i=0;i<arguments.length;i++) {
money+=arguments[i];
}
return money;
}
})()
var cost=currying(cost); //转化为currying函数
cost(100);
cost(100);
cost(200);
cost(); //400

设计模式--装饰者模式

发表于 2017-03-26

用途

动态的给某个对象添加一些额外的职责,而不会影响从这个类中派生的其他对象。

简单的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var Plane=function() {
}
Plane.prototype.fire=function() {
console.log('fire!');
}
var MissileDecorator=function(plane) {
this.plane=plane;
}
MissileDecorator.prototype.fire=function() {
console.log('missile!!');
this.plane.fire();
}
var plane=new Plane();
plane=new MissileDecorator(plane);
plane.fire();

设计模式--职责链模式

发表于 2017-03-22

简介

职责链使多个对象都有机会处理请求,将这些对象连成一条链,并沿着这条链传递该请求,知道有一个对象
处理他为止。避免了请求发送者和接受者之间的耦合。

简单的职责链实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
var Chain=function(fn) {
this.fn=fn;
this.successor=null;
}
Chain.prototype.setNextSuccessor=function(successor) {
return this.successor=successor;
}
Chain.prototype.passRequest=function() {
var ret=this.fn.apply(this,arguments);
if (ret==='nextSuccessor' && this.successor) {
return this.successor.passRequest.apply(this.successor,arguments);
}
return ret;
}
//使用
var fn1=new Chain(function() {
console.log(1);
return 'nextSuccessor';
})
var fn2=new Chain(function() {
console.log(2);
return 'nextSuccessor';
})
var fn3=new Chain(function() {
console.log(3);
})
fn1.setNextSuccessor(fn2);
fn2.setNextSuccessor(fn3);
fn1.passRequest();

增加对异步请求的处理 可以让节点有权力决定什么时候把请求传递给下一个节点

1
2
3
4
5
Chain.prototype.next=function() {
if (this.successor) {
return this.successor.passRequest.apply(this.successor,arguments);
}
}

利用AOP实现职责链

1
2
3
4
5
6
7
8
9
10
Function.prototype.after=function(fn) {
var self=this;
return function() {
var ret=self.apply(this,arguments);
if (ret==='nextSuccessor') {
return fn.apply(this,arguments);
}
return ret;
}
}

设计模式--享元模式

发表于 2017-03-21

简介

  • 享元模式(FlyWeight)是一种用于性能优化的模式,运用共享技术来有效支持大量细粒度的对象。主要用于
    当系统中创建了大量类似的对象从而导致内存占用过时的情况。
  • 享元模式要求将对象的属性划分为内部状态(属性)和外部状态(属性)。目标是尽量减少共享对象的数量。

    如何划分内部对象和外部对象

  • 内部状态存储于对象内部。
  • 内部状态可以被一些对象共享。
  • 内部状态独立于具体的场景,通常不会改变。
  • 外部状态取决于具体的场景,并根据场景而变化,外部状态不能被共享。

    何时使用

  1. 一个程序中使用了大量相似的对象
  2. 由于使用了大量对象,造成很大的内存开销
  3. 对象的大多数状态都可以变为外部状态
  4. 剥离出对象的外部状态后,可以用相对较少的共享对象取代大量对象。
    5.

设计模式--组合模式

发表于 2017-03-20

组合模式的作用

组合模式将对象组成树形结构,以表示’整体-部分’的结构。利用对象的多态性统一对待组合对象和单个对象。
树结构的节点分为组合节点和叶节点。叶节点下面不会再有节点,组合节点下面可能还有其他组合节点和叶节点。

什么时候使用组合模式

  1. 表示对象的部分-整体层次结构。
  2. 客户希望统一对待树中的所有对象。

例子:扫描文件夹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//folder是组合节点
var Folder=function(name) {
this.name=name;
this.files=[];
}
Folder.prototype.add=function(file) {
this.files.push(file);
}
Folder.prototype.scan=function() {
console.log('开始扫描文件夹:',this.name);
for (var i=0;i<this.files.length;i++) {
this.files[i].scan();
}
}
//file是叶节点
var File=function(name) {
this.name=name;
}
File.prototype.add =function() {
throw new Error('文件下面不能再添加文件');
}
File.prototype.scan=function() {
console.log('当前文件名:',this.name);
}
//使用
var folder1=new Folder('所有资料');
var folder2=new Folder('生活资料');
var folder3=new Folder('工作资料');
var file1=new File('数学');
var file2=new File('语文');
var file3=new File('钻木取火');
var file4=new File('nodeJs从入门到放弃');
folder1.add(file1);
folder1.add(file2);
folder2.add(file3);
folder3.add(file4);
folder1.add(folder2);
folder1.add(folder3);
folder1.scan();

值得注意的地方

  1. 组合模式不是父子关系,而是一种(HAS-A)聚合关系。
  2. 对一组叶对象的操作必须具有一致性。也就是说不能对某个叶对象单独操作,要一视同仁。
  3. 为️防止一个叶节点关联到多个组合对象,需要建立组合节点和叶节点的双向映射关系。

保持叶节点和组合节点的关联。比如在组合模式中使用职责链时,有可能需要让请求从子节点往父节点上冒泡传递。当我们删除某个文件时,实际是从这个文件所在的上层文件夹中删除这个文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
var Folder=function(name) {
this.name=name;
this.parent=null;
this.files=[];
}
Folder.prototype.add=function(file) {
this.files.push(file);
file.parent=this;
}
Folder.prototype.scan=function() {
console.log('开始扫描文件夹:',this.name);
for (var i=0;i<this.files.length;i++) {
this.files[i].scan();
}
}
Folder.prototype.rmove=function() {
//根节点
if (!this.parent) {
return;
}
for (var files=this.parent.files,i=files.length-1;i>=0;i--) {
var file=files[i];
if (file===this) {
files.splice(i,1);
}
}
}
var File=function(name) {
this.name=name;
this.parent=null;
}
File.prototype.add=function() {
throw new Error('不能添加在文件下面');
}
File.prototype.scan=function() {
console.log('扫描到文件:',this.name);
}
File.prototype.remove=function() {
if (!this.parent) {
return;
}
for (var files=this.parent.files,i=files.length-1;i>=0;i--) {
var file=files[i];
if (file===this) {
files.splice(i,1);
}
}
}

css学习--relative

发表于 2017-03-13
  1. relactive限制子孙定位元素定位
  2. 设置了具体z-index值,会创建层级上下文,则内部absolute层级都是在此层级上排列。
  3. absolute元素突破overflow: hidden; 父relative则限制absolute子元素突破overflow.
  4. 对于fixed子元素,只能限制其z-index。
  5. 定位相对于自身位置。
  6. relative定位是无侵入,不会影响其他元素定位
  7. 同时存在对立定位属性 (top/bottom left/right),top存在时bottom无效,left存在right无效。
  8. 可以提高层叠上下文
  9. relative z-index:auto;不会新建层叠上下文,不会限制内部absolute层级(除IE6/IE7)
12…5
BetaSu

BetaSu

一言不合撸源码

50 日志
© 2017 BetaSu
由 Hexo 强力驱动
主题 - NexT.Pisces