金沙棋牌官方平台

当前位置:金沙棋牌 > 金沙棋牌官方平台 > ThinkPHP实例教程,技术栈开发web应用

ThinkPHP实例教程,技术栈开发web应用

来源:http://www.logblo.com 作者:金沙棋牌 时间:2019-11-09 19:48

用“MEAN”技术栈开发web应用(一)AngularJs前端架构

2015/09/09 · CSS, HTML5, JavaScript · 1 评论 · MEAN

原文出处: 吕大豹   

angular路由

总体思路

首先给大家介绍angular-ui-router的基本用法。

前言

不知何时突然冒出“MEAN技术栈”这个新词,听起来很牛逼的样子,其实就是我们已经熟悉了的近两年在前端比较流行的技术,mongodb、express、angularjs、nodejs,由于这几项技术涵盖了从前端到后端再到数据库,可以用他们完整的开发一个web应用了,所以成了一个非常牛逼的组合,颇有当年LAMP的气势。前端要从切图仔迈向全栈的路上,这几门技术必须得有所涉猎。本系列文章利用自己虚构的一个小项目为例,对“使用MEAN技术栈开发web应用”做一个入门级的介绍。

北京小课堂

分享人:吴昊杰

目录

1.背景介绍

2.知识剖析

3.常见问题

4.解决方案

5.编码实战

6.拓展思考

7.参考文献

8.更多讨论

thinkphp通过 style="color: #ff0000;">RESTful方式提供数据给angular,前端(包括模板页面)全部由angular来接管。

如何引用依赖angular-ui-router

AngularJs的争议

angular,简称ng,是google出品的优秀框架,在2013~2014年大红大紫,但是国内好像慢一拍,我从2015年才看到使用ng的项目大量出现。ng自出现伊始就有人诟病太难上手了,完全不同的开发方式,团队开发更是不知道如何组织代码。不过随着jquery这位老大哥逐渐被抛弃,大家开始慢慢接受mvvm这样的编程思维。然而一个不好的消息是,ng团队打算重构的angular2.0版本要发生重大变革,与1.0不能同日而语,虽然官方有1.0向2.0迁移的方案,但额外的工作总是不太好的,而且使用2.0还要付出更多的学习成本。

再加上今年又有react这个实力派雄起,ng的风头顿时被抢过去了,人们又开始研究react下的编程方式。不过我估计react的真正实用也得等到一两年后。眼下angular1.x也仍然是一个不错的选择。尽管有2.0的变革,但是1.4还是一个稳定版本,我们使用稳定版本肯定是不会有问题的。

所以我的结论是,但用无妨,不会存在白学了这种事情,就算将来angular1.x废弃了,你学到的编程思维还是在的。

本文讨论如何使用AngularJs进行前端的架构,对于ng的基础知识不做讲解,需要了解的同学可以看我之前写过的一个系列

1.背景介绍

一般来说,我们认为AngularJS是一套前端的MVC框架。那么,为了实现视图的中转,肯定会涉及到路由的概念。这里我们就来说说有关AngularJS的路由——ngRoute。

首先谈谈APP应用。平时我们用的app总是多页面,如果用原生安卓或者苹果,那当然很流畅啦。但是当我们用一般的html页面做移动端,简单时候我们可以用这样的标签去链接页面时,速度还是可以的。   但是当我们的应用越来越多时,切换起来没那么流畅。又是碍于网速,页面加载进来有点慢。但是在angular里面,我们可以用路由进行切换。因为在angular里面,我们用户一般在加载这样的应用时,会整个的缓存在手机上。我们用路由进行切换时,不用再发起HTTP请求了。体验比原来好。

示例

angular.module('app',["ui.router"])
.config(function($stateProvider){
$stateProvider.state(stateName, stateCofig);
}) 

练手项目简介

为了系统的学习“MEAN”技术栈,我虚构了一个小项目,先做一个介绍。

QuestionMaker,是一个用于生成调查问卷的系统,用户可以编辑试题(选择题、填空题),并可以实时预览编辑结果。然后还可以编辑一份试卷,为试卷添加试题,然后保存为一分完整的调查问卷。有点类似于调查派。先上一张截图吧:

图片 1

项目的功能主要是CRUD操作,所以非常适合angular的应用场景,双向绑定对于实现实时预览这样的功能简直是信手拈来。

项目的前后端是完全分离的,后端不渲染页面,只提供数据接口,前端使用ng的动态模板来渲染页面,通过ajax请求来获取所需数据。

项目我已经开源到github,有兴趣的同学可以查看:

2.知识剖析

ngRoute是一个AngularJS的模块。其不是在AngularJS的核心库当中。

            在使用ngRoute的时候,实际上,我们是在应用的主模块中引入ngRoute模块并添加$routeProvider服务到主模块的config方法中来达到我们的目标。这与其他一些库的使用方式是类似的,如ng-grid。

            在ngRoute中,主要有$route、$routeProvider、$routeParams三个服务项目。

            $routeProvider用于在主应用主模块的配置方法中。$route与$routeParams一般常见于控制器中。

服务$routeProvider用来定义一个路由表,即地址栏与视图模板的映射

服务$routeParams保存了地址栏中的参数

服务$location用来实现用于获取当前url以及改变当前的url,并且存入历史记录

服务$route完成路由匹配,并且提供路由相关的属性访问及事件,如访问当前路由对应的controller

指令ngView用来在主视图中指定加载子视图的区域

angular路由可以实现多视图的单页Web应用。 当请求一个url时,根据路由配置匹配这个url,然后请求模板片段,并插入到ng-view中去。这种做法使网页局部刷新,减少了切换网页时带来的突兀感, 也减少了项目的代码量。

实现一个用户管理模块,走通增删改查4个操作,通过该示例,演示如何在thinkphp中使用AngularJS。

$stateProvider.state(stateName, stateConfig)

前端目录结构

用ng来构建一个项目应该如何安排目录结构呢?为了不人工增加复杂度,我这里没有用bower来管理依赖库,也没有其他文章中介绍的那样用yeoman来生成项目,只是单纯的手动来创建目录,这样可以把我们的注意力集中到项目的核心上,目录结构是这样的:

前端的代码都在src目录下,包括入口文件index.html,这样方便我们后续做合并压缩等编译工作,编译后的文件可以一并放入dist目录下。

3.常见问题

ngRoute实现原理和如何使用路由?

一. 准备工作

stateName是string类型
stateConfig是object类型
//statConfig可以为空对象
$stateProvider.state("home",{});
//state可以有子父级
$stateProvider.state("home",{});
$stateProvider.state("home.child",{})
//state可以是链式的
$stateProvider.state("home",{}).state("about",{}).state("photos",{});

首页index.html

这是项目的入口页面,其实就是一个大容器,在这里加载所有的js和css文件,然后提供一个视图容器就够了,因为从这个页面以后,我们页面就不再会有跳转,全部是通过前端路由来做局部刷新,首页的代码非常精简:

JavaScript

<!doctype html> <html ng-app="QMaker"> <head> <meta charset="utf-8"> <title>Question Maker</title> <link rel="stylesheet" href="/src/lib/bootstrap-3.3.5/css/bootstrap.min.css"> <script src="/src/lib/jquery-1.9.1.min.js"></script> <script src="/src/lib/angular-1.4.1.min.js"></script> <script src="/src/lib/angular-ui-router.min.js"></script> <link rel="stylesheet" href="/src/css/base.css"> <!--{main}--> <script src="/src/js/app.js"></script> <script src="/src/js/controllers.js"></script> <script src="/src/js/directives.js"></script> <script src="/src/js/filters.js"></script> <script src="/src/js/routes.js"></script> <script src="/src/js/services.js"></script> <!--{endmain}--> </head> <body> <div class="navbar navbar-default"> <div class="container-fluid"> <div class="navbar-header"> <a href="#/" class="navbar-brand">Question Maker</a> </div> </div> </div> <div class="maincontent container-fluid" ui-view> </div> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!doctype html>
<html ng-app="QMaker">
<head>
    <meta charset="utf-8">
    <title>Question Maker</title>
    <link rel="stylesheet" href="/src/lib/bootstrap-3.3.5/css/bootstrap.min.css">
    <script src="/src/lib/jquery-1.9.1.min.js"></script>
    <script src="/src/lib/angular-1.4.1.min.js"></script>
    <script src="/src/lib/angular-ui-router.min.js"></script>
 
    <link rel="stylesheet" href="/src/css/base.css">
    <!--{main}-->
    <script src="/src/js/app.js"></script>
    <script src="/src/js/controllers.js"></script>
    <script src="/src/js/directives.js"></script>
    <script src="/src/js/filters.js"></script>
    <script src="/src/js/routes.js"></script>
    <script src="/src/js/services.js"></script>
    <!--{endmain}-->
</head>
 
<body>
    <div class="navbar navbar-default">
        <div class="container-fluid">
            <div class="navbar-header">
                <a href="#/" class="navbar-brand">Question Maker</a>
            </div>
        </div>
    </div>
    <div class="maincontent container-fluid" ui-view>
 
    </div>
</body>
 
</html>

ngRoute实现原理

我们知道,设置

<ahref="#div1">div1</a>

            <ahref="#div2">div2</a>

            <ahref="#div3">div3</a>

        <divid="div1">我是div1</div>

            <divid="div2">我是div2</div>

            <divid="div3">我是div3</div>

这样的锚点,a链接会在同一页面中跳转。ngRoute利用了这一特性将锚点出的文件设置为模板,在锚点被链接时,监听到url的变化,加载相应的模板文件。

1. 加载所需的js和css文件

angular.min.js angular    核心库文件

angular-ui-router.min.js angular    路由插件

angular-resource.min.js    负责与服务端restful交互的插件

layer    弹窗插件,该插件依赖于jQuery-1.10.1.min.js和jquery-ui.min.js两个库文件以及一个jquery-ui.min.css样式表

bootstrap.min.css bootstrap    核心样式表

文件结构如下:

图片 2

2. 引导页

准备一个angular引导页,angular通过该引导页开启一个angular应用,后续所有的操作,都是基于该引导页进行的。

友情提醒:

这里的引导页,其实就是我们应用的默认页面,具体到thinkphp中,指的就是DEFAULT_MODULE/DEFAULT_CONTROLLER/DEFAULT_ACTION对应的模板文件。第一次访问应用时,thinkphp控制器会定向到该页面,之后的模板页面,全部由angular接管,跟thinkphp的模板引擎就没有半点关系了。

3. 应用首页

在引导页中通过<div ui-view="main"></div>包含我们的应用首页。便签的含义后面会有解释。

注意:这一步不是必须的,因为你也可以把应用首页的内容,全部放在引导页中,但是这样做就不够友好了。

4. 搭建RESTFul环境

为了能够使用$resource,我们必须让服务端按照RESTful的方式来工作,否则,$resource就无法发挥其作用了。

thinkphp中内置了对RESTful的支持,使用方式也很简单,就是让某个Controller继承自RestController,然后按照一定的规则来编写资源方法即可。但是它有一个缺点,thinkphp内置的RESTful对资源的访问方式不够友好,其访问资源的URL结构如下:

/模块名称/控制器名称/资源名称

基于此,我们考虑使用thinkphp的路由功能,来实现对RESTful的支持,使用thinkphp的路由功能时,控制器是没有必要继承RestController的,但为了尊重tp的劳动成果,同时,为了兼顾友好的资源访问方式,最终,我使用的是RestController+路由两者结合的方式。

补充:

资源方法的命名规则为:资源名称_REST类型

REST类型有如下几种:get,post,put,delete

5. 创建数据库表

创建用户表,并初始化一些数据

stateConfig包含的字段:template, templateUrl, templateProvider, controller, controllerProvider, resolve, url, params, views, abstract, onEnter, onExit, reloadOnSearch, data

入口文件app.js

有了入口页面,还得有一个js的启动入口,就是这个app.js了,在这里它只做了两件事情:

  1. 启动angular,代码只有一行:

JavaScript

var app = angular.module('QMaker', ['ui.router']);

1
var app = angular.module('QMaker', ['ui.router']);

我们拥有了一个名为app的全局模块。这里把ui.router给注入了,因为我们整个应用都用ui-router来做路由,后面会做详细介绍。

2. 把ui-router的$state和$stateParams服务挂到$rootScope上,这样我们在后面所有的模块中,都能够访问到路由参数,不必在每个地方都注入一次了。代码也是相当简单:

JavaScript

app.run(function($rootScope, $state, $stateParams) { $rootScope.$state = $state; $rootScope.$stateParams = $stateParams; });

1
2
3
4
app.run(function($rootScope, $state, $stateParams) {
    $rootScope.$state = $state;
    $rootScope.$stateParams = $stateParams;
});

4.解决方案

 

$urlRouteProvider

控制器合集controllers.js

controller.js里面是所有的controller定义,由于这个项目比较小,而且反正最后都要合并,所以就都放在一个文件里了,这样可以使用链式写法app.controller(‘a’, …).controller(‘b’, …), 一口气将所有的controller都定义好。如果项目比较大,controller多,可以把controllers建为一个文件夹,然后在里面放各个controller。

controller里面就是跟业务相关的一些代码了,如试题数据的初始化,添加答案、删除选项等操作。

但是当我们需要发起ajax请求的时候,如保存试题,就不宜在controller里面直接写了,这样会造成逻辑混杂代码混乱。所有需要请求服务端的操作,我们可以抽象为一个个服务,进行“分层”,通过ng提供的service机制来做调用。

NGROUTE包含以下部分:

服务$routeProvider用来定义一个路由表,即地址栏与视图模板的映射

服务$routeParams保存了地址栏中的参数

服务$location用来实现用于获取当前url以及改变当前的url,并且存入历史记录

服务$route完成路由匹配,并且提供路由相关的属性访问及事件,如访问当前路由对应的controller

指令ngView用来在主视图中指定加载子视图的区域

$routeProvider提供了定义路由表的服务,它有两个核心方法,when(path,route)和otherwise(params)。

[sql] view plain copy

$urlRouteProvider.when(whenPath, toPath)
$urlRouterProvider.otherwise(path)
$urlRouteProvider.rule(handler)

服务合集services.js

接上面,所有和试题相关的服务端请求,我们可以封装成一个QuestionService,这个服务提供:提交试题、删除试题、更新试题等服务,这样层次就很清晰了。

所以,在services.js中,我们定义所有和服务相关的东西,在本项目中,我们的服务全都是ajax请求,可以用ng提供的$http服务来很方便的完成。事实上service中并不是必须写ajax请求,凡是可以抽象理解为“公共服务”的东西,都可以定义在这里,可以被其他模块随意调用。

ngRoute的使用

a.引入两个文件,angular和angular-route:

                    

<script src="angular.min.js"></script>

<script src="angular-route.min.js"></script>

b.主页面中设置容器ng-view

c.然后在ng-app中注入ngRoute

d.最后配置路由表

一个简单的ngRoute结构示例

                    

<script>

        angular.module('indexApp', [ngRoute])

        .config(['$routeProvider', function($routeProvider) {

$routeProvider

                .when('/div1', {

                    template: '<p>这是div1{{text}}</p>',

                    controller: 'div1Controller'

})

                .when('/div2', {

                    template: '<p>这是div2{{text}}</p>',

                    controller: 'div2Controller'

})

                .when('/div3', {

                    template: '<p>这是div3{{text}}</p>',

                    controller: 'div3Controller'

})

                .when('/content/:id', {

                    template: '<p>这是content{{id}}</p>',

                    controller: 'div4Controller'

})

.otherwise({

                    redirectTo: '/div1'

});

}]);

    </script>

 

$state.go

指令合集directives.js

了解过ng的同学应该对指令不会陌生,通过指令我们可以用扩展html标签的方式来很容易的实现一些UI效果,使用方便、可被多个地方公共使用,就像过去我们写jquery插件一样。所有的指令都定义在这个文件中,同样可以使用链式写法,很爽。

在我们的项目中,有一些功能是通用的,例如列表的分页,那么就可以把分页功能做成一个指令。我定义了一个名为pagenav的指令,然后在所有需要用分页的地方就可以调用了,代码如下:

JavaScript

<pagenav pageobj="pageObject" pagefunc="pageFunction"></pagenav>

1
<pagenav pageobj="pageObject" pagefunc="pageFunction"></pagenav>

只需一个标签,然后通过属性指定分页数据和翻页函数即可。

5.参考文献

菜鸟教程

AngularJS路由二三事(一):ngRoute

ngRoute 模块_AngularJS中文网

  1. DROP TABLE IF EXISTS `an_user`;  
  2. CREATE TABLE `an_user` (  
  3.   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,  
  4.   `user_id` int(10) unsigned NOT NULL COMMENT '用户id',  
  5.   `user_name` varchar(100) NOT NULL COMMENT '用户名称',  
  6.   `email` varchar(255) DEFAULT NULL COMMENT '邮箱地址',  
  7.   `tel` varchar(255) DEFAULT NULL COMMENT '手机号码',  
  8.   `weixin` varchar(255) DEFAULT NULL COMMENT '微信号',  
  9.   `qq` varchar(255) DEFAULT NULL COMMENT 'qq号码',  
  10.   PRIMARY KEY (`id`)  
  11. ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户表';  
  12.   
  13. INSERT INTO `an_user` VALUES ('1', '1', 'demo1', 'demo1@qq.com', '13100000000', 'weixin_test1', '123456');  
  14. INSERT INTO `an_user` VALUES ('2', '2', 'demo2', 'demo2@qq.com', '13100000001', 'weixin_test2', '123456');  
  15. INSERT INTO `an_user` VALUES ('3', '3', 'demo3', 'demo3@qq.com', '13100000002', 'weixin_test3', '123456');  
  16. INSERT INTO `an_user` VALUES ('4', '4', 'demo4', 'demo4@qq.com', '13100000003', 'weixin_test4', '123456');  
  17. INSERT INTO `an_user` VALUES ('5', '5', 'demo5', 'demo5@qq.com', '13100000004', 'weixin_test5', '123456');  
  18. INSERT INTO `an_user` VALUES ('6', '6', 'demo6', 'demo6@qq.com', '13100000005', 'weixin_test6', '123456');  
  19. INSERT INTO `an_user` VALUES ('7', '7', 'demo7', 'demo7@qq.com', '13100000006', 'weixin_test7', '123456');  
  20. INSERT INTO `an_user` VALUES ('8', '8', 'demo8', 'demo8@qq.com', '13100000007', 'weixin_test8', '123456');  
  21. INSERT INTO `an_user` VALUES ('9', '9', 'demo9', 'demo9@qq.com', '13100000008', 'weixin_test9', '123456');  

$state.go(to, [,toParams],[,options])
形参to是string类型,必须,使用"^"或"."表示相对路径;
形参toParams可空,类型是对象;
形参options可空,类型是对象,字段包括:location为bool类型默认true,inherit为bool类型默认true, relative为对象默认$state.$current,notify为bool类型默认为true, reload为bool类型默认为false

过滤器合集filters.js

我们的项目使用ng提供的动态模板,服务端不渲染页面,只提供数据接口。有些数据我们需要进行格式化后进行输出,这就用到filter了,所有的filter都放在这里。filter的定义和使用的非常简单,此不不多述了。

6.更多讨论

为什么推荐用ui-router替代ngRoute

ngRoute在路由配置时用$routeProvider。

ui-router路由配置时用 $stateProvider 和$urlRouterProvider。

ngRoute是官方路由。

ui-route是第三方路由。

ngroute是用AngularJS框架的核心部分。

ui-router是一个社区库,它是用来提高完善ngroute路由功能的。

ui-router允许嵌套视图(nested views)和多个命名视图(multiple named views)。

二. 开始吧

$state.go('photos.detail')
$state.go('^')到上一级,比如从photo.detail到photo
$state.go('^.list')到相邻state,比如从photo.detail到photo.list
$state.go('^.detail.comment')到孙子级state,比如从photo.detail到photo.detial.comment

前端路由定义routes.js

本项目使用ui-router来做前端路由,这个目测也是现在最流行的做法。ui-router是一个第三方插件,由于ng内置的ngRouter功能较弱,无法实现嵌套路由和多视图路由,而ui-router引入了“状态”这个概念来控制视图,从而实现这些功能,所以ui-router成了最好的选择。它是angular-ui项目()中的一个模块,该项目还提供了很多基于ng的ui,像日期选择器什么的。ui-router貌似是最受欢迎的一个。

用ui-router可以实现嵌套路由和同一页面多视图,具体使用方法可以参考我博客中转载的几篇文章:

本项目中,由于整站无刷新,所以路径的层级会比较深,嵌套路由就派上了用场。在入口页面index.html中,用一个div来做父容器,加上ui-view属性,就可以在里面加载别的模板了。从试题列表到试题编辑页面的切换,就都在这个父容器中加载。

而在试题编辑页面,又有对应的题型编辑和试题预览视图,通过给ui-view赋予名字,就可以加载各自对应的模板,这里就是多视图的应用。代码片段如下:

JavaScript

<!--试题编辑视图--> <div ui-view="editArea"></div> <!--试题预览视图--> <div ui-view="previewArea"></div>

1
2
3
4
5
<!--试题编辑视图-->
<div ui-view="editArea"></div>
 
<!--试题预览视图-->
<div ui-view="previewArea"></div>

在试卷预览页面,我们也需要对试题进行展示,只需在页面上在定义一个ui-view,然后在路由中进行配置,就可以加载试题预览模版,很容易的实现了模板的复用。

页面中没有任何逻辑,只需在route.js中配置好路由规则,整站无刷新跳转就这么轻而易举的实现了。

问题一: 为什么ui-router可以嵌套路由而ng-router不能嵌套路由

 

ui-sref

tpl目录

利用ui-router做了前端路由后,除了入口页面index.html外,其他所有页面就都变成模板了(被ui-router动态加载)。所有的模板都放在tpl目录下。如果业务的模块较多,可以在此目录下再新建文件夹,本项目比较简单,所以就只有一层。不论有多少层目录,在routers.js中配置好就OK啦。利用ui-router可以注入模板对应的控制器,所以代码中我们也不必在加ng-controller,模板文件中就是很干净的ng模板。

答:因为ng-router没有明确的父子层级关系,ui-router明确了这一点

1. 创建引导页

前面说过,引导页其实就是我们应用的默认页面,在我的项目中,默认页面的文件路径为:

/tpl/Admin/Index/index.html

在该文件中,加入如下内容:

ui-sref='stateName'
ui-sref='stateName({param:value, param:value})'

lib目录

这里放置的是项目所需的外部库。有angular、ui-router、jquery、bootstrap。你可以看到我只是把代码文件给直接放里面了,没有用当下流行的bower进行管理。是因为我不想再人为的增加复杂度,万一有人的机器上bower安装失败或者git环境有问题,或者github无法访问,都会令人十分沮丧。

反正就这几个稳定版本,不如直接下载过来。如果需要压缩我后期用gulp来搞一下就行了。

问题二:不同页面之间如何传参?

.controller('pageOneCtrl', function ($scope, $state) {

              $scope.toPage2 = function (id) {

                $state.go('page2', {ID:id});

            };

            //接收页面:

            .controller('pageTwoCtrl’, function ($scope, $state, $stateParams) {

              var receivedId = $stateParams.ID;

              console.log(receivedId);

            //打印的结果即为id

            });

可以通过点击事件进行传参

html中:

ng-click=“toPage2(name,number)”

控制器中:

  .controller('pageOneCtrl', function ($scope, $state) {

$scope.toPage2 = function (name,number) {

$state.go('page2', {

args:{

  NAME:name,

  NUMBER:number

  });

};

});

在第二个页面中通过$staeParams获得参数ID。

            .controller('pageTwoCtrl’, function ($scope, $state, $stateParams) {

  var receivedName = $stateParams.args.NAME;

  var receivedNumber = $stateParams.args.NUMBER;

});

 

ui-view

总结

这个小项目的前端结构就是这个样子啦。从上面我们可以看出,用ng来做前端的架构还是很有条理的。controller、service、directive这些概念,本质上还是“模块”,所以我们可以以模块开发的方式来很爽快的写代码,文件与文件之间没有任何耦合和依赖。模块所需的依赖,我们通过ng的注入机制来给注入。所以在index.html中引入这些文件的时候,没有顺序要求,任意顺序引入皆可。

顺便说一句,前端代码的后处理,我已经用gulp写好了脚本,用npm安装所需的包后,执行gulp就可以编译生成dist目录。

本文只做angular前端架构入门级别的介绍,关于文中提到的一些具体技术细节,可以查看我写的angular系列文章

这个示例项目我已开源到github(),目前已经实现了基本功能。后续我会扩展更多的功能,到时候也必然会涉及到更多的技术问题,angular进行前端架构的路才刚刚开始。

1 赞 1 收藏 1 评论

图片 3

问题三:paramr是做什么用的

params是路由之中页面的参数传递方式.

this.$router.push({

 path:"/detail",

 params:{

 name:'nameValue',

 code:10011

 }

});

腾讯视频链接:

PPT链接:

[html] view plain copy

==没有名称的ui-view

鸣谢

感谢大家观看

BY :  李仁 | 吴昊杰

angular路由

小课堂

        分享人: 吴昊杰

 

<div ui-view></div>
$stateProvider.state("home",{
template: "<h1>hi</h1>"
}) 
  1. <!DOCTYPE html>  
  2. <html ng-app="antp">  
  3.     <head>  
  4.         <meta charset="utf-8" />  
  5.         <title></title>  
  6.         <meta content="width=device-width, initial-scale=1.0" name="viewport" />  
  7.         <meta content="" name="author" />  
  8.         <link href="/public/css/bootstrap.min.css" rel="stylesheet" type="text/css" media="all">  
  9.         <link href="/public/css/jquery-ui.min.css" rel="stylesheet" type="text/css" media="all">  
  10.         <script type="text/javascript" src="/public/js/angular.min.js"></script>  
  11.         <script type="text/javascript" src="/public/js/angular-resource.min.js"></script>  
  12.         <script type="text/javascript" src="/public/js/angular-ui-router.min.js"></script>  
  13.         <script type="text/javascript" src="/public/js/jquery-1.10.1.min.js"></script>  
  14.         <script type="text/javascript" src="/public/js/jquery-ui.min.js"></script>  
  15.         <script type="text/javascript" src="/public/js/layer/layer.js"></script>  
  16.         <script type="text/javascript" src="/config.js"></script>  
  17.         <script type="text/javascript" src="/app.js"></script>  
  18.         <link rel="shortcut icon" href="favicon.ico" />  
  19.     </head>  
  20.     <body>  
  21.         <div class="container-fluid">  
  22.             <div class="row clearfix">  
  23.                 <div class="col-md-12" style="float: none;display: block;margin-left: auto;margin-right: auto;">  
  24.                     <div ui-view="main"></div>  
  25.                 </div>  
  26.             </div>  
  27.         </div>  
  28.     </body>  
  29. </html>  

或者这样配置:

 

$stateProvider.state("home"{
views: {
"": {
template: "<h1>hi</h1>"
}
}
}) 

页面中加载的js和css,除了config.js和app.js,其它的在前面都已经作了说明,这两个后面也会说到。

注意html标签中的ng-app指令,该指令的内容,就是angular要开启的应用名称。

2. 开启应用

之前的index.html文件中,通过ng-app指令定义了一个应用名称,定义完之后,我们还需要开启它,开启的方式也很简单,我们需要创建一个js文件,名称为app.js,在里面先加入如下内容:

==有名称的ui-view

 

<div ui-view="main"></div>
$stateProvider.state("home",{
views: {
"main" : {
template: "<h1>hi</h1>"
}
}
}) 

 

==多个ui-view

[javascript] view plain copy

<div ui-view></div>
<div ui-view="data"></div>
$stateProvider.state("home",{
views: {
"":{template: "<h1>hi</h1>"},
"data": {template: "<div>data</div>"}
}
}) 

 

项目文件结构

  1. var app = angular.module("antp",["ui.router","ngResource"]);  

node_modules/
partials/
.....about.html
.....home.html
.....photos.html
app.js
index.html

 

创建state和view

其中,module的第二个参数,是angular的一些依赖包。

3. 配置路由

使用ui.router的路由功能,通过config预先配置好访问url、该url对应的视图模板以及控制器等信息,同样是在app.js文件中,继续加入如下内容:

app.js

 

var photoGallery = angular.module('photoGallery',["ui.router"]);
photoGallery.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home',{
url: '/home',
templateUrl: 'partials/home.html'
})
.state('photos',{
url: '/photos',
templateUrl: 'partials/photos.html'
})
.state('about',{
url: '/about',
templateUrl: 'partials/about.html'
})
}) 

[javascript] view plain copy

index.html

 

<!DOCTYPE html>
<html lang="en" ng-app="photoGallery">
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.css"/>
</head>
<body>
<h1>Welcome</h1>
<div ui-view></div>
<script src="node_modules/jquery/dist/jquery.js"></script>
<script src="node_modules/angular/angular.js"></script>
<script src="node_modules/angular-ui-router/release/angular-ui-router.js"></script>
<script src="node_modules/angular-animate/angular-animate.js"></script>
<script src="node_modules/bootstrap/dist/js/bootstrap.js"></script>
<script src="node_modules/angular-bootstrap/ui-bootstrap-tpls.js"></script>
<script src="app.js"></script>
</body>
</html> 
  1. app.config(function($stateProvider, $urlRouterProvider, $locationProvider) {  
  2.     //启用HTML5模式的路由,该模式下会去除URL中的#号  
  3.     //$locationProvider.html5Mode(true);  
  4.     //默认页面,所有请求不到的资源,都会转向到这个URL  
  5.     $urlRouterProvider.otherwise("/index");  
  6.     $stateProvider.state("user", {  
  7.         url: "/user",  
  8.         views: {  
  9.             main: {  
  10.                 templateUrl: "tpl/Admin/User/index.html",  
  11.                 controller: "UserCtroller"  
  12.             }  
  13.         }  
  14.     }).state("index", {  
  15.         url: "/index",  
  16.         views: {  
  17.             main: {  
  18.                 templateUrl: "tpl/Admin/Index/main.html",  
  19.                 controller: "MainCtroller"  
  20.             }  
  21.         }  
  22.     }).state("user-add", {  
  23.         url: "/user/add",  
  24.         views: {  
  25.             main: {  
  26.                 templateUrl: "tpl/Admin/User/add.html",  
  27.                 controller: "UserFormCtroller"  
  28.             }  
  29.         }  
  30.     }).state("user-edit", {  
  31.         url: "/user/edit/:user_id",  
  32.         views: {  
  33.             main: {  
  34.                 templateUrl: "tpl/Admin/User/add.html",  
  35.                 controller: "UserFormCtroller"  
  36.             }  
  37.         }  
  38.     });  
  39. });  

state之间的跳转

 

index.html

还记得之前引导页中的ui-view="main"吗?ui-view的名字,就是state中配置的views下面的属性名称。也许你会说,config里面配置了那么多的main,它是如何知道找的是哪个main?仔细看下代码就知道了。

注意1:控制器controller我们并没有手动写在某个页面的标签上,而是统一配置在了config里。

注意2:每个视图模板必须要对应一个控制器,并且这个控制器必须要被创建,否则,该视图将无法展示。

注意3:不要把此处的控制器和thinkphp里面的控制器搞混,事实上,他们两者之间没有任何关系。

4. 引入每个模块下的js

这里为了便于代码管理与维护,我在每个模块下面创建了一个js文件,每个模块的js完成特定的功能,这些js同样需要在app.js中被引入。

<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">



</button>
<a ui-sref="home" class="navbar-brand">Home</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>
<a ui-sref="photos">Photos</a>
</li>
<li>
<a ui-sref="about">About</a>
</li>
</ul>
</div>
</div>
</nav>
<div ui-view></div>

 

以上通过ui-sref属性完成state之间的跳转。

[javascript] view plain copy

多个view以及state嵌套

 

有时候,一个页面上可能有多个ui-view,比如:

  1. document.write('<script type="text/javascript" src="/tpl/Admin/Index/main.js"></script>');  
  2. document.write('<script type="text/javascript" src="/tpl/Admin/User/user.js"></script>');  
<div ui-view="header"></div>
<div ui-view="body"></div>

 

假设,以上页面属于一个名称为parent的state中。

5. 浏览器访问

在浏览器地址栏中,输入

图片 4

仔细观察下地址栏,我们输入的是

首页,引导页中的<div ui-view="main"></div>,表示我需要路由到main这个视图,但是,我们输入的地址

由于/index指向的是tpl/Admin/Index/main.html,所以此处就会把main.html对应的内容展示出来。

main.html文件内容:

我们知道在ui-router中,一个state大致是这样设置的:

 

<div ui-view="header"></div>
<div ui-view="body"></div>

 

所有state下views下的所有键值对(类似 "body@content":{templateUrl: 'partials/photos.html'})都被放到一个键值集合中。而ui-view的工作原理就是根据自己的属性值,到这个键值集合中去找匹配的键,找到就把对应的页面显示出来。

[html] view plain copy

点击header对应的页面链接,可能会跳转到另外的子页面出现在<div ui-view="body"></div>这个位置。这时候页面出现了子父关系,而每个页面都属于某个state,这样state间就出现了子父关系。这些跳转的子页面,在路由设置中,可能被称为parent.son1, parent.son2...这就是state的嵌套。

 

在现有的文件结构上增加content.html, header.html,文件结构变为:

  1. <div ng-include="'tpl/Admin/Public/header.html'"></div>  
  2. <blockquote>  
  3.     <p>  
  4.         我是默认页面,所有请求不到的资源,都会到我这里来...  
  5.     </p>  
  6. </blockquote>  

node_modules/
partials/
.....about.html
.....home.html
.....photos.html
.....content.html
.....header.html
app.js
index.html

 

content.html 包含了多各ui-view, 一个ui-view和页头相关,保持不变;令一个ui-view和会根据页头上的点击呈现不同的内容

其中,通过ng-include指令,引入了一个公共导航页面,ng-include指令中双引号内的单引号不可少,内容如下:

<div ui-view="header"></div>
<div ui-view="body"></div>

 

header.html 把原先indext.html中nav部分放到这里来

[html] view plain copy

<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">



</button>
<a ui-sref="content.home" class="navbar-brand">Home</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>
<a ui-sref="content.photos">Photos</a>
</li>
<li>
<a ui-sref="content.about">About</a>
</li>
</ul>
</div>
</div>
</nav> 

 

index.html 这时变成了这样

  1. <div style="margin-top:20px;">  
  2.     <nav class="navbar navbar-default" role="navigation">  
  3.         <div class="navbar-header">  
  4.             <a class="navbar-brand" href="#">Brand</a>  
  5.         </div>  
  6.         <div class="collapse navbar-collapse">  
  7.             <ul class="nav navbar-nav">  
  8.                 <li class="active">  
  9.                      <a ui-sref="user">用户管理</a>  
  10.                 </li>  
  11.             </ul>  
  12.               
  13.         </div>  
  14.     </nav>  
  15. </div>  

<div ui-view></div>

 

app.js 路由现在这样设置

6. 用户列表

点击导航中的【用户管理】,即可跳转到用户列表页面,如下:

图片 5

该列表对应的视图文件为tpl/Admin/User/index.html,内容如下:

var photoGallery = angular.module('photoGallery',["ui.router"]);
photoGallery.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('home');
$stateProvider
.state('content',{
url: '/',
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{templateUrl: 'partials/header.html'},
}
})
.state('content.home',{
url: 'home',
views:{
"body@content":{templateUrl: 'partials/home.html'}
}
})
.state('content.photos',{
url: 'photos',
views:{
"body@content":{templateUrl: 'partials/photos.html'}
}
})
.state('content.about',{
url:'about',
views:{
"body@content":{templateUrl: 'partials/about.html'}
}
})
}) 

 

这时候,页面是这样呈现出来的:

[html] view plain copy

→ 来到home这个路由

 

.state('content.home',{
url: 'home',
views:{
"body@content":{templateUrl: 'partials/home.html'}
}
}) 
  1. <div ng-include="'tpl/Admin/Public/header.html'"></div>  
  2. <button type="button" class="btn btn-primary" ng-click="addAction()">新增</button>  
  3. <table class="table table-bordered table-striped" style="margin-top:15px;">  
  4.     <thead>  
  5.         <tr>  
  6.             <th>用户名</th>  
  7.             <th>邮箱</th>  
  8.             <th>手机号</th>  
  9.             <th>微信</th>  
  10.             <th>QQ</th>  
  11.             <th>操作</th>  
  12.         </tr>  
  13.     </thead>  
  14.     <tbody>  
  15.         <tr ng-repeat="user in data.user">  
  16.             <td>  
  17.                 <a ui-sref="user-edit({user_id:user.user_id})" ng-bind="user.user_name"></a>  
  18.             </td>  
  19.             <td ng-bind="user.email"></td>  
  20.             <td ng-bind="user.tel"></td>  
  21.             <td ng-bind="user.weixin"></td>  
  22.             <td ng-bind="user.qq"></td>  
  23.             <td>  
  24.                 <button type="button" class="btn btn-link">  
  25.                     <a ui-sref="user-edit({user_id:user.user_id})">修改</a>  
  26.                 </button>  
  27.                 <button type="button" class="btn btn-link" ng-click="deleteAction(user.user_id)">删除</button>  
  28.             </td>  
  29.         </tr>  
  30.     </tbody>  
  31. </table>  

以上,告诉我们partials/home.html将会被加载到与"body@content"匹配的ui-view中。暂时对应的ui-view还没有出现,于是等待。

 

→ 路由看到index.html上的<div ui-view></div>

为了能够从后端拿到数据,我们需要创建一个$resource资源,创建方式如下:

.state('content',{
url: '/',
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{templateUrl: 'partials/header.html'},
}
})

 

于是,就找到了content这个state下views下的 "":{templateUrl: 'partials/content.html'}这个键值对,把partials/content.html显示出来。

[javascript] view plain copy

→ 分别加载partials/content.html页面上的各个部分

 

看到<div ui-view="header"></div>,就加载如下:

  1. //通过factory创建一个service,该service通过$resource返回了一个资源对象  
  2. //$resource负责与支持restful的服务端进行数据交互  
  3. app.factory("UserService", function($resource) {  
  4.     return $resource(globalConfig.API.URL + "users/:id", {  
  5.        id: "@id"  
  6.     },  
  7.     {  
  8.         //query方法要求服务端返回的数据格式为数组,如果返回的是非数组格式,需要在transformResponse函数中作转换处理  
  9.         query: {  
  10.             method: "GET",  
  11.             isArray: true,  
  12.             transformResponse: function(data) {  
  13.                 return JSON.parse(data);  
  14.             }  
  15.         },  
  16.         update: {  
  17.             method: "PUT"  
  18.         }  
  19.     });  
  20. });  

"header@content":{templateUrl: 'partials/header.html'},

 

看到<div ui-view="body"></div>,先加载 "body@content":{templateUrl: 'partials/home.html'}

这里,创建了一个名字为UserService的资源,然后,我们还需要创建一个控制器,将UserService资源注入进去,代码如下:

→ 点击header上的链接

 

点击<a ui-sref="content.photos">Photos</a>,来到:

[javascript] view plain copy

.state('content.photos',{
url: 'photos',
views:{
"body@content":{templateUrl: 'partials/photos.html'}
}
}) 

 

把partials/photos.html显示到<div ui-view="body"></div>中去。

  1. //用户列表Ctroller  
  2. app.controller('UserCtroller', function($scope, $state, UserService) {  
  3.     $scope.data = {};  
  4.     //获取用户列表  
  5.     UserService.query().$promise.then(  
  6.         function(data){  
  7.             //将查询结果赋值给data.user,模板中可以对data.user变量进行遍历  
  8.             $scope.data.user = data;  
  9.         },  
  10.         function(error) {  
  11.             console.log("An error occurred", error);  
  12.         }  
  13.     );  
  14.     $scope.addAction = function() {  
  15.         $state.go("user-add");  
  16.     };  
  17.     $scope.deleteAction = function(user_id){  
  18.         layer.confirm("确定要删除该用户吗", {  
  19.             btn: ['确定','取消']  
  20.         }, function(index){  
  21.             layer.close(index);  
  22.             UserService.remove({id:user_id}).$promise.then(  
  23.                 function(res){  
  24.                     if(res.status){  
  25.                         $state.go("user",null,{  
  26.                             reload:true  
  27.                         });  
  28.                     }else{  
  29.                           
  30.                     }  
  31.                 },  
  32.                 function(error) {  
  33.                     console.log("An error occurred", error);  
  34.                 }  
  35.             );  
  36.         });  
  37.     }  
  38. });  

点击<div ui-view="body"></div>,来到:

 

.state('content.about',{
url:'about',
views:{
"body@content":{templateUrl: 'partials/about.html'}
}
})

 

通过UserService的query方法,获取用户列表信息。

 

7. 新增用户

点击列表上的【新增】,将会通过$state.Go("user-add");跳转到新增页面:

图片 6

该页面对应的视图文件为tpl/Admin/User/add.html,内容如下:

把partials/about.html显示到<div ui-view="body"></div>中去。

 

state多级嵌套

[html] view plain copy

以上,在路由设置中,state名称有content, content.photos有了这样的一层嵌套。接下来,要实现state的多级嵌套。

 

在photos.html页面准备加载一个子页面,叫做photos-list.html;
与photo-list.html页面相邻的还有一个页面,叫做photo-detail.html;
在photo-detail.html页面上加载一个子页面,叫做photos-detail-comment.html;

  1. <div ng-include="'tpl/Admin/Public/header.html'"></div>  
  2. <form class="form-horizontal" role="form" name="userForm">  
  3.     <div class="form-group">  
  4.          <label class="col-sm-3 control-label">用户名</label>  
  5.          <div class="col-sm-4">  
  6.             <input type="text" class="form-control" ng-model="user.user_name"/>  
  7.          </div>  
  8.     </div>  
  9.     <div class="form-group">  
  10.          <label class="col-sm-3 control-label">邮箱</label>  
  11.          <div class="col-sm-4">  
  12.             <input type="email" class="form-control" ng-model="user.email"/>  
  13.          </div>  
  14.     </div>  
  15.     <div class="form-group">  
  16.          <label class="col-sm-3 control-label">手机号</label>  
  17.          <div class="col-sm-4">  
  18.             <input type="tel" class="form-control" ng-model="user.tel"/>  
  19.          </div>  
  20.     </div>  
  21.     <div class="form-group">  
  22.          <label class="col-sm-3 control-label">微信号</label>  
  23.          <div class="col-sm-4">  
  24.             <input type="text" class="form-control" ng-model="user.weixin"/>  
  25.          </div>  
  26.     </div>  
  27.     <div class="form-group">  
  28.          <label class="col-sm-3 control-label">QQ</label>  
  29.          <div class="col-sm-4">  
  30.             <input type="text" class="form-control" ng-model="user.qq"/>  
  31.          </div>  
  32.     </div>  
  33.     <div class="col-sm-offset-3 col-sm-4">  
  34.         <button type="submit" class="btn btn-primary" ng-click="submitAction(userForm)">  
  35.             保存  
  36.         </button>  
  37.         <button type="button" class="btn btn-default" ng-click="cancelAction()">  
  38.             返回  
  39.         </button>  
  40.     </div>  
  41. </form>  

这样,页面有了嵌套关系,state也相应的会有嵌套关系。

 

现在,文件结构变成:

 

该页面中用到了angular的ng-model指令,ng-model指令用于数据的双向绑定,注意下表单中类似于user.user_name的东西,首先,controller中会通过点号前面的user获取表单数据,表单数据就是点号后面若干个类似于user_name的对应的内容的组合。

js代码:

node_modules/
partials/
.....about.html
.....home.html
.....photos.html
.....content.html
.....header.html
.....photos-list.html
.....photo-detail.html
.....photos-detail-comment.html
app.js
index.html

 

photos.html 加一个容纳子页面的ui-view

 

photos

[html] view plain copy

<div ui-view></div>

 

如何到达这个子页面呢?修改header中的相关部分如下:

  1. //新增和修改用户Ctroller  
  2. app.controller('UserFormCtroller', function($scope, $state, $stateParams, UserService) {  
  3.     if($stateParams.user_id){  
  4.         var user_id = $stateParams.user_id;  
  5.         var param = {id:user_id};  
  6.         //获取指定用户  
  7.         UserService.get(param).$promise.then(  
  8.             function(res) {  
  9.                 $scope.user = res;  
  10.             },  
  11.             function(error) {  
  12.                 console.log("An error occurred", error);  
  13.             }  
  14.         );  
  15.     }  
  16.     $scope.submitAction = function(userForm) {  
  17.         if(!userForm.$valid){  
  18.             return false;  
  19.         }  
  20.         if($stateParams.user_id){  
  21.             //更新用户信息  
  22.             UserService.update(param,$scope.user).$promise.then(  
  23.                 function(res) {  
  24.                     if(res.status){  
  25.                         $state.go("user");  
  26.                     }else{  
  27.                           
  28.                     }  
  29.                 },  
  30.                 function(error) {  
  31.                     console.log("An error occured", error);  
  32.                 }  
  33.             );  
  34.         }else{  
  35.             //新增  
  36.             UserService.save($scope.user).$promise.then(  
  37.                 function(res) {  
  38.                     if(res.status){  
  39.                         $state.go("user");  
  40.                     }else{  
  41.                           
  42.                     }  
  43.                 },  
  44.                 function(error) {  
  45.                     console.log("An error occured", error);  
  46.                 }  
  47.             );  
  48.         }  
  49.     };  
  50.     $scope.cancelAction = function() {  
  51.         $state.go("user");  
  52.     };  
  53. });  
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">



</button>
<a ui-sref="content.home" class="navbar-brand">Home</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>
<a ui-sref="content.photos.list">Photos</a>
</li>
<li>
<a ui-sref="content.about">About</a>
</li>
</ul>
</div>
</div> 

通过UserService的save方法来新增一个用户,而update方法则负责用户信息的修改。

注意:在修改用户的信息之前,我们需要通过UserService的get方法把用户已有的信息填充到页面上。

8. 修改用户

点击列表上的【修改】链接,进入到用户修改页面:

以上,通过<a ui-sref="content.photos.list">Photos</a>来到photos.html的子页面photos-list.html.

图片 7

photos-list.html 通过2种途径到相邻页photo-detail.html

通过列表中的ui-sref="user-edit({user_id:user.user_id})"这一句,即可实现页面的跳转,同时,带上了user_id这个参数,可以在控制器中注入$stateParams来获取此处的参数,代码在前面已经贴过了。

9. 删除用户

点击列表上的【删除】,将会弹出一个删除确认的提示,如图:

图片 8

点击【确定】后,即可通过UserService的remove方法来删除该用户。

注意:删除一个资源,也可以使用delete方法,但由于delete在有些浏览器中被当成了关键字,所以使用上需要写成UserService["delete"]这种格式。

10. thinkphp路由配置

<h1>photos-list</h1>
<ul>
<li><a ui-sref="^.detail">我通过相对路径到相邻的state</a></li>
<li><a ui-sref="content.photos.detail">我通过绝对路径到相邻的state</a></li>
</ul> 

 

photo-detail.html 又提供了来到其子页面photos-detail-comment.html的ui-view

[php] view plain copy

<h1>photo-details</h1>
<a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
<div ui-view></div> 

 

photos-detail-comment.html 则很简单:

  1. 'URL_ROUTER_ON' => true  

<h1>photos-detail-comment</h1>

[php] view plain copy

app.js state多级嵌套的设置为

 

var photoGallery = angular.module('photoGallery',["ui.router"]);
photoGallery.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('home');
$stateProvider
.state('content',{
url: '/',
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{templateUrl: 'partials/header.html'},
}
})
.state('content.home',{
url: 'home',
views:{
"body@content":{templateUrl: 'partials/home.html'}
}
})
.state('content.photos',{
url: 'photos',
views:{
"body@content":{templateUrl: 'partials/photos.html'}
}
})
.state('content.photos.list',{
url: '/list',
templateUrl: 'partials/photos-list.html'
})
.state('content.photos.detail',{
url: '/detail',
templateUrl: 'partials/photos-detail.html'
})
.state('content.photos.detail.comment',{
url: '/comment',
templateUrl: 'partials/photos-detail-comment.html'
})
.state('content.about',{
url:'about',
views:{
"body@content":{templateUrl: 'partials/about.html'}
}
})
})
  1. 'URL_ROUTE_RULES' => array(  
  2.         array('api/users/:id','Admin/User/user_get','',array('method'=>'get')),  
  3.         //注意:列表记录对应的路由必须要放在单条记录路由的后面,否则无法获取单条记录  
  4.         array('api/users','Admin/User/user_get','',array('method'=>'get')),  
  5.         array('api/users','Admin/User/user_post','',array('method'=>'post')),  
  6.         array('api/users/:id','Admin/User/user_put','',array('method'=>'put')),  
  7.         array('api/users/:id','Admin/User/user_delete','',array('method'=>'delete')),  
  8.     )  

 抽象state

 

如果一个state,没有通过链接找到它,那就可以把这个state设置为abstract:true,我们把以上的content和content.photos这2个state设置为抽象。

11. 后端代码

.state('content',{
url: '/',
abstract: true,
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{templateUrl: 'partials/header.html'},
}
})
...
.state('content.photos',{
url: 'photos',
abstract: true,
views:{
"body@content":{templateUrl: 'partials/photos.html'}
}
})

 

那么,当一个state设置为抽象,如果通过ui-sref或路由导航到该state会出现什么结果呢?

[php] view plain copy

--会导航到默认路由上

 

$urlRouterProvider.otherwise('home');

  1. //查询用户列表或单条记录  
  2.     public function user_get(){  
  3.         $id = I('id');  
  4.         if ($id) {  
  5.             $where = array('user_id' => $id);  
  6.             $users = DBUtil::queryRow($this->userModel,$where);  
  7.         }else{  
  8.             $users = DBUtil::queryList($this->userModel);  
  9.         }  
  10.         $this->response($users,'json');  
  11.     }  
  12.       
  13.     //新增用户  
  14.     public function user_post(){  
  15.         $user_id = DBUtil::getMaxKey($this->userModel, 'user_id');  
  16.         //angular默认post过来的数据类型为Content-Type:application/json; charset=utf-8  
  17.         $userData = json_decode(file_get_contents('php://input'),true);  
  18.         $userData['user_id'] = $user_id;  
  19.         $result = DBUtil::add($this->userModel, $userData);  
  20.         $this->response(array('status'=>$result),'json');  
  21.     }  
  22.       
  23.     //修改用户  
  24.     public function user_put(){  
  25.         $user_id = $_REQUEST['id'];  
  26.         //angular默认post过来的数据类型为Content-Type:application/json; charset=utf-8  
  27.         $userData = json_decode(file_get_contents('php://input'),true);  
  28.         $result = DBUtil::save($this->userModel, array('user_id' => $user_id), $userData);  
  29.         if ($result !== false) {  
  30.             $result = true;  
  31.         }  
  32.         $this->response(array('status'=>$result),'json');  
  33.     }  
  34.       
  35.     //删除用户  
  36.     public function user_delete(){  
  37.         $user_id = $_REQUEST['id'];  
  38.         $result = DBUtil::delete($this->userModel, array('user_id' => $user_id));  
  39.         $this->response(array('status'=>$result),'json');  
  40.     }  

三. 去除URL中的#号

.state('content.home',{
url: 'home',
views:{
"body@content":{templateUrl: 'partials/home.html'}
}
}) 

 

最终把partials/home.html显示出来。

默认情况下,angular通过URL中的#号来识别资源路径类别,凡是带#号的资源,统一由angular调配,而不带#号的资源,由服务端调配,如果需要去除#号,可以参考以下步骤:

1. 启用HTML5模式

首页需要在config中注入$locationProvider,然后通过$locationProvider.html5Mode(true);来启用html5模式的路由。

2. 加入base标签

在引导页中加入<base href="/">

3. 后端thinkphp配置

在控制器中增加一个_empty方法,在该方法中,跳转到首页。

使用控制器

在实际项目中,数据大多从controller中来。

首先在路由中设置state所用到的控制器以及控制器别名。

var photoGallery = angular.module('photoGallery',["ui.router"]);
photoGallery.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('home');
$stateProvider
.state('content',{
url: '/',
abstract: true,
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{templateUrl: 'partials/header.html'},
}
})
.state('content.home',{
url: 'home',
views:{
"body@content":{
templateUrl: 'partials/home.html',
controller: 'HomeController',
controllerAs: 'ctrHome'
}
}
})
.state('content.photos',{
url: 'photos',
abstract: true,
views:{
"body@content":{
templateUrl: 'partials/photos.html',
controller: 'PhotoController',
controllerAs: 'ctrPhoto'
}
}
})
.state('content.photos.list',{
url: '/list',
templateUrl: 'partials/photos-list.html',
controller: "PhotoListController",
controllerAs: 'ctrPhotoList'
})
.state('content.photos.detail',{
url: '/detail',
templateUrl: 'partials/photos-detail.html',
controller: 'PhotoDetailController',
controllerAs: 'ctrPhotoDetail'
})
.state('content.photos.detail.comment',{
url: '/comment',
templateUrl: 'partials/photos-detail-comment.html'
})
.state('content.about',{
url:'about',
views:{
"body@content":{templateUrl: 'partials/about.html'}
}
})
})

添加controller.js,该文件用来定义所用到的controller.现在的文件结构为:

asserts/
.....css/
.....images/
..........image1.jpg
..........image2.jpg
..........image3.jpg
..........image4.jpg
node_modules/
partials/
.....about.html
.....home.html
.....photos.html
.....content.html
.....header.html
.....photos-list.html
.....photo-detail.html
.....photos-detail-comment.html
app.js

index.html

controllers.js

photoGallery.controller('HomeController',['$scope', '$state', function($scope, $state){
this.message = 'Welcome to the Photo Gallery';
}]);
//别名:ctrPhoto
photoGallery.controller('PhotoController',['$scope','$state', function($scope, $state){
this.photos = [
{ id: 0, title: 'Photo 1', description: 'description for photo 1', imageName: 'image1.jpg', comments:[
{name: 'user1', comment: 'Nice'},
{ name:'User2', comment:'Very good'}
]},
{ id: 1, title: 'Photo 2', description: 'description for photo 2', imageName: 'image2.jpg', comments:[
{ name: 'user2', comment: 'Nice'},
{ name:'User1', comment:'Very good'}
]},
{ id: 2, title: 'Photo 3', description: 'description for photo 3', imageName: 'image3.jpg', comments:[
{name: 'user1', comment: 'Nice'}
]},
{ id: 3, title: 'Photo 4', description: 'description for photo 4', imageName: 'image4.jpg', comments:[
{name: 'user1', comment: 'Nice'},
{ name:'User2', comment:'Very good'},
{ name:'User3', comment:'So so'}
]}
];
//给子state下controller中的photos赋值
this.pullData = function(){
$scope.$$childTail.ctrPhotoList.photos = this.photos;
}
}]);
//别名:ctrPhotoList
photoGallery.controller('PhotoListController',['$scope','$state', function($scope, $state){
this.reading = false;
this.photos = new Array();
this.init = function(){
this.reading = true;
setTimeout(function(){
$scope.$apply(function(){
$scope.ctrPhotoList.getData();
});
}, 1500);
}
this.getData = function(){
//调用父state中controller中的方法
$scope.$parent.ctrPhoto.pullData();
/*this.photos = $scope.$parent.ctrPhoto.photos;*/
this.reading = false;
}
}]);
//别名:ctrPhotoDetail
photoGallery.controller('PhotoDetailController',['$scope', '$state', function($scope,$state){
}]); 

以上,通过$scope.$$childTail.ctrPhotoList在父state中的controller中拿到子state中的controller;通过$scope.$parent.ctrPhoto在子state中的controller中拿到父state中的controller。

photos-list.html

<h1>photos-list</h1>
<div ng-init="ctrPhotoList.init()">
<div style="margin:auto; width: 40px;" ng-if="ctrPhotoList.reading">
<i class="fa fa-spinner fa-5x fa-pulse"></i>
</div>
<div class="well well-sm" ng-repeat="photo in ctrPhotoList.photos">
<div class="media">
<div class="media-left" style="width:15%;">
<a ui-sref="content.photos.detail">
<img class="img-responsive img-rounded" src="../asserts/images/{{photo.imageName}}" alt="图片 9">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">{{photo.title}}</h4>
{{photo.description}}
</div>
</div>
</div>
</div> 

state间如何传路由参数

在content.photos.detail这个state设置接收一个路由参数。

.state('content.photos.detail',{
url: '/detail/:id',
templateUrl: 'partials/photos-detail.html',
controller: 'PhotoDetailController',
controllerAs: 'ctrPhotoDetail'
}) 

photos-list.html 送出一个路由参数

<h1>photos-list</h1>
<div ng-init="ctrPhotoList.init()">
<div style="margin:auto; width: 40px;" ng-if="ctrPhotoList.reading">
<i class="fa fa-spinner fa-5x fa-pulse"></i>
</div>
<div class="well well-sm" ng-repeat="photo in ctrPhotoList.photos">
<div class="media">
<div class="media-left" style="width:15%;">
<a ui-sref="content.photos.detail({id:photo.id})">
<img class="img-responsive img-rounded" src="../asserts/images/{{photo.imageName}}" alt="图片 10">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">{{photo.title}}</h4>
{{photo.description}}
</div>
</div>
</div>
</div> 

以上,通过<a ui-sref="content.photos.detail({id:photo.id})">把路由参数送出。

controller.js PhotoDetailController控制器通过$stateParams获取路由参数

...
//别名:ctrPhotoDetail
photosGallery.controller('PhotoDetailController', ['$scope', '$state', '$stateParams',
function($scope, $state, $stateParams){
var id = null;
this.photo = null;
this.init = function(){
id = parseInt($stateParams.id);
this.photo = $scope.ctrPhoto.photos[id];
}
}
]); 

photos-detail.html 从以上的PhotoDetailController中获取数据。

<h1>photo-details</h1>
<a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
<a ui-sref="content.photos.list" style="margin-left: 15px;">
<i class="fa fa-arrow-circle-left fa-2x"></i>
</a>
<div ng-init="ctrPhotoDetail.init()">
<img class="img-responsive img-rounded" ng-src="../assets/images/{{ctrPhotoDetail.photo.imageName}}"
style="margin:auto; width: 60%;">
<div class="well well-sm" style="margin:auto; width: 60%; margin-top: 15px;">
<h4>{{ctrPhotoDetail.photo.title}}</h4>
<p>{{ctrPhotoDetail.photo.description}}</p>
</div>
<div style="margin:auto; width: 80%; margin-bottom: 15px;">
<button style="margin-top: 10px; width:100%;"
class="btn btn-default" ui-sref=".comment">Comments</button>
</div>
</div>
<div ui-view></div> 

state间如何传字符串参数

在路由中这样设置:

.state('content.photos.detail.comment',{
url:'/comment?skip&limit',
templateUrl: 'partials/photos-detail-comment.html',
controller: 'PhotoCommentController',
controllerAs: 'ctrPhotoComment'
}) 

controllers.js 中修改如下

photoGallery.controller('HomeController',['$scope', '$state', function($scope, $state){
this.message = 'Welcome to the Photo Gallery';
}]);
//别名:ctrPhoto
photoGallery.controller('PhotoController',['$scope','$state', function($scope, $state){
this.photos = [
{ id: 0, title: 'Photo 1', description: 'description for photo 1', imageName: 'image1.JPG', comments:[
{ name:'User1', comment: 'Nice', imageName: 'man.png'},
{ name:'User2', comment:'Very good', imageName: 'man.png'},
{ name:'User3', comment:'Nice', imageName: 'woman.png'},
{ name:'User4', comment:'Very good', imageName: 'woman.png'},
{ name:'User5', comment:'Very good', imageName: 'man.png'},
{ name:'User6', comment:'Nice', imageName: 'woman.png'},
{ name:'User7', comment:'So so', imageName: 'man.png'}
]},
{ id: 1, title: 'Photo 2', description: 'description for photo 2', imageName: 'image2.JPG', comments:[
{ name:'User1', comment: 'Nice', imageName: 'man.png'},
{ name:'User2', comment:'Very good', imageName: 'man.png'},
{ name:'User3', comment:'Nice', imageName: 'woman.png'},
{ name:'User4', comment:'Very good', imageName: 'woman.png'}
]},
{ id: 2, title: 'Photo 3', description: 'description for photo 3', imageName: 'image3.JPG', comments:[
{ name:'User1', comment: 'Nice', imageName: 'man.png'},
{ name:'User2', comment:'Very good', imageName: 'man.png'},
{ name:'User3', comment:'Nice', imageName: 'woman.png'},
{ name:'User4', comment:'Very good', imageName: 'woman.png'},
{ name:'User5', comment:'Very good', imageName: 'man.png'},
{ name:'User6', comment:'Nice', imageName: 'woman.png'},
{ name:'User7', comment:'So so', imageName: 'man.png'}
]},
{ id: 3, title: 'Photo 4', description: 'description for photo 4', imageName: 'image4.JPG', comments:[
{ name:'User6', comment:'Nice', imageName: 'woman.png'},
{ name:'User7', comment:'So so', imageName: 'man.png'}
]}
];
//给子state下controller中的photos赋值
this.pullData = function(){
$scope.$$childTail.ctrPhotoList.photos = this.photos;
}
}]);
//别名:ctrPhotoList
photoGallery.controller('PhotoListController',['$scope','$state', function($scope, $state){
this.reading = false;
this.photos = new Array();
this.init = function(){
this.reading = true;
setTimeout(function(){
$scope.$apply(function(){
$scope.ctrPhotoList.getData();
});
}, 1500);
}
this.getData = function(){
//调用父state中controller中的方法
$scope.$parent.ctrPhoto.pullData();
/*this.photos = $scope.$parent.ctrPhoto.photos;*/
this.reading = false;
}
}]);
//别名:ctrPhotoDetail
photoGallery.controller('PhotoDetailController', ['$scope', '$state', '$stateParams',
function($scope, $state, $stateParams){
var id = null;
this.photo = null;
this.init = function(){
id = parseInt($stateParams.id);
this.photo = $scope.ctrPhoto.photos[id];
}
}
]);
photoGallery.controller('PhotoCommentController', ['$scope', '$state', '$stateParams',
function($scope, $state, $stateParams){
var id, skip, limit = null;
this.comments = new Array();
this.init = function(){
id = parseInt($stateParams.id);
var photo = $scope.ctrPhoto.photos[id];
if($stateParams.skip){
skip = parseInt($stateParams.skip);
}else{
skip = 0;
}
if($stateParams.limit){
limit = parseInt($stateParams.limit);
}else{
limit = photo.comments.length;
}
this.comments = photo.comments.slice(skip, limit);
}
}
]); 

也就是,$stateParams不仅可以接收路由参数,还可以接收查询字符串参数。

photo-detail.html 需要把查询字符串参数传递出去

<h1>photo-details</h1>
<a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
<a ui-sref="content.photos.list" style="margin-left: 15px;">
<i class="fa fa-arrow-circle-left fa-2x"></i>
</a>
<div ng-init="ctrPhotoDetail.init()">
<img class="img-responsive img-rounded" ng-src="../assets/images/{{ctrPhotoDetail.photo.imageName}}"
style="margin:auto; width: 60%;">
<div class="well well-sm" style="margin:auto; width: 60%; margin-top: 15px;">
<h4>{{ctrPhotoDetail.photo.title}}</h4>
<p>{{ctrPhotoDetail.photo.description}}</p>
</div>
<div style="margin:auto; width: 80%; margin-bottom: 15px;">
<button style="margin-top: 10px; width:100%;"
class="btn btn-default" ui-sref=".comment({skip:0, limit:2})">Comments</button>
</div>
</div>
<div ui-view></div> 

以上,通过ui-sref=".comment({skip:0, limit:2})把查询字符串传递出去。

photos-detail-comment.html

<h1>photos-detail-comment</h1>
<div ng-init="ctrPhotoComment.init()" style="margin-top:15px;">
<div ng-repeat="comment in ctrPhotoComment.comments" class="well well-sm" style="margin: auto; width: 60%;">
<div class="media">
<div class="media-left media-middle">
<a href="">
<img class="img-circle" style="width:60px;" src="../assets/images/{{comment.imageName}}" alt="图片 11">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">{{comment.name}}</h4>
{{comment.comment}}
</div>
</div>
</div>
</div> 

state间如何传递对象

通过data属性,把一个对象赋值给它。

.state('content',{
url: '/',
abstract: true,
data:{
user: "user",
password: "1234"
},
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{templateUrl: 'partials/header.html'},
}
}) 

给header.html加上一个对应的控制器,并提供注销方法。

$stateProvider
.state('content',{
url: '/',
abstract: true,
data:{
user: "user",
password: "1234"
},
views:{
"":{templateUrl: 'partials/content.html'},
"header@content":{
templateUrl: 'partials/header.html',
controller: function($scope, $rootScope, $state){
$scope.logoff = function(){
$rootScope.user = null;
}
}
}
}
})

添加一个有关登录页的state

.state('content.login',{
url:'login',
data:{
loginError: 'User or password incorrect.'
},
views:{
"body@content" :{
templateUrl: 'partials/login.html',
controller: function($scope, $rootScope, $state){
$scope.login = function(user, password, valid){
if(!valid){
return;
}
if($state.current.data.user === user && $state.current.data.password === password){
$rootScope.user = {
name: $state.current.data.user
}
// Or Inherited
/*$rootScope.user = {
name: $state.$current.parent.data.user
};*/
$state.go('content.home'); 
}else{
$scope.message = $state.current.data.loginError;
}
}
}
}
}
}) 

添加login.html文件,现在的文件结构为:

asserts/
.....css/
.....images/
..........image1.jpg
..........image2.jpg
..........image3.jpg
..........image4.jpg
node_modules/
partials/
.....about.html
.....home.html
.....photos.html
.....content.html
.....header.html
.....photos-list.html
.....photo-detail.html
.....photos-detail-comment.html
.....login.html

app.js

index.html

login.html

<form name="form" ng-submit="login(user, password, form.$valid)">
<div class="panel panel-primary" style="width:360px; margin: auto;">
<div class="panel-heading">
<h3 class="panel-title">Indentification</h3>
</div>
<div class="panel-body">
<input name="user" type="text" class="form-control" ng-model="user" placeholder="User ..." required>
Enter the user
<hr>
<input name="password" type="password" class="form-control" ng-model="password" placeholder="Password ..." required>
Enter the password 
</div>
<div class="panel-footer">
<button class="btn btn-default" type="submit">Login</button>
<button class="btn btn-default" type="reset">Reset</button>
{{message}} 
</div> 
</div>
</form> 

header.html 修改如下

<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> 



</button>
<a class="navbar-brand" ui-sref="content.home">Home</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>
<a ui-sref="content.photos.list">Photos</a> 
</li>
<li>
<a ui-sref="content.about">About</a> 
</li> 
</ul>
<ul class="nav navbar-nav navbar-right"> 
<li ng-if="user.name" class="dropdown">
<a class="dropdown-toggle" role="button" aria-expanded="false" href="#" data-toggle="dropdown">{{user.name}} </a>
<ul class="dropdown-menu" role="menu">
<li><a ui-sref="content.home" ng-click="logoff()">Sing out</a></li> 
</ul> 
</li> 
<li ng-if="!user.name">
<a ui-sref="content.login">Sing In</a>
</li> 
</ul> 
</div>
</div>
</nav> 

onEnter和onExit事件

.state('content.photos.detail',{
url: '/detail/:id',
templateUrl: 'partials/photos-detail.html',
controller: 'PhotoDetailController',
controllerAs: 'ctrPhotoDetail',
resolve:{
viewing: function($stateParams){
return{
photoId: $stateParams.id
}
}
},
onEnter: function(viewing){
var photo = JSON.parse(sessionStorage.getItem(viewing.photoId));
if(!photo){
photo = {
views: 1,
viewing: 1
}
}else{
photo.views = photo.views + 1;
photo.viewing = photo.viewing + 1;
}
sessionStorage.setItem(viewing.photoId, JSON.stringify(photo));
},
onExit: function(viewing){
var photo = JSON.parse(sessionStorage.getItem(viewing.photoId));
photo.viewing = photo.viewing - 1;
sessionStorage.setItem(viewing.photoId, JSON.stringify(photo));
}
})

在PhotoDetailController中:

photoGallery.controller('PhotoDetailController', ['$scope', '$state', '$stateParams',
function($scope, $state, $stateParams){
var id = null;
this.photo = null;
this.viewObj = null;
this.init = function(){
id = parseInt($stateParams.id);
this.photo = $scope.ctrPhoto.photos[id];
this.viewObj = JSON.parse(sessionStorage.getItem($stateParams.id));
}
}
]);

photos-detail.html

<h1>photo-details</h1>
<a class="btn btn-default" ui-sref=".comment">通过相对路径去子state</a>
<a ui-sref="content.photos.list" style="margin-left: 15px;">
<i class="fa fa-arrow-circle-left fa-2x"></i>
</a>
<div ng-init="ctrPhotoDetail.init()">
<img class="img-responsive img-rounded" ng-src="../assets/images/{{ctrPhotoDetail.photo.imageName}}"
style="margin:auto; width: 60%;">
<div class="well well-sm" style="margin:auto; width: 60%; margin-top: 15px;">
<div class="well well-sm pull-right" style="width: 100px;">
<i>Views {{ctrPhotoDetail.viewObj.views}}</i>
</div>
<div class="well well-sm pull-right" style="width: 110px;">
<i>Viewing {{ctrPhotoDetail.viewObj.viewing}}</i>
</div>
<h4>{{ctrPhotoDetail.photo.title}}</h4>
<p>{{ctrPhotoDetail.photo.description}}</p>
</div>
<div style="margin:auto; width: 80%; margin-bottom: 15px;">
<button style="margin-top: 10px; width:100%;"
class="btn btn-default" ui-sref=".comment({skip:0, limit:2})">Comments</button>
</div>
</div>
<div ui-view></div> 

StateChangeStart事件

controller.js 增加如下

photoGallery.controller('RootController', ['$scope', '$state', '$rootScope',
function($scope, $state, $rootScope){
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){
if(toState.data.required && !$rootScope.user){
event.preventDefault();
$state.go('content.login');
}
});
}
]); 

修改content这个state:

.state('content',{
url:'/',
abstract: true,
data:{
user: "user",
password: "1234"
},
views:{
"":{
templateUrl: 'partials/content.html',
controller: 'RootController'
},
"header@content":{
templateUrl: 'partials/header.html',
controller: function($scope, $rootScope, $state){
$scope.logoff = function(){
$rootScope.user = null;
}
}
}
}
})

content.photos.detail这个state

.state('content.photos.detail',{
url:'/detail/:id',
templateUrl: 'partials/photos-detail.html',
controller: 'PhotoDetailController',
controllerAs: 'ctrPhotoDetail',
data:{
required: true
},
resolve:{
viewing: function($stateParams){
return{
photoId: $stateParams.id
}
}
},
onEnter: function(viewing){
var photo = JSON.parse(sessionStorage.getItem(viewing.photoId));
if(!photo){
photo = {
views: 1,
viewing: 1
}
}else{
photo.views = photo.views + 1;
photo.viewing = photo.viewing + 1;
}
sessionStorage.setItem(viewing.photoId, JSON.stringify(photo));
},
onExit: function(viewing){
var photo = JSON.parse(sessionStorage.getItem(viewing.photoId));
photo.viewing = photo.viewing - 1;
sessionStorage.setItem(viewing.photoId, JSON.stringify(photo));
}
})

以上,添加了

data:{
required: true
} 

同理,content.photos.detail.comment这个state

.state('content.photos.detail.comment',{
url:'/comment?skip&limit',
templateUrl: 'partials/photos-detail-comment.html',
controller: 'PhotoCommentController',
controllerAs: 'ctrPhotoComment',
data:{
required: true
}
}) 

StateNotFound事件

photosGallery.controller('RootController', ['$scope', '$state', '$rootScope',
function($scope, $state, $rootScope){
$rootScope.$on('$stateChangeStart', 
function(event, toState, toParams, fromState, fromParams){
if(toState.data.required && !$rootScope.user){
event.preventDefault();
$state.go('content.login');
return;
} 
});
$rootScope.$on('$stateNotFound', 
function(event, unfoundState, fromState, fromParams){
event.preventDefault();
$state.go('content.notfound');
});
}
]); 

添加一个state:

.state('content.notfound',{
url:'notfound',
views: {
"body@content": {templateUrl: 'partials/page-not-found.html'} 
} 
}) 

page-not-found.html

<div class="well well-sm" style="margin: 20px;">
<i class="fa fa-frown-o fa-4x pull-left"></i><h3>404 - Sorry! Not found your page.</h3>
</div> 

StateChangeSuccess事件

photosGallery.controller('RootController', ['$scope', '$state', '$rootScope',
function($scope, $state, $rootScope){
$rootScope.accessLog = new Array();
$rootScope.$on('$stateChangeStart', 
function(event, toState, toParams, fromState, fromParams){
if(toState.data.required && !$rootScope.user){
event.preventDefault();
$state.go('content.login');
return;
} 
});
$rootScope.$on('$stateNotFound', 
function(event, unfoundState, fromState, fromParams){
event.preventDefault();
$state.go('content.notfound');
});
$rootScope.$on('$stateChangeSuccess', 
function(event, toState, toParams, fromState, fromParams){
$rootScope.accessLog.push({
user: $rootScope.user,
from: fromState.name,
to: toState.name,
date: new Date()
});
});
}
]); 

添加一个state

.state('content.log',{
url:'log',
data:{
required: true
},
views: {
"body@content": {templateUrl: 'partials/log.html'} 
} 
}) 

log.html

<h1><i class="fa fa-file-text-o"></i> Access Log</h1>
<div style="margin:auto; width: 380px;">
<div class="well well-sm" ng-repeat="log in accessLog track by $index">
<i class="fa fa-pencil fa-2x pull-left"></i>
{{log.user ? log.user.name: 'anonymous'}} in {{log.date | date: 'longDate'}} at {{log.date | date: 'shortTime'}}
<p>From: {{log.from}} => to: {{log.to}}</p>
</div>
</div> 

StateChangeError事件

photosGallery.controller('RootController', ['$scope', '$state', '$rootScope',
function($scope, $state, $rootScope){
$rootScope.accessLog = new Array();
$rootScope.$on('$stateChangeStart', 
function(event, toState, toParams, fromState, fromParams){
if(toState.data.required && !$rootScope.user){
event.preventDefault();
$state.go('content.login');
return;
} 
});
$rootScope.$on('$stateNotFound', 
function(event, unfoundState, fromState, fromParams){
event.preventDefault();
$state.go('content.notfound');
});
$rootScope.$on('$stateChangeSuccess', 
function(event, toState, toParams, fromState, fromParams){
$rootScope.accessLog.push({
user: $rootScope.user,
from: fromState.name,
to: toState.name,
date: new Date()
});
});
$rootScope.$on('$stateChangeError', 
function(event, toState, toParams, fromState, fromParams, error){
event.preventDefault();
$state.go('content.error', {error: error});
});
}
]); 

添加2个state:

.state('content.profile', {
url:'profile',
data:{
required: true
},
resolve:{
showError: function(){
throw 'Error in code.';
}
},
views:{
"body@content": {template: '<div>Error</div>'}
} 
})
.state('content.error',{
url:'error/:error',
views:{
"body@content":{
templateUrl: 'partials/error.html',
controller: function($scope, $stateParams){
$scope.error = {
message: $stateParams.error
}
}
}
}
})

error.html

<div class="well well-sm" style="margin: 20px;">
<i class="fa fa-exclamation-circle fa-2x"> Sorry! But this message was displayed: {{error.message}}</i>
</div>

您可能感兴趣的文章:

  • angularJS中router的使用指南
  • Angular2学习笔记——详解路由器模型(Router)
  • 详解angular2实现ng2-router 路由和嵌套路由
  • Angularjs中UI Router的使用方法
  • angular基于路由控制ui-router实现系统权限控制
  • AngularJS ui-router (嵌套路由)实例
  • 详解angular笔记路由之angular-router

本文由金沙棋牌发布于金沙棋牌官方平台,转载请注明出处:ThinkPHP实例教程,技术栈开发web应用

关键词:

上一篇:图片压缩算法,获取图片信息和像素内容

下一篇:没有了