用Angular(1.X)开发上一代web应用

以前focus on 移动开发商没怎么接触过重量级的前端Pc框架,此次接手一个Angular的项目,在重构前趁机学习一下。

在书中说道“Angular的整个应用都是由模型驱动的,是同中所展示的内容是模型,被存储起来的内容也是模型,几乎所有的一切都是模型”。Angular的概念比较多有 module, confroller, Template, Filter , Directors , Service。以下逐个了解下。

controller

他有三个公用

  • 为应用中的模型设置初始状态
  • 通过$scope对象把数据模型和函数暴露给视图管理模块
  • 监视模型其余部分的变量并采取相应的动作
    关于controller拆分粒度,个人认为应该向拆组件那么拆。
    controller可以嵌套,并且通过嵌套可以继承$scope.
    使用注意事项:
  • 不要试图复用controller,一个controller一般只负责一小块视图
  • 不要再Controller中操作DOM,这不是控制器的职责
  • 不要再Controller里面做数据格式化,ng有很好用的表单控件
  • 不要在controller里面做数据过滤操作,ng有Filter服务
  • 一般来说controller不会互相调用的,controller之间的交互通过事件进行 emit向

Filter

数据格式转换,作为数据在模板上展示的辅助工具

  • 内置9个filter:
    currency,date,filter,json,limitTo,lowercase,number,orderBy,uppercase
  • filter 使用|符号嵌套使用
  • filter可以传递参数
  • 可以自定义filter
{{11234567789 | data:"MM/DD/YYYY @ h:mma"}}
model.filter('filtera',function(){
    return function(item){
        return item +'hahahhah';
    }
})

Template

没什么好说的 就是View层用来展示的模板

Directors

指令 有点像是组件,特点是可以做一定的DOM操作,如事件绑定,返回指定模板到容器等。
angular 没有组件的概念,视图的复用使用directory来实现的。
指令的四种类型

restrict 匹配模式

restrict 元素 例子
A 标签(默认)
E 元素
C 样式类
M 注释方式

注意
当需要创建带有自己的模板的指令时,使元素名称的方式创建指令
当需要为已有的HTML标签增加功能的时候,使用属性的方式创建指令

template 模板
templateUrl 模板路径 支持异步请求
templateCatch 模板缓存

module.run(function($templateCatch){
//  run 方法在所有依赖注入加载完成后执行,且仅执行一次
    $templateCatch.put('hello.html',"
....
") }); module.director('hello', function($templateCatch){ return { restrict: 'AECM', template:$templateCatch.get('hello.html'), replace: true } })

link
使用link来操作dom,绑定事件,类似组件。

model.director('loader', function(){
return {
    restrict:'AE',
    link: function(scope, element, attr){
        element.bind('mouseenter', function(){
            scope.loadData();//controller中的scope
            or scope.$apply('loadData')
        })
    }
}
})

通过属性来获取不同的处理方法,达到指令复用的目的。

hahaha
model.director('loader', function(){
    return {
        restrict:'AE',
        link: function(scope, element, attrs){
            element.bind('mouseenter', function(){
                scope.$apply(attrs.howtoload)//html 不区分大小写 统一使用小写
            })
        }
    }
})

指令间通信

通过暴露controller,其他指令依赖该指令,调用controller上暴露出来的方法

    动感超人---力量
var mydoel = angular.module('model',[]);
myModule.directive('superman', function(){
    return {
        scope: {},//创建独立作用域,多指令不共享作用域。 link controller 操作基于这个scope
        restrict: 'AE',
        controller: function($scope){
        // 指令暴露出去的方法写在这里
            $scope.ablities = [];
            this.addStrengh = function() {
                $scope.ablities.push('strength');
            }
            this.addSpeed = function() {
                $scope.ablities.push('addSpeed');
            }
            this.addLight = function() {
                $scope.ablities.push('addLight');
            }
        },
        link: function(scope, element, attrs){
        // 指令内部绑定事件和数据
            element.addClass('btn btn-primary');
            element.bind('mousenter', function(){
                console.log(scope.abilities);
            })
        }
    }
});
myModule.directive('strength',function(){
    return {
        require: '^superman',// 指令依赖
        link: function(scope, element, attrs, supermanCtrl) {//第四个参数是required 中依赖的指令的作用域
            supermanCtrl.addStrength();
        }
    }
})

获取model的controller上的属性和方法

  • @ 为单向传递
    
mymodel.controller('MyCtrl', ['$scope', function($scope){
    $scope.ctrlFlavor = '百威';
}])
mymodel.directive('drink', function(){
    return {
        restrict: 'AE',
        template: "
{{flaver}}
", link: function(scope, element, attrs){ scope.flavor = attrs.flaver; } } }); //使用@绑定可以传递字符串 等价于下面 mymodel.directive('drink', function(){ return { restrict: 'AE', scope:{ flavor: '@' }, template: "
{{flaver}}
" } })
  • = 为双向绑定
    此处不举例
  • & 用于调用方法
    
mymodel.controller('MyCtrl', ['$scope', function($scope){
    $scope.sayhello = function(name){
        alert(name);
    }
}])
mymodel.directive('greeting', function(){
    return {
        restrict: 'AE',
        scope: {
            greet: '&'
        },
        template: ''
    }
});

内置指令

form
form可以嵌套
自动校验,防止重复提交
input元素类型进行扩展
text,number,submit....
内置样式: ng-valid ng-invalid ng-pristine ng-dirty

    
//如果这里写了ng-submit 不要在input中再写一遍 否则会重复递交 // $invalid 内置校验方法

replace 替换里面

service

服务获取数据的方法的封装,可以被传到各个controller中调用。有点像是公共方法的提取。

// 定义一个服务时 名称不要以$开头
    model.factory('userlist',['$http', function($http){
        function($http){
            var doRequest = function(userName, path){
                return $http([
                    method: 'GET',
                    url:'users.json'
                ])
            }
            return {
                list: function(username){
                return doRequest(username, 'userList');
                }
            }
        }
    }])
    //自定义服务写在最后面
    model.controller('servertest',['$scope', '$timeout', '$http', 'userlist',function(){
    ...
    userlist.list($scope.name).success(function(){...})
    ...
    
    }])

service 特性

  • service都是单例的
  • service由$inject 负责实例化
  • service在整个应用的生命周期中存在 可以用来共享数据
  • 在需要使用的地方利用依赖注入机制注入service
  • 自定义的service写在内置Service之后
  • 自定义Service避免$开头

其他参数

$scope

scope 是一个 plan old javascript object
scope 提供了一些工具方法 $watch $apply
$scope 是表达式的执行环境-作用域
$scope 是一个树形结构 与DOM标签平行
子scope对象会继承父scope对象
$scope 可以传播事件 类似DOM事件 可以向上向下传
scope不仅是MVC的基础 也是后面实现双向数据绑定的基础

$rootProvider 路由服务

hash后面匹配路径,仅有以下两个方法,支持匹配组

$rootProvider
.when('/list',{
    template:'listTemplate'//模板文件路径,
    controller: 'listController'//控制器名称
})
.otherwise({
    redirectTo:'/list'// default routerß
})

angular 模块化

使用Angular.module来定义模块,防止变量污染

var s = angular.module('modela', [])//后面数组中放置依赖 内容为directors等 
s.controller('modelascontroller',['$scope', function($scope){
    $scope.greeting = ……
}]) 

Angular项目的gulp工作流搭建

处理Angular编译问题

值得注意的是,一般书写时按照简写的格式:

angular.module("MyMod").controller("MyCtrl", function($scope, $timeout) {  
});

但是压缩js会破快AngularJS文件所需的依赖注入,以至于无法工作,因此压缩前你需要将代码手动修改为下面的形式:

angular.module("MyMod").controller("MyCtrl", ["$scope", "$timeout", function($scope, $timeout) {  
}]);

在此着重介绍下ng-annotate这个项目,它会自动帮你做这件事$_$,这个项目正好提供了gulp的插件.

为压缩文件添加md5 并且替换html中的链接

gulp.task('concat',['prdPackLess', 'prdPackJs','prdPackIndex'],function() {
    return gulp.src(['static/tmp/**/*.css','!static/tmp/css/sdkheader.css','static/tmp/**/*.js', '!static/tmp/js/sdkheader.js'])  //- 需要处理的css/js文件,放到一个字符串数组里 !剔除掉你不想打版本的文件
        .pipe($.rev())
        .pipe(gulp.dest('static/'))
        .pipe($.rev.manifest())   //- 生成一个rev-manifest.json
        .pipe(gulp.dest('ref/')); //- 将 rev-manifest.json 保存到 rev 目录内
});

gulp.task('rev',['concat','compressHtml', 'copy'],function() {
    return gulp.src(['ref/rev-manifest.json', 'static/tmp/html/**/*.html'])   //- 读取 rev-manifest.json 文件以及需要进行css名替换的文件
        .pipe(revCollector()) //- 执行文件内css名的替换
        .pipe(gulp.dest('static/html'));  //- 替换后的文件输出的目录

});

参考链接
前端构建的初步尝试
使用gulp压缩合并Angular项目中的Js
gulp学习指南之CSS合并压缩与MD5命名及路径替换
[用AngularJS开发下一代Web应用]

Angular 与 escript6

由于之前有使用es6开发的体验,于是好奇是不是可以使用es6来开发Angular 开来已经有人这么做了Angular1.X和es6的结合
angular es6开发指南

你可能感兴趣的:(用Angular(1.X)开发上一代web应用)