angular2地址栏路由配置

一步一步route过去可以,地址栏直接写url怎么就找不到了呢?

这关乎于Nodejs的express路由规则(http://hm4123660.iteye.com/blog/2195035)

express 封装了多种 http 请求方式,我们主要只使用 get和post,可以使用 app.all 获取所以请求方式,回调函数有两个参数分别是 req 和 res,代表请求信息和响应信息。

  • req.query

    : 处理 get 请求

  • req.params

    : 处理 /:xxx 形式的 get 请求

  • req.body

    : 处理 post 请求

  • req.param()

    : 可以处理 get 和 post 请求,但查找优先级由高到低为req.params→req.body→req.query

例如:

获取表达post的参数

var username=req.body.name;//获取post参数
var password=req.body.password;

获取get参数

访问URL:http://localhost:3000/test?id=110&password=120

获取代码:

app.get('/test',function(req,res){
    res.send("id: "+req.query.id+"  password: "+req.query.password);
})

一. *通配URL

例如:

app.get('/test/*',function(req,res){
    res.send(req.originalUrl);//req.originalUrl获取当前URL
});

*号可以通配URL为localhost:3000/test/.......的URL

二. /:id的占位标识符URL

例如:

app.get('/test/:userid',function(req,res){
    res.send("userid: "+req.params.userid);//req.params.userid获取userid的值
});

三.next()权限控制转移

express的路由控制有个next()功能,在定义了多个路由的时候,使用next对匹配的url会按顺序执行,

如果不使用next进行权限转移,只会执行第一个满足的路由规则。

<span class="token comment">next() 函数用于将当前控制权转交给下一步处理,如果给 next() 传递一个参数时,表示出错信息</span>

例如:

app.get('/test/*',function(req,res,next){
    //res.send("userid:");//要进行转移,不要响应客户端
req.temp="给你控制权";
    next();//把权限转移到下一个路由
});
app.get('/test/next',function(req,res){
    res.send("content: "+req.temp);
})

访问URL:http://localhost:3000/test/next满足这两个路由规则

next()一般用来编写中间件

  • 中间件一般不直接对客户端进行响应,而是对请求进行一些预处理,再传递下去;
  • 中间件一般会在路由处理之前执行;

比如:

// 检查用户是否登录中间件,所有需要登录权限的页面都使用此中间件
function checkLogin (req, res, next) {
  if (req.session.user) {
    next();//检验到用户已登入,转移权限阁下一个路由
  } else {
    res.redirect('/');//否则,页面重定位,不执行下面路由
  }
} 

满足了通配符*和next()两个条件(需要传入),就可以使得二级路由获得权限了。

app.get('/*', function (req, res, next) {
// 就是不能有这一句
// res.sendFile(__dirname + '/../dist/index.html');
// 上面这一句其实是无关紧要的,并不需要它就可以访问第一个路由
    req.temp="给你控制权";
 next();
});
app.get('/test',function(req,res){
    res.send("content: "+req.temp);
})

静态目录其实已经在app.use的时候指定了

app.use('/', express.static(__dirname + '/../dist'));
app.use('/scripts', express.static(__dirname + '/../node_modules'));

res.sendFile之后next或者在获取了控制权的下一级路由中写这一句,都会报Forbidden的。

这是单纯node中路由的跳转,在angular2中,不会去加载另一个html文件,还是要用angular自己的方式实现,参看 Angular2 路由教程 3 - 子模块以及异步加载(https://gold.xitu.io/entry/58523aa91b69e6006c7e63ac)

如果像一般的starter那样把todo相关的路由定义在一个文件中,然后在app的路由定义中把所有路由合并到一起。todo.routes.ts的内容如下:

// 省略import
export const TodoRoutes: Route[] = [
    {
        path: 'todo',
        canActivateChild: [MyTodoGuard],
        children: [
            { path: 'list', component: TodoListComponent, resolve: { todos: MyTodoResolver } },
            { path: 'detail/:id', component: TodoDetailComponent, canDeactivate: [ CanLeaveTodoDetailGuard ] }
        ]
    }
];

然后在app.routes.ts中定义一个路由模块:

const routes: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full' },
    { path: 'home', component: HomeComponent },
    //此处省略...TodoRoutes 这里就是将TodoRoutes列表里的内容合并到routes
];
@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule { }

最后,在AppModule里面引入这个路由模块。

这种方式实现的路由无法实现子模块的延时加载,要实现延时加载,首先要将todo模块的路由修改成子路由模块,也就是要修改todo.routes.ts

// 省略import
export const TodoRoutes: Route[] = [
    {
        path: 'todo',
        canActivateChild: [MyTodoGuard],
        children: [
            { path: 'list', component: TodoListComponent, resolve: { todos: MyTodoResolver } },
            { path: 'detail/:id', component: TodoDetailComponent, canDeactivate: [ CanLeaveTodoDetailGuard ] }
        ]
    }
];
// 通过下面的方式定义了一个子路由模块
@NgModule({
  imports: [ RouterModule.forChild(TodoRoutes) ],
  exports: [ RouterModule ]
})
export class TodoRoutingModule { }

这里定义了一个子路由模块,TodoRoutingModule,它使用RouterModule.forChild(TodoRoutes)来创建。跟整个App的路由模块比较的话,主路由模块使用RouterModule.forRoot(routes)来定义。

定义好了子路由模块,在子模块里面引入它既可:

// 省略import
@NgModule({
  imports: [CommonModule, FormsModule, TodoRoutingModule ],
  declarations: [TodoListComponent, TodoDetailComponent, TodoItemComponent],
  providers: [TodoService, MyTodoResolver, MyTodoGuard, CanLeaveTodoDetailGuard]
})
export class TodoModule {}

这样就定义好了一个子模块。当用户打开/todo/list/todo/detail/*时,这个子模块里面的相关页面就会展示,它也不会跟其他模块有任何交互。也就是说,进入和离开这个子模块,都是通过路由跳转实现。这个子模块也是完全独立的,可以独立开发,也可以很容易就用到其他应用里面。

coockbook参看http://blog.csdn.net/qq_36181008/article/details/53331685

另外,使用`ActivatedRoute`拿到当前路由获取参数:

ngOnInit() {
        this.route.params.subscribe((params) => {
            this.createPies();
            this.onTopListFilterChange(params['id']);
        });
    };

  但如果是在`children`中指定的component要拿到路由参数就没那么容易了,这时候再使用ActivatedRoute根本拿不到参数,我猜应当是在Angular2中一个ActivatedRoute对应一级路由配置,所以我们需要找到父级路由,由父级路由去拿参数。这时我们需要借用Router类的routeState属性的parent方法:

this.router.routeState.parent(this.activatedRoute).params.subscribe(params => {
   this.getDetailsById(params['id']);
})

上面的问题原文地址:http://www.cnblogs.com/dojo-lzz/p/5883408.html

默认情况下Angular2将所有的代码打包成一个文件,目的是为了提高应用的流畅性,但是如果是运行在mobile中的app,加载一个大文件可能会过慢,所以rc5提供了一种延迟加载方式,例如:

import { ModuleWithProviders }  from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

export const routes: Routes = [
  { path: '', redirectTo: 'contact', pathMatch: 'full'},
  { path: 'crisis', loadChildren: 'app/crisis/crisis.module#CrisisModule' },
  { path: 'heroes', loadChildren: 'app/hero/hero.module#HeroModule' }
];

export const routing: ModuleWithProviders = RouterModule.forRoot(routes);

其中,path指明路径,loadChildren指明使用延迟加载,'app/crisis/crisis.module#CrisisModule'指明了模块的路径,和模块的名称, 如果是用 export default 的话,这里可以不需要表明名称,只需要路径。

但是上面的语法在有些版本不能正确的懒加载,甚至使子路由失效,需要用lambada表达式:

const routes = [
  {path: '', component: HomeComponent},
  {path: 'test', loadChildren: () =>TestModule},
  {path: 'amway', loadChildren: () =>AmwayModule }
];

绝对很好用,来自stackoverflow

路由器根据路由状态来实例化组件并把他们放到合适的路由组出发点上。

@Component({
  template: `
    ...
    <router-outlet></router-outlet>
    ...
    <router-outlet name="popup"></router-outlet>
  `
})
class MailAppCmp {
}

  如‘/inbox/33/message/44(popup:compose)’,首先实例化ConversationCmp放到主<router-outlet>中,然后实例化MessageCmp放到name为popup的<Router-outlet>中。

  现在路由器对URL的解析过程完毕。但是如果用户想从MessageCmp中跳转到别的路由状态该如何做呢?Angular2提供了两种方式。

  一种是通过router.navigate方法来导航:

@Component({...})
class MessageCmp {
  private id: string;
  constructor(private route: ActivatedRoute, private router: Router) {
    route.params.subscribe(_ => this.id = _.id);
  }

  openPopup(e) {
    this.router.navigate([{outlets: {popup: ['message', this.id]}}]).then(_ => {
      // navigation is done
    });
  }
}

  一种是利用router-link方式:

@Component({
  template: `
    <a [routerLink]="['/', {outlets: {popup: ['message', this.id]}}]">Edit</a>
  `
})
class MessageCmp {
  private id: string;
  constructor(private route: ActivatedRoute) {
    route.params.subscribe(_ => this.id = _.id);
  }
}

详细阅读http://www.cnblogs.com/keatkeat/p/5810987.html

最后问题解决了还是要配置node的express模块,也就是之前常常看到含有__dirname的部分:

var path= require("path");
var app = express();

app.get('/*', function (req, res, next) {
//res.sendFile(__dirname + '/../dist/index.html');
res.sendfile(path.join(__dirname, '../dist', './index.html'));
req.temp="next";
//next();
});

简言之就是需要join一下path和index

*通配符也是很关键的。

参考文章http://www.cnblogs.com/stoneniqiu/p/5669419.html

延伸阅读http://www.cnblogs.com/darrenji/p/4981505.html

略:

var path= require("path");      
app.get('/*', function (req, res, next) {
    //res.sendFile(__dirname + '/../dist/index.html');
    res.sendfile(path.join(__dirname, '../dist', './index.html'));
   });