本文是自己学习angularJS的第一篇总结,并不是一个step by step 的教程,而是将自己学习过程中有疑惑的地方记录下来。考虑到之后的AngularJS总结也将依赖这个应用,因此本文会在前面两个章节具体的介绍应用搭建过程,在之后的总结中,将不再涉及应用搭建的内容。
路由是前端构建单页面应用(SPA)必不可少的一部分。AngularJS中有两种路由实现,一个是内置的ngRouter,还有一个是基于 ngRoute 开发的第三方路由模块uiRouter。考虑到目前主要使用的是功能更强大uiRouter模块,因此本文将主要介绍uiRouter的使用。
需要注意的是,AngularJS1.2以后做了模块化的处理,也就是路由没有包含在Angular.js这个文件里面,而是把它独立出来成了一个模块。也就是说,不管是 使用ngRouter还是uiRouter,都需要单独引入模块文件。ngRouter对应的外部 js文件是 angular-route.js,uiRouter对应的外部文件是angular-ui-router.js。引入模块的方式有两种,一种是直接在index.html中中引入文件模块文件,这种方式比较简单便捷,甚至可以不用单独下载,直接引入cdn地址,如下:
这里的地址是分别从不同的地方找过来的,有出入可以在网上查查
还有一种方式是使用npm包管理器安装依赖。为了响应前端工程化开发,这里使用npm包管理器安装依赖,考虑到有些同学坑没有接触了模块化,详细的介绍以下npm配合webpack搭建前端应用的过程。
新建应用
创建一个项目并安装依赖。
- 利用npm 初始化一个项目。
mkdir routerStart
cd routerStart
npm init
- 安装依赖
查看angular 版本: npm view angular version
根据查出来的版本进行安装
安装angular :npm install --save [email protected]
安装angular-route:npm install --save [email protected]
安装@uirouter/angularjs:npm install --save @uirouter/[email protected]
也可以直接在这个网站查看各个包的信息:npm包管理器
启动应用
以上已经安装好了最重要的三个依赖包,但为了能够更方便便捷的进行测试,再引入一个概念:webpack。可以把webpack看作是一个组织模块的框架,它的作用是:分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。有关于webpack的详细讲解配置,webpack
接下来新建几个文件:index.html、index.js、webpack.config.js。其中index.htm作为在浏览器上展示的界面,index.js是index.html中用到的脚本,webpack.config.js是webpack的配置文件,各个文件的内容如下:
//package.json配置文件
{
"name": "routerstart",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack"
},
"author": "spilledyear",
"license": "ISC",
"dependencies": {
"angular": "^1.6.6",
"angular-route": "^1.6.6",
"@uirouter/angularjs": "^1.0.10",
"webpack": "^3.8.1"
}
}
//webpack.config.js
module.exports = {
entry: './index.js',
output: {
filename: './bundle.js',
},
module: {
rules: [{
// test: /\.less$/,
// use: [{
// loader: "style-loader" // creates style nodes from JS strings
// }, {
// loader: "css-loader" // translates CSS into CommonJS
// }, {
// loader: "less-loader" // compiles Less to CSS
// }]
}]
}
};
//index.js
import angular from 'angular';
import ngRoute from 'angular-route';
import uiRouter from '@uirouter/angularjs';
var app = angular.module("app", [])
.controller("appCtrl",function($scope){
$scope.name = "hello!";
});
index.html
test
{{name}}
需要注意index.html中的这部分内容
并没有直接引用index.js文件,而是引入了bundle.js文件?这里会让人产生疑惑,为什不引入index.js文件?bundle.js文件从哪里来?这也是前端模块化工程与非模块化工程的主要区别,在非模块化工程中,习惯性的将所有依赖的js框架引入到html界面,这种做法造成的后果就是项目结构组织混乱、文件依赖关系错综复杂,代码功底不够还会让各种全局满天飞。模块化很好的解决了这些问题,想知道模块化更具体的细节,请自行google。而这里引入的bundle.js文件,其实和webpack有关,如果此时没有利用webpack做任何事情,仅仅是用浏览器打开index.html文件,那么肯定是可以在控制台看到报错信息的,此时的bundle.js文件是不存在的。在webpack的配置文件中,有这么一段内容:
entry: './index.js',
output: {
filename: './bundle.js',
},
根据字面的意思,应该可以猜到这段代码的用意,事实也是如此,entry和output是webpack中的两个概念,entry作为整个应用的入口文件,webpack会找到入口文件,然后根据这个文件里面的内容依次加载其它依赖的模块,然后进行编译等操作,最后将所有编译后结果输出到output 配置的输出文件中,文中配置的是bundle.js,这就是为什么只需要在index.html引入bundle.js的原因。如果你有仔细观察bundle.js文件的话,会发现这个文件很大(最少有1M),这就很好的说明了它是编译后的产物。
还有一个需要注意的地方是package.json文件
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack"
},
在scripts脚本中配置了start命令,大概就是说在执行npm start的时候相当于执行了 webpack命令。具体的细节还请参照这篇文章:webpack
接下来是启动过程
在命令行以下执行
npm start
如果一切正常,会在命令行下得到以下信息
image.png
这时候再观察应用目录结构,会发现根目录下多了一个bundle.js文件,此时完全可以把 npm start 当作是一个编译过程。
准备工作完毕,直接在浏览器下打开index.html文件,运行结果正常
image.png
如果模块化工程开发过程是这样的,那也太麻烦了吧。可能这样吗?不存在的。想使用更强大的功能,只需要修改webpack配置文件就可以了,比如开发中最期待的热部署。考虑到之后的许多AngularJS特性都需要利用这个应用来测试,在此贴出webpack比较全面的配置文件(以后可能还会添加),想了解详情请跳转上文中提到的链接
//webpack.congfigjs
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './app/index.js',
output: {
path: __dirname + "/dist",
filename: "app.js"
},
devtool: 'eval-source-map',
devServer: {
port: 9000, //端口
contentBase: "./app", //本地服务器所加载的页面所在的目录
historyApiFallback: true, //不跳转
inline: true //实时刷新
},
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: "babel-loader"
},
exclude: /node_modules/
},
{
test: /\.less$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader", // translates CSS into CommonJS
options: {
modules: true
}
}, {
loader: "less-loader" // compiles Less to CSS
}]
}]
},
plugins: [
//new 一个这个插件的实例,并传入相关的参数
new webpack.BannerPlugin('版权所有,翻版必究'),
new HtmlWebpackPlugin({
template: __dirname + "/app/index.tmpl.html"
})
],
};
同时,应用的目录结构也做了相应的调整,如下:
image.png
app目录下存放的是源文件,dist下是编译后的输出文件。其它几个配置文件的配置信息如下:
//.babelrc
{
"presets": ["es2015", "stage-0"] //babelr支持的模块
}
//package.json
{
"name": "routerstart",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server --open",
"webpack": "webpack"
},
"author": "spilledyear",
"license": "ISC",
"dependencies": {
"angular": "^1.6.6",
"angular-route": "^1.6.6",
"@uirouter/angularjs": "^1.0.10",
"bootstrap": "^3.3.7"
},
},
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"html-webpack-plugin": "^2.30.1",
"webpack": "^3.8.1",
"webpack-dev-server": "^2.9.3"
}
}
工作完毕,命令行下直接执行以下命令
npm start
浏览器自动打开,结果和刚才的一样,同时,修改源代码,浏览器也会即时刷新。
注意,虽然应用运行正常,但是这里还有些问题。从package.json可以看出目前配置了两个命令,一个是 npm start,另一个是 npm run webpack。其中npm run webpack 完全是用来打包的, npm start 配置的是webpacke-dev,是为了方便调试。但是angularJS开发和react开发是有不同的,这里也没有用JSX语法,这就意味着需要将angularJS中的一些html文件搬到编译后的目录(dist),可能需要用gulp,为了不再增加应用的复杂性,这里不再引入gulp相关内容。因此,再之后的开发过程中,不需要考虑 npm run webpack 这个命令。如果需要打包,可能需要将app目录下的一些文件手动拷贝到dist目录下。
uiRouter
uiRouter是基于 ngRoute 开发的第三方路由模块,功能比ngRoute 强大,使用方式也比较简答,因此先介绍uiRouter。当然,最好的文档还是官方文档:ui-router ,例如:
image.png
uiRouter的首页就详细的介绍了与ngRoute的关系以及使用方式。通过api文档API可以发现,uiRouter 中存在这么几个概念 。
image.png
接下来介绍使用最多的几个。
模块
ui.router
服务
stateProvider
指令
ui-sref
ui-view
首先需要明白“state” 是路由中非常重要的一个概念,在使用过程中,可以为每个state分配所对应的模块(界面),当需要改变界面时,只需要找到对应界面(模板)的那个state,最后uiRouter将模板加载到模板容器(ui-view),用户就可以在界面看到想要的效果。
location服务的作用。用官方的一段原话:
location. When urlRouterProvider is used behind the scenes anytime you specify a url in a state configuration. All urls are compiled into a UrlMatcher object (see location发生改变的时候,
urlRouterProvider。
location以反映当前状态。
ui-sref指令
Equivalent to href or ng-href in elements except the target value is a state name. Adds an appropriate href to the element according to the state associated URL.
可以作用在标签上,它指是一个 state 对应的值。当点击链接的时候,就会找到state对应的URL,进而导航到对应的URl。
ui-view指令
Renders views defined in the current state. Essentially ui-view directives are (optionally named) placeholders that gets filled with views defined in the current state.
可以看作时一个界面的容器。通过路由加载的界面,都必须放到一个或者多哥ui-view容器中。它最主要的作用是呈现当前状态下定义的视图,也就意味着如果没有定义ui-view,当前state对应的视图就没办法展现,在界面上就看不到任何效果。
接下来通过一个实例来讲解uiRouter的使用方式。
//index.js
import angular from 'angular';
import ngRoute from 'angular-route';
import uiRouter from '@uirouter/angularjs';
var app = angular.module("app", [uiRouter])
.config(["$stateProvider", "$urlRouterProvider",
function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state("app", {
url: "/",
templateUrl: "index.html"
})
.state("page01", {
url: "/page01",
templateUrl: "template/page01.html"
})
.state("page02", {
url: "/page02",
templateUrl: "template/page02.html"
})
.state("page03", {
url: "/page03",
templateUrl: "template/page03.html"
})
}
])
.controller("appCtrl",function($scope, $state){
$scope.name = "hello!";
$scope.goPage = function(){
$state.go('page03');
}
});
//index.html
test