Angular 1.x with ES6 & Webpack
MEANの初体验 - Angular 1.x with ES6 & Webpack
不要觉得这样的搭配很怪 在我想这么写之前已经有好几篇这样的教程粗线了:
- [ Angular 1.x和ES6的结合 ]
- [ Writing AngularJS Apps Using ES6 ]
- [ Using Angular 1.x With ES6 and Webpack ]
所以呐 我在写 [ PlotIt ] 的时候就是参考以上教程慢慢琢磨出来的…
Web Components
期初的前端开发思想中就已经产生分离的概念 即 结构层(HTML) / 表现层(CSS) / 行为层(JavaScript)
在前端进化之路上 开发工程师们觉得单单这样还是不够HOLD住大型项目的复杂程度
因此 分离思想进一步升级 变成了Web组件化
不知道组件化的自行谷歌或者看看 [ A Guide to Web Components ]
好了 其实 Angular 1.x with ES6 & Webpack 这样的搭配就是为了迎合 Web Components 的思想
Directive / Controller / Service / Route
目录结构
-- /components
-- /slide
-- index.html
-- index.css
-- index.js
-- /others
-- ...
-- /views
-- index.html
-- ...
-- ...
-- main.js
-- main.service.js
-- main.route.js
传统的 Angular (最常用的)基础结构由 Directive / Controller / Service / Route 组成
组件内部 index.js
将会包含该组件的 Directive(模板 + 组件交互) 和 Controller(组件方法)
那么 公用的 Service 和 Route 会集中起来分别写在 main.service.js
和 main.route.js
中
- Service 存放公用方法
- Route 将配置路由 导入
/views
内的模板
最后由 main.js
作为入口 由 Webpack 进行组织所有依赖打包成 bundle.js
Component
Directive
Directive 包含了两部分 [ 加载 template ] 和 [ 组件初始化配置&组件间交互处理 ]
-
template
加载 html 文件html 中可以写一些 ng指令 调用内部属性和方法
另外 html 中也可以获取到其他组件
在使用时可直接 用组件中
controllerAs: 'name'
定义的name
调用其组件 -
link (scope, element, attrs)
初始化&交互方法- scope
此 scope 非 $scope
scope 传入的其实是当前整个 angular app 的作用域 在里面可以获取到当前所有组件的属性和方法
所以适合写组件间的交互
- element
传入当前组件的 DOM 节点 可以添加一些监听事件
但建议 一般情况下直接在 html 写 ng 指令比较好
- attrs
组件调用时传入的 attr 可用来初始化一些配置需求
- $watch
获取或者监听组件属性的时候会使用到 $watch
建议写在
link
中 而不是在Controller
里坑点就是 $watch 方法是挂在 $scope 上面的
而每个组件的 $scope 都需要 $inject ( Controller 部分会写 )
避开此坑的方法如下:
–
// 导入组件模板 html
import template from './index.html';
// 导入组件样式 css
import './index.css';
// Slide Directive
let slideTpl = () => {
return {
template: template,
controller: 'slideCtrl',
controllerAs: 'slide',
bindToController: true,
restrict: 'E',
link: (scope, element, attrs) => {
// watch something
var self = scope.slide;
$scope = self.$scope;
$scope.$watch('attr', self.doSomething);
// do other things..
}
}
};
Controller
在 ES6 的书写格式里 所有 angular 自带的模块方法和属性 都需要通过 $inject
的方式注入到 Controller 里
注意按需注入 以下只是举例…
class slideCtrl {
constructor($scope, $location, $route, $http, $rootScope, Service) {
// angular 自带方法
this.$scope = $scope;
this.$location = $location;
this.$route = $route;
this.$rootScope = $rootScope;
this.$http = $http;
// 自行注册的 Service
this.Service = Service;
...
}
innerFunction() {
}
}
slideCtrl.$inject = ['$scope', '$location', '$http', '$route', '$rootScope', 'Service'];
Export
最后 组件是包含 tpl 和 controller 两部分作为输出
其实 两部分分开成独立文件再输出也是可以的 只不过为了方便简洁 都放在了 index.js
里
export default {
tpl: slideTpl,
controller: slideCtrl
};
Service
抽出公用方法放入 Service 中 调用方法 详见 index.js
中的 Controller 和 main.js
export default class Service {
constructor($http) {
this.$http = $http;
// ...
}
}
// whatever you need, just inject
Service.$inject = ['$http'];
Route
需要依赖安装 angular-route
& angular-ui-router
做这一步其实是为了构建 [ SPA ] 即根据路由的不同 局部刷新页面 而不用整个页面做刷新
详细使用方法在此 [ 学习 ui-router - 状态嵌套和视图嵌套 ]
routing.$inject = ['$stateProvider', '$urlRouterProvider', '$locationProvider'];
export default function routing($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.html5Mode(true);
// config HOME url
$urlRouterProvider.when('', '/home');
$urlRouterProvider.when('/', '/home');
// config other url
$urlRouterProvider.when('/other', '/other');
// config state
$stateProvider
.state('state', {
url: '/home',
template: require('./views/index.html')
})
.state('otherState', {
url: '/other',
template: require('./views/other.html')
});
}
views/
-
index.html
主页入口 在 Main 中介绍
-
other.html
相当于局部页面 是直接作为模块加入到 index.html 中的
可直接按需加载 directive 标签 如
<slide></slide>
Main
index.html
<!DOCTYPE html>
<!-- 加载 angular -->
<html ng-app="app" lang="zh-Has">
<head>
...
</head>
<body>
<!-- ui-view 由 main.route.js 配置 -->
<div ui-view></div>
<!-- Webpack 将所有依赖打包成 bundle.js -->
<script src="scripts/bundle.js"></script>
</body>
</html>
main.js
Webpack 主入口
将 Directive / Controller / Service / Route 集成起来组成 app
导入当前目录下的 js 文件 需要写成 ‘./’ + 文件名
否则 webpack 会首先去 node_modules 下查找
// import from npm
import angular from 'angular';
import uiRouter from 'angular-ui-router';
import ngRoute from 'angular-route';
// import from local file
import Route from './main.route';
import Service from './main.service';
// import main css
import '../somewhere/main.css';
// import component
import slide from './components/slide';
import others from './components/others';
// config angualr module info
const MODULE_NAME = 'app';
const app = angular.module(MODULE_NAME, [uiRouter, ngRoute]);
// add route
app.config(Route);
// add service
app.service('Service', Service);
// add directive
app
.directive('slide', slide.tpl),
.directive('others', others.tpl);
// add controller
app
.controller('slideCtrl', slide.controller)
.controller('othersCtrl', others.controller);
// final export
export default MODULE_NAME;
END
Angular 1.x with ES6 & Webpack 大致已经记录完毕 ~
ES6 可以看看 [ ES6 Study Notes ]
Webpack 可以看看 [ Webpack 入门指迷 ]
Webpack 和 React 是一对好基友 大多数 Webpack教程 是和 React 绑在一起写的