Angularjs的工程化

AMD规范和CMD规范

为什么需要模块化管理工具

在编写项目时可能需要加载很多js文件,若b.js依赖a.js,且a.js比b.js大很多,那么浏览器会让b.js等待a.js加载完毕后再去执行b.js里的内容;而即使d.js并不依赖a.js,b.js,c.js,也会等待这三个文件均加载完毕才执行,为了让浏览器能够按需加载,提出了模块化管理工具。

<script type="text/javascript" src="js/a.js"></script>
<script type="text/javascript" src="js/b.js"></script>
<script type="text/javascript" src="js/c.js"></script>
<script type="text/javascript" src="js/d.js"></script>

AMD规范

全称为Asynchronous Module Defined,即异步模块管理,它通过使用依赖注入等方法完整描述了模块的定义、依赖关系、引用关系以及加载机制,AngularJS、RequireJS均是符合AMD规范的。

define函数

函数中有三个参数,前两个参数可以省略,第三个参数是模块的具体实现本身。 当define函数执行时,它首先会异步调用第二个参数中列出的依赖模块,当所有的模块被载入完成之后,如果第三个参数是一个回调函数则执行,然后告诉系统模块可用,也通知了依赖于自己的模块自己已经可用。

define([module-name?], [array-of-dependencies?], [module-factory-or-object]);

其中:
module-name: 模块标识,可以省略。
array-of-dependencies: 所依赖的模块,可以省略。
module-factory-or-object: 模块的实现,或者一个JavaScript对象。

下面代码定义了一个alpha模块,并且依赖于内置的require,exports模块,以及外部的beta模块。

define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
exports.verb = function() {
return beta.verb();
};
});

案例

项目结构

案例

│ test.html



└─js

│ main.js

│ math.js

│ pi.js



└─lib

require.js

项目代码
test.html
<!DOCTYPE html>
<html>
<head>
<title>RequireJS学习</title>
</head>
<body>
<script data-main="js/main.js" src="js/lib/require.js"></script>
<!-- main.js是主入口文件 -->
</body>
</html>
main.js
requirejs.config({
baseUrl: 'js', //所有js程序的根目录
paths: {
//别名
"math": "math"
}
}); requirejs(["math"],
function(math){
alert(math.squre(8));
alert(math.area(10));
});
alert("hello");
math.js
define(["pi"], function(pi){
alert("我是math");
return {
"squre": function(number){
return number * number;
},
"area": function(r){
return pi.pi * r *r;
}
};
});
pi.js
define({
"pi": 3.1415926
})
项目说明
  • 在html文件中引包时需要同时指定require.js文件和main.js文件;

  • main.js是主入口文件,只有主入口main.js能用requirejs,其他入口只能用define;

  • math.js用define定义模块,模块暴露的API用return返回;

  • main.js中如果有语句不需要依赖别人的语句,可以不写在回调函数里面,而现在很少有机会不在回调函数中写语句,即AMD和CMD越来越像。

CMD规范

全称为Common Module Defined,即普通模块管理,其执行过程是懒式的。NodeJS、SeaJS、CommonJS、webpack均是符合CMD规范的。

define函数

define(function(require, exports, module) {
// 模块定义在此
});

AngularJS的工程化

angular-async-loader

angular-async-loader可以轻松解决ReuqireJS和AngularJS之间的粘合问题。angular-async-loader官网

安装前端依赖

大体思路就是用RequireJS配置AngularJS项目,配置步骤如下。

  • 进入项目文件夹,在命令行窗口执行下列指令,创建bower前端依赖文件。

    bower init
  • 创建.bowerrc文件并进行配置(先创建一个空文档,再在命令行用rename重命名为.bowerrc),配置内容如下,配置后,用bower下载的模块会生成在assets文件夹下。

    {
    "directory" : "assets"
    }
  • 安装AngularJS。

    bower install angular --save
  • 安装ui-router。

    bower install angular-ui-router --save
  • 安装RequireJS。

    bower install requirejs --save
  • 安装angular-async-loader。

    bower install angular-async-loader --save

书写三大文件

三大文件为app-routes.js、app.js、bootstrap.js。

在项目根目录下分别创建ngApp文件夹、app-routes.js、app.js、bootstrap.js、index.html文件。

bootstrap.js

bootstrap.js是RequireJS的入口文件。

require.config({
baseUrl: '/',
//别名
paths: {
'angular': 'assets/angular/angular.min',
'angular-ui-router': 'assets/angular-ui-router/release/angular-ui-router.min',
'angular-async-loader': 'assets/angular-async-loader/dist/angular-async-loader.min'
},
//声明paths中元素暴露的接口和依赖
shim: {
'angular': {exports: 'angular'}, //暴露的是angular
'angular-ui-router': {deps: ['angular']} //依赖的是angular
}
});
//核心入口
require(['angular', './app-routes'], function (angular) {
//当整个文档就绪之后
angular.element(document).ready(function () {
//angular.bootstrap是一个方法,表示启动angular
angular.bootstrap(document, ['myapp']);
//通过类名添加ng-app指令,也可以通过attr来添加
angular.element(document).find('html').addClass('ng-app');
});
});

app.js

app.js中创建了app对象。

define(function (require, exports, module) {
//这是一个CMD规范的模块,模块的作用是向外暴露app整体
//AMD只能向外暴露json形式的API //引入依赖
var angular = require('angular');
var asyncLoader = require('angular-async-loader'); require('angular-ui-router'); //创建app对象,app对象依赖ui.router
var app = angular.module('app', ['ui.router']); // initialze app module for angular-async-loader
asyncLoader.configure(app);
//向外暴露
module.exports = app;
});

app-routes.js

app-routes.js中定义了路由,这里采用了连续依赖,bootstrap.js依赖app-routes.js,app-routes.js依赖app.js。

define(function (require) {
//引入app对象
var app = require('./app');
//定义路由
app.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home'); $stateProvider
.state('home', {
url: '/home',
template: '<h1>我是首页!</h1>'
});
}]);
});

index.html

index.html是唯一的单页面,但不表示只存在一个html页面,其他页面可作为模板存在,在index.html文件中创建一个ui-view容器,然后用RequireJS语法引用入口文件bootstrap.js。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>
测试系统
</title>
</head>
<body>
<ui-view></ui-view> <script type="text/javascript" src="assets/requirejs/require.js" data-main="bootstrap.js"></script>
</body>
</html>

ngApp

ngApp里可根据场景创建相应文件夹,存放编写控制器、服务和指令等内容的js文件。此处创建root文件夹和home文件夹。

root
RootCtrl.js
define(function (require) {
var app = require('app');
require('./rootService');
// dynamic load services here or add into dependencies of ui-router state config
// require('../services/usersService'); app.controller('RootCtrl', ['$scope', 'rootService', function ($scope, rootService) {
this.a = rootService.m;
}]); });
rootService.js
define(function (require) {
var app = require('app'); // dynamic load services here or add into dependencies of ui-router state config
// require('../services/usersService'); app.factory("rootService", function () {
return {
m : 9
}
}); });
template.html
<div>
<header>
<h1>我是root的template文件</h1>
{{rootCtrl.a}}
<nav>
<a ui-sref="root.home" ui-sref-active="cur">首页</a>
</nav>
</header>
<ui-view> </ui-view>
<footer>我是footer</footer>
</div>

home

HomeCtrl.js
define(function (require) {
var app = require('app');
require('jquery'); //var $ = require('jquery');为什么不用变量接收,因为jquery的原理就是给window对象添加属性
require('jquery-ui');
app.controller('HomeCtrl', [function () {
this.a = 100;
$('.box').animate({ 'font-size': 100 }, 1000, function () {
$(this).css("color", "red");
$(this).draggable();
});
}]); });
template.html
<div>
<h1>我是首页。{{homeCtrl.a}}</h1>
<div class="box">你好</div>
</div>

jquery的引用

法一:

最简单的方法就是在index.html上引用,这样可以在全局上使用$函数,缺点是不管页面是否使用jquery,总是先会加载完毕。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>测试系统</title>
<link rel="stylesheet" href="css/root.css" />
</head>
<body>
<ui-view></ui-view>
<script
type="text/javascript"
src="/assets/jquery/dist/jquery.min.js"
></script>
<script
type="text/javascript"
src="/assets/requirejs/require.js"
data-main="bootstrap.js"
></script>
</body>
</html>

法二:

也可以在bootstrap.js上起一个别名,使用RequireJS加载jquery。

require.config({
baseUrl: '/',
//别名
paths: {
'angular': 'assets/angular/angular.min',
'angular-ui-router': 'assets/angular-ui-router/release/angular-ui-router.min',
'angular-async-loader': 'assets/angular-async-loader/dist/angular-async-loader.min',
'jquery': 'assets/jquery/dist/jquery.min'
},
//声明paths中元素暴露的接口和依赖
shim: {
'angular': {exports: 'angular'}, //暴露的是angular
'angular-ui-router': { deps: ['angular'] }, //依赖的是angular
'jquery': {exports: 'jquery'} //暴露的是jquery
}
});

然后在需要使用jquery的控制器中写入如下代码。

define(function (require) {
var app = require('app');
var jquery = require('jquery');
app.controller('HomeCtrl', [function () {
jquery('.box').animate({ 'font-size': 100 }, 1000);
}]); });

若要引入jquery的插件,需要bower下载jquery-ui,然后改变bootstrap.js

require.config({
baseUrl: '/',
//别名
paths: {
'angular': 'assets/angular/angular.min',
'angular-ui-router': 'assets/angular-ui-router/release/angular-ui-router.min',
'angular-async-loader': 'assets/angular-async-loader/dist/angular-async-loader.min',
'jquery': 'assets/jquery/dist/jquery.min',
'jquery-ui': 'assets/jquery-ui/jquery-ui.min'
},
//声明paths中元素暴露的接口和依赖
shim: {
'angular': {exports: 'angular'}, //暴露的是angular
'angular-ui-router': { deps: ['angular'] }, //依赖的是angular
'jquery': {exports: 'jquery'}, //暴露的是jquery
'jquery-ui': { deps: ['jquery'] }, //依赖的是jquery
}
});

在控制器中写入如下代码。

define(function (require) {
var app = require('app');
var $ = require('jquery');
require('jquery-ui');
app.controller('HomeCtrl', [function () {
this.a = 100;
$('.box').animate({ 'font-size': 100 }, 1000, function () {
$(this).css("color", "red");
$(this).draggable();
});
}]); });

项目结构

项目

│ app-routes.js

│ app.js

│ bootstrap.js

│ index.html



├─assets

│ ├─angular

│ ├─angular-async-loader

│ ├─angular-ui-router

│ ├─jquery

│ ├─jquery-ui



├─css

│ root.css



└─ngApp

├─home

│ HomeCtrl.js

│ template.html



└─root

RootCtrl.js

rootService.js

template.html

注:在项目中使用ctrl+p,可以定位到目标文件。

Angularjs的工程化的更多相关文章

  1. 基于AngularJS的企业软件前端架构[转载]

    这篇是我参加QCon北京2014的演讲内容: 提纲: 企业应用在软件行业中占有很大的比重,而这类软件多数现在也都采用B/S的模式开发,在这个日新月异的时代,它们的前端开发技术找到了什么改进点呢? B/ ...

  2. 阿里云无线&前端团队是如何基于webpack实现前端工程化的

    背景 前端经历了初期的野蛮生长(切图,写简单的特效)——为了兼容浏览器兼容性而出现的各种类库(JQUERY,YUI等——mv*(饱暖思淫欲,代码多了,也就想到怎样组织代码结构,backbone,ang ...

  3. 前端教程&开发模块化/规范化/工程化/优化&工具/调试&值得关注的博客/Git&面试-资源汇总

    内容精简 资源这么多,多看看多学习再总结肯定是好的.多读读就算看重了不算浪费时间,毕竟一千个读者就有一千个林黛玉,还有温故而知新,说不定多读一些内容,就发现惊喜了呢.不过,在此也精简一些内容,就1~2 ...

  4. 从AngularJS2谈到前台开发工程化

    才刚刚对AngularJS有些了解,又听闻AngularJS2早就铺天盖地了,AngularJS3刚刚夭折,AngularJS4今年已经发布了,还是学习先下AngularJS2吧,据说更加适合以移动为 ...

  5. 从零开始搭建口袋妖怪管理系统(4)-借助webpack4.6工程化项目(上)

    "手动是不可能手动的了,这辈子都不可能手动的了." 一.目标 上一章我们借助ngRoute,完成了口袋妖怪SPA系统的多模块导航开发,但是现在引用的东西越来越多,项目文件目录开始变 ...

  6. 通过AngularJS实现前端与后台的数据对接(二)——服务(service,$http)篇

    什么是服务? 服务提供了一种能在应用的整个生命周期内保持数据的方法,它能够在控制器之间进行通信,并且能保证数据的一致性. 服务是一个单例对象,在每个应用中只会被实例化一次(被$injector实例化) ...

  7. AngularJs之九(ending......)

    今天继续angularJs,但也是最后一篇关于它的了,基础部分差不多也就这些,后续有机会再写它的提升部分. 今天要写的也是一个基础的选择列表: 一:使用ng-options,数组进行循环. <d ...

  8. AngularJS过滤器filter-保留小数,小数点-$filter

    AngularJS      保留小数 默认是保留3位 固定的套路是 {{deom | number:4}} 意思就是保留小数点 的后四位 在渲染页面的时候 加入这儿个代码 用来精确浮点数,指定小数点 ...

  9. Angular企业级开发(1)-AngularJS简介

    AngularJS介绍 AngularJS是一个功能完善的JavaScript前端框架,同时是基于MVC(Model-View-Controller理念的框架,使用它能够高效的开发桌面web app和 ...

  10. 模拟AngularJS之依赖注入

    一.概述 AngularJS有一经典之处就是依赖注入,对于什么是依赖注入,熟悉spring的同学应该都非常了解了,但,对于前端而言,还是比较新颖的. 依赖注入,简而言之,就是解除硬编码,达到解偶的目的 ...

随机推荐

  1. Hugging Face发布diffuser模型AI绘画库初尝鲜!

    作者:韩信子@ShowMeAI 深度学习实战系列:https://www.showmeai.tech/tutorials/42 TensorFlow 实战系列:https://www.showmeai ...

  2. 分布式ID生成方案总结整理

    目录 1.为什么需要分布式ID? 2.业务系统对分布式ID有什么要求? 3.分布式ID生成方案 3.1 UUID 3.2.数据库自增 3.3.号段模式 3.4. Redis实现 3.4. 雪花算法(S ...

  3. Mysql之MGR高可用实战案例

    MGR高可用实战案例 1.环境准备 node1 rocky8.6 10.0.0.8 node2 rocky8.6 10.0.0.18 node3 rocky8.6 10.0.0.28 2.所有节点更改 ...

  4. vue 过滤器时间格式化

    1.导入了一个moment.js插件,里面封装了格式化时间的方法 ①:插件的链接:https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/mom ...

  5. xshell取消置顶

    现象:xshell置顶,导致无法正常浏览其他应用,文件等 原因分析:打开xshell时,触发其置顶快捷方式:Alt+A 解决建议:针对此问题,首先,可以从"查看栏"手动取消置顶:其 ...

  6. 关于 Windows6.1-KB2999226-x64.msu 此更新不适用你的计算机解决办法

    前言 今天被这个破问题坑了很长时间,网上一大堆扯跳过那个检查,通过提取 cab 文件然后直接用命令安装,我可以明确的告诉你不是那样的解决的,因为我实际用命令装过也装不上(这里我吐槽一下,我猜你最初的问 ...

  7. dojo 访问 VS 创建的Json文件 汉字乱码

    通过VS创建了一个json文件,直接保存成了文件放到了Web根目录下. 通过dojo的dojo/request访问,返回的汉字都是乱码. 通过以下方案解决. 用记事本把josn文件打开,然后点击另存为 ...

  8. MAUI Blazor (Windows) App 动态设置窗口标题

    接着上一篇"如何为面向 Windows 的 MAUI Blazor 应用程序设置窗口标题?" Tips: 总所周知,MAUI 除了 Windows App 其他平台窗口是没有 Ti ...

  9. 【大数据】kafka-02:Kafka Connect内容、原理及使用

    〇.概述 1.常见资料 (1)confluent https://docs.confluent.io/5.4.0/connect/kafka-connect-jdbc/sink-connector/s ...

  10. 3.4:使用Weka实现KNN分类的算法示例

    〇.概述 1.使用Weka平台,并在该平台使用数据导入.可视化等基本操作: 2.对KNN算法的不同k值进行比较,对比结果得出结论. 一.打开Weka3.8并导入数据 二.导入数据 三.KNN算法分类操 ...