基于 require 与 angular-ui-router 实现 angular 按需加载。
使用组件化的思路来定义页面。每一个页面组件有独立的 controller,controller 可以跟随组件自身被异步加载进主页面,不需要初始化时预先载入全部 controller 代码。并且组件也有完整的生命周期,可以实现安装与卸载,降低内存泄漏的风险。
- 公司过于保守,不愿意尝试其他新兴框架。
- 项目中人员目前只熟悉 Angular 1.x。
- 项目中人员比较习惯使用 jQuery 来完成除数据绑定以外的其他功能需求。
- 项目中使用到大量需要操作 DOM 的插件,如:Bootstrap 等。
- 希望开发 SPA(单页面)应用,但又担心项目过于庞大,首次加载过慢。
一个组件就是一个文件夹,文件夹内有与文件夹同名的 html 和 js 文件,css 文件可以直接在 html 中使用 <link> 引入(如果使用相对路径,就必须是相对主页面的路径,而不是相对组件 html 的路径)。
component
|-- component.html
|-- component.js
|-- component.css
js 文件需要遵循 AMD 规范,使用 define
将文件定义为一个模块。routeApp
是基于 angular-ui-router 封装的核心模块。
define(['routeApp'], function(routeApp) {
routeApp.controller('componentCtrl', function($scope) {
// controller 内部在页面每次载入时也会执行
$scope.name = '我是一个组件';
});
var $component;
function scrollHandle(e) {
// 屏幕滚动时的处理
}
// 返回值可以包含安装和卸载方法
return {
// 安装
install: function(data) { // 接收上一个页面的传值
data && console.log(data.msg);
// 所有 DOM 操作,以及添加事件监听的行为必须在安装方法中执行
$component = document.getElementById('component');
window.addEventListener('scroll', scrollHandle);
},
// 卸载
uninstall: function() {
// 移除事件监听,以及一些 DOM 的引用
window.removeEventListener('scroll', scrollHandle);
$component = null;
return { // 卸载后可以向下一个页面传值
msg: '传达我的问候'
};
}
}
});
注意,模块返回的 install
与 uninstall
并不是必须的,如果代码中没有对其他对象的强引用操作,则可以省略返回值。
一个路由也就是一个 angular-ui-router 的 state。
var routes = [{
name: 'page1',
component: 'pages/page1'
}, ...]
路由属性的完整配置:
-
name
- 路由链接的 ui-sref,同时也是路由的 state 名称。 -
component
- 组件(文件夹)路径。 -
hasjs
- 可选。布尔值,明确指出组件是否包含 js,默认为true
。 -
text
- 可选。路由文本。路由生成后可以在路由的 state 对象上访问到。 -
path
- 可选。在浏览器地址栏显示的路径,同时也是生成链接的真实 href。默认情况下等于 name。 -
from
- 可选。字符串或者正则表达式,所有匹配的路径都会重定向到该页面。默认为空。'*'
表示其余 url 都重定向到该页面。'/path/*'
表示与星号之前路径匹配的所有 url 都会重定向到该页面。 -
children
- 可选。子路由数组
routeApp
模块是一个 angular-ui-router 路由实现的简单封装对象,使用非常简单。
require(['routeApp'], function(routeApp) {
var routes = [...];
routeApp.module.controller('mainCtrl', function($scope) {
// 可以直接使用路由配置数组去生成菜单
$scope.menus = routes;
});
routeApp.install(routes); // 安装路由
routeApp.start(); // 启动应用
});
你可以通过 routeApp.module
完成主页面的 controller 注册,它实际上就是 angular.module()
创建的一个 Angular 模块。
angular
- angular 对象的引用。module
- routeApp 的 module 对象引用。curRoute
- 路由的当前路线 js 模块的返回值。version
- 加载路由资源时的版本号后缀。$state
- angular-ui-router 的 $state 服务引用。
install
- 安装路由。start
- 启动应用。可以传入一个 DOM 元素,表示应用的挂在对象。默认为 document。on
- 注册事件监听。off
- 移除事件监听。controller
- 用于注册组件的controller
控制器。实际上调用的是$controllerProvider.register
。
changeBefore
- 注册路由的changeBefore
监听,对应 angular-ui-router 的$stateChangeStart
事件。回调参数分别为event
,toState
,toParams
,fromState
,fromParams
。change
- 注册路由的change
监听,对应 angular-ui-router 的$stateChangeSuccess
事件。回调参数分别为event
,toState
,toParams
,fromState
,fromParams
。changeAfter
- 注册路由的changeAfter
监听,对应 angular-ui-router 的$viewContentLoaded
事件。回调参数为event
。
需要注意的是,每个组件注册的 controller
与 install
一样都会在每次页面安装时执行。
执行顺序是:
changeBefore
回调 =>- 执行旧组件页面的
uninstall
,并将需要传递给新组件页面的数据通过return
返回 => - 新组件页面初始化(仅执行一次,之后再次安装页面不会执行) =>
change
回调 =>- 执行新组件页面的
controller
=> - 执行新组件页面的
install
,并将旧组件页面传递的数据注入 => changeAfter
回调 => End
我们可以使用 r.js 来打包压缩项目主页面所用到的所有 js 模块。组件的 js 无需打包,组件被加载时,它们才会被载入页面。其余的 css、image 等文件使用一些前端自动化工具打包压缩即可。