swayok/page.js

小巧的客户端路由器

维护者

详细信息

github.com/swayok/page.js

源代码

安装: 61

依赖者: 0

建议者: 0

安全: 0

星星: 0

关注者: 1

分支: 688

语言:JavaScript

2.01 2018-11-24 15:27 UTC

This package is auto-updated.

Last update: 2024-09-10 04:55:32 UTC


README

page router logo

受Express启发的简洁客户端路由器。

Build Status Coverage Status Gitter

page('/', index)
page('/user/:user', show)
page('/user/:user/edit', edit)
page('/user/:user/album', album)
page('/user/:user/album/sort', sort)
page('*', notfound)
page()

或路由声明的安全变体

page.route('/', index)
page.route('/user/:user', show)
page.route('/user/:user/edit', edit)
page.route('/user/:user/album', album)
page.route('/user/:user/album/sort', sort)
page.route('*', notfound)

此版本将不允许您将除字符串以外的任何内容作为第一个参数传递,也不允许将函数作为第二个参数传递

安装

安装 page.js 有多种方式。使用包管理器

$ npm install page # for browserify
$ component install visionmedia/page.js
$ bower install visionmedia/page.js

运行示例

要运行示例,请按照以下步骤安装开发依赖项并运行示例服务器

$ git clone git://github.com/visionmedia/page.js
$ cd page.js
$ npm install
$ node examples
$ open https://127.0.0.1:4000

目前我们有以下示例

  • basic 最小应用程序,显示基本路由
  • notfoundbasic 相似,具有单页面 404 支持功能
  • album 显示分页和外部链接
  • profile 简单用户资料
  • query-string 展示如何使用路由器集成插件
  • state 阐述如何使用历史状态来缓存数据
  • server 阐述如何使用 dispatch 选项在服务器上初始化内容
  • chrome Google Chrome 风格的管理界面
  • transitions 展示在“页面”之间添加转场效果的简单技术
  • partials 使用 hogan.js 在客户端渲染 mustache 部分模板

注意:请记住,这些示例没有使用 jQuery 或类似库,因此示例中的某些部分可能相对冗长,尽管它们与 page.js 没有直接关系。

API

page.route(path, callback[, callback ...])

Failsafe variant of page(path, callback[, callback ...])

定义路由映射 path 到给定的 callback(s)。每个回调函数接收两个参数,上下文next。类似于 Express,调用 next 将调用具有给定路径的下一个注册的回调。

page.route('/', user.list)
page.route('/user/:id', user.load, user.show)
page.route('/user/:id/edit', user.load, user.edit)
page.route('*', notfound)

在某些条件下,链接将被忽略,不会进行分发,例如

  • 不同源的链接
  • 具有 download 属性的链接
  • 具有 target 属性的链接
  • 具有 rel="external" 属性的链接

page(callback)

这相当于 page('*', callback) 用于通用“中间件”。

page(path)

导航到给定的 path

$('.view').click(function(e){
  page('/user/12')
  e.preventDefault()
})

page(fromPath, toPath)

设置从一路径到另一路径的跳转。

page.redirect(fromPath, toPath)

等同于 page(fromPath, toPath)

page.redirect(path)

调用 page.redirect 仅以字符串作为第一个参数时,将跳转到另一个路由。等待当前路由推送状态后,将其替换为新路由,使浏览器历史记录保持干净。

page('/default', function(){
  // some logic to decide which route to redirect to
  if(admin) {
    page.redirect('/admin');
  } else {
    page.redirect('/guest');
  }
});

page('/default');

page.show(path, state, dispatch, push, customData)

导航到 path。返回:Context 参数

  • path - URL
  • state - 历史状态对象
  • dispatch - 布尔值;默认:true;当 false 时,路由器将不会为此 URL 运行任何处理器,但将创建 Context 实例
  • push - 布尔值;默认:true;当 false 时,路由器将不会更改浏览器地址栏中的 URL
  • customData - 对象;存储到 Context 中的某些特定数据。有关更多信息,请参阅 Context#customData

page.replace(path, state, init, dispatch, customData)

导航到 path 替换浏览器历史记录中的当前 URL。返回:Context 参数

  • path - URL
  • state - 历史状态对象
  • init - 布尔值;我不确定,但可能只是一个标志,表示在 page.start() (@swayok) 中分发的初始 Context
  • dispatch - 布尔值;默认:true;当 false 时,路由器将不会为此 URL 运行任何处理器,但将创建 Context 实例
  • customData - 对象;存储到 Context 中的某些特定数据。有关更多信息,请参阅 Context#customData

page.back(path, state)

导航到历史记录中的上一页或当历史记录为空时导航到 path。参数

  • path - 当历史记录为空时默认导航到的URL。默认:基础URL
  • state - 历史状态对象

page.reload()

重新加载当前URL

page([options])

注册页面的 popstate / click 绑定。如果您正在进行选择性绑定,您可能需要传递 { click: false } 来指定此操作。以下选项可用

  • click 绑定到点击事件 [true]
  • popstate 绑定到 popstate [true]
  • dispatch 执行初始分发 [true]
  • hashbang 在URL前添加 #! [false]
  • decodeURLComponents 从路径组件(查询字符串、路径名、hash)中删除URL编码 [true]

如果您希望从服务器加载初始内容,您可能需要将 dispatch 设置为 false

page.start([options])

与上面的 page([options]) 相同。

page.stop()

解绑 popstateclick 处理程序。

page.base([path])

获取或设置基础 path。例如,如果 page.js 在 /blog/* 中运行,则设置基础路径为 "/blog"。

page.exit(path, callback[, callback ...])

定义一个退出路由映射 path 到给定的 callback(s)

退出路由在页面更改时调用,使用来自先前更改的上下文。例如

page('/sidebar', function(ctx, next) {
  sidebar.open = true
  next()
})

page.exit('/sidebar', function(ctx, next) {
  sidebar.open = false
  next()
})

page.exit(callback)

相当于 page.exit('*', callback)

上下文

路由传递 Context 对象,这些对象可以用来共享状态,例如 ctx.user =,以及 pushState API 提供的“state”历史记录 ctx.state

Context#save()

使用 replaceState() 保存上下文。例如,这对于在用户按下“后退”时加载的HTML或其他资源的缓存很有用。

Context#handled

如果为 true,则将上下文标记为已处理,以防止 默认404行为。例如,这对于具有无限数量回调的路由很有用。

Context#canonicalPath

包括“基础”路径(如果有)和查询字符串的路径名(如)/admin/login?foo=bar"。

Context#path

路径名和查询字符串(如)/login?foo=bar"。

Context#querystring

无前导 ? 的查询字符串(如 "foo=bar"),默认为 ""。

Context#pathname

无查询字符串的路径名(如)/login"。

Context#state

pushState 状态对象。

Context#title

pushState 标题。

Context#push

指示是否应更改当前URL。默认:null

示例:您处理了显示模态对话框的请求,但您不希望在浏览器中更改页面地址。为此,您只需在请求处理程序中将 contxt.push = false; 设置即可。

注意:如果 push 参数在 page.show()page.replace() 中为 false,则 contxt.push = true; 不会强制更改URL。

Context#customData

针对此上下文的一些特定数据。允许您提供有关此上下文的更多信息。

可以通过 page.show() 和 page.replace() 将 customData 对象作为第5个参数传递

它用于 page.reload() 以及默认的 onclick() 和 onpopstate() 事件处理程序

  • page.reload() 提供 {is_reload: true} customData
  • onclick() 提供 {is_click: true, target: DOM Element} customData
  • onpopstate() 提供 {is_history: true} customData

路由

路由器使用与 Express 相同的字符串到正则表达式的转换,因此 ":id"、":id?" 和 "*" 等与您预期的一样工作。

与 Express 相似的另一个方面是传递多个回调的能力。您可以使用此功能来简化嵌套回调,或者简单地抽象组件。

分离关注点

例如,假设您有一个用于 编辑 用户的路由,还有一个用于 查看 用户的路由。在这两种情况下,您都需要加载用户。实现这一目标的一种方法是在这里所示的方式中使用几个回调

page('/user/:user', load, show)
page('/user/:user/edit', load, edit)

使用 * 字符,我们可以将其更改为匹配所有以 "/user" 前缀的路由,以实现相同的结果

page('/user/*', load)
page('/user/:user', show)
page('/user/:user/edit', edit)

同样,* 可以用作所有路由之后的通配符,作为 404 处理器,在所有路由之前、之间等。例如

page('/user/:user', load, show)
page('*', function(){
  $('body').text('Not found!')
})

默认 404 行为

默认情况下,当路由不匹配时,page.js 会调用 page.stop() 来取消绑定自身,然后继续重定向到请求的地址。这意味着您可以在不明确绑定某些链接的情况下,使用 page.js 与多页应用程序 一起

处理参数和上下文

就像 requestresponse 对象在 Express 中被传递一样,page.js 有一个单一的 "Context" 对象。使用之前的 loadshow 用户的示例,我们可以将任意属性分配给 ctx 以在回调之间保持状态。

要构建一个将加载用户以供后续路由使用的 load 函数,您需要访问传递的 ":id"。您可以使用 ctx.params.NAME 来这样做,就像 Express 一样

function load(ctx, next){
  var id = ctx.params.id
}

然后对服务器执行某种操作,将用户分配给 ctx.user 以供其他路由使用。然后调用 next() 来传递控制权到后续匹配的路由(如果有的话)。

function load(ctx, next){
  var id = ctx.params.id
  $.getJSON('/user/' + id + '.json', function(user){
    ctx.user = user
    next()
  })
}

“show” 函数可能看起来像这样,但是您可以根据需要渲染模板或执行任何操作。请注意,在这里 next() 并未调用,因为这被认为是“终点”,并且直到另一个链接被点击或调用 page(path),都不会匹配任何路由。

function show(ctx){
  $('body')
    .empty()
    .append('<h1>' + ctx.user.name + '<h1>');
}

最后,像这样使用它们

page('/user/:id', load, show)

处理状态

当与 pushState API 和 page.js 一起工作时,您可以提供可选的状态对象,以便在用户导航历史记录时使用。

例如,如果您有一个照片应用程序,您执行了一个相对昂贵的搜索来填充图像列表,通常当用户在浏览器中点击“后退”时,路由会被调用,并且查询会被再次执行。

一个示例实现可能如下所示

function show(ctx){
  $.getJSON('/photos', function(images){
    displayImages(images)
  })
}

您可以使用历史记录的状态对象来缓存此结果或任何其他值。这使得在用户按后退时完全省略查询成为可能,从而提供了更好的体验。

function show(ctx){
  if (ctx.state.images) {
    displayImages(ctx.state.images)
  } else {
    $.getJSON('/photos', function(images){
      ctx.state.images = images
      ctx.save()
      displayImages(images)
    })
  }
}

注意:如果状态在第一次滴答(xhr、setTimeout 等)之后更改,则必须使用 ctx.save(),否则它是可选的,并且状态将在分发后保存。

匹配路径

以下是一些将字符串转换为 RegExp 的示例。

匹配显式路径

page('/about', callback)

匹配需要通过 ctx.params.name 访问的参数

page('/user/:name', callback)

匹配多个参数,例如 /user/tj/edit/user/tj/view

page('/user/:name/:operation', callback)

匹配一个可选参数和一个必需参数,现在 /user/tj 将匹配与 /user/tj/show 等相同的路由

page('/user/:name/:operation?', callback)

使用通配符字符 * 来匹配段,可通过 ctx.params[N] 获取,其中 N* 的索引,因为您可以使用多个。例如,以下将匹配 /user/12/edit/user/12/albums/2/admin 等。

page('/user/*', loadUser)

命名通配符访问,例如 /file/javascripts/jquery.js 将提供 "/javascripts/jquery.js" 作为 ctx.params.file

page('/file/:file(*)', loadUser)

当然,还有 RegExp 字面量,其中捕获组可通过 ctx.params[N] 获取,其中 N 是捕获组的索引。

page(/^\/commits\/(\d+)\.\.(\d+)/, loadUser)

插件

一个示例插件 examples/query-string/query.js 展示了如何创建插件。它将提供一个解析自 node-querystringctx.query 对象。

使用 "*" 匹配任何路径以解析查询字符串

page('*', parse)
page('/', show)
page()

function parse(ctx, next) {
  ctx.query = qs.parse(location.search.slice(1));
  next();
}

function show(ctx) {
  if (Object.keys(ctx.query).length) {
    document
      .querySelector('pre')
      .textContent = JSON.stringify(ctx.query, null, 2);
  }
}

可用插件

请提交拉取请求以添加更多内容到这个列表。

运行测试

在控制台

$ npm install
$ npm test

在浏览器中

$ npm install
$ npm run serve
$ open https://127.0.0.1:3000/

支持IE8+

如果您希望路由在不支持pushState的旧版Internet Explorer中工作,可以使用HTML5-History-API polyfill。

  npm install html5-history-api
如何将polyfill与路由一起使用(可选)

如果您的Web应用程序位于嵌套的基础路径中,您需要为HTML5-History-API polyfill指定basepath。在调用page.base()之前使用:history.redirect([prefixType], [basepath]) - 如有需要,请提供翻译链接。

  • prefixType[string|null] - 默认用"/"替换锚点(#)后的字符串。
  • basepath[string|null] - 设置基本路径。参见默认的page.base() "/"。(注意:在pathname后需要斜杠)

拉取请求

  • 将提交分解为单一目标。
  • 一个目标应该是相关但需要解释的代码块。
  • 提交应以这种形式进行:what-it-is: how-it-does-it 和或 why-it's-needed 或 what-it-is 对于微小的更改
  • 拉取请求和提交应该是代码的指南。

许可协议

(MIT许可协议)

版权所有 (c) 2012 TJ Holowaychuk <tj@vision-media.ca>

特此授予任何获得本软件及其相关文档副本(“软件”)的个人免费使用软件的权利,不受任何限制,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件副本的权利,并允许软件的受供者进行此类操作,前提是遵守以下条件

上述版权声明和本许可声明应包含在软件的副本或实质性部分中。

本软件按“原样”提供,不提供任何形式的质量保证,无论是明示的、暗示的,还是关于适销性、特定用途或非侵权的保证。在任何情况下,作者或版权所有者均不对任何索赔、损害或其他责任负责,无论这些责任是由于合同、侵权或其他方式引起的,无论这些责任是否与软件或软件的使用或其他操作有关。