当前位置: 首页 > 文档资料 > Next.js 中文文档 >

路由

优质
小牛编辑
122浏览
2023-12-01

<Link>用法

Examples
  • Hello World

可以用 <Link> 组件实现客户端的路由切换。

// pages/index.js
import Link from 'next/link'

export default () =>
  <div>
    Click{' '}
    <Link href="/about">
      <a>here</a>
    </Link>{' '}
    to read more
  </div>
// pages/about.js
export default () => <p>Welcome to About!</p>

注意:可以使用<Link prefetch>使链接和预加载在后台同时进行,来达到页面的最佳性能。

客户端路由行为与浏览器很相似:

  1. 组件获取
  2. 如果组件定义了getInitialProps,数据获取了。如果有错误情况将会渲染 _error.js
  3. 1和2都完成了,pushState执行,新组件被渲染。

如果需要注入pathname, queryasPath到你组件中,你可以使用withRouter。

URL 对象

Examples
  • With URL Object Routing

组件<Link>接收 URL 对象,而且它会自动格式化生成 URL 字符串

// pages/index.js
import Link from 'next/link'

export default () =>
  <div>
    Click{' '}
    <Link href={{ pathname: '/about', query: { name: 'Zeit' }}}>
      <a>here</a>
    </Link>{' '}
    to read more
  </div>

将生成 URL 字符串/about?name=Zeit,你可以使用任何在Node.js URL module documentation定义过的属性。

替换路由

<Link>组件默认将新 url 推入路由栈中。你可以使用replace属性来防止添加新输入。

// pages/index.js
import Link from 'next/link'

export default () =>
  <div>
    Click{' '}
    <Link href="/about" replace>
      <a>here</a>
    </Link>{' '}
    to read more
  </div>
组件支持点击事件 onClick

<Link>支持每个组件所支持的onClick事件。如果你不提供<a>标签,只会处理onClick事件而href将不起作用。

// pages/index.js
import Link from 'next/link'

export default () =>
  <div>
    Click{' '}
    <Link href="/about">
      <img src="/static/image.png" alt="image" />
    </Link>
  </div>
暴露 href 给子元素

如子元素是一个没有 href 属性的<a>标签,我们将会指定它以免用户重复操作。然而有些时候,我们需要里面有<a>标签,但是Link组件不会被识别成超链接,结果不能将href传递给子元素。在这种场景下,你可以定义一个Link组件中的布尔属性passHref,强制将href传递给子元素。

注意: 使用a之外的标签而且没有通过passHref的链接可能会使导航看上去正确,但是当搜索引擎爬行检测时,将不会识别成链接(由于缺乏 href 属性),这会对你网站的 SEO 产生负面影响。

import Link from 'next/link'
import Unexpected_A from 'third-library'

export default ({ href, name }) =>
  <Link href={href} passHref>
    <Unexpected_A>
      {name}
    </Unexpected_A>
  </Link>
禁止滚动到页面顶部

<Link>的默认行为就是滚到页面顶部。当有 hash 定义时(#),页面将会滚动到对应的 id 上,就像<a>标签一样。为了预防滚动到顶部,可以给<Link>scroll={false}属性:

<Link scroll={false} href="/?counter=10"><a>Disables scrolling</a></Link>
<Link href="/?counter=10"><a>Changes with scrolling to top</a></Link>

命令式

Examples
  • Basic routing
  • With a page loading indicator

你也可以用next/router实现客户端路由切换

import Router from 'next/router'

export default () =>
  <div>
    Click <span onClick={() => Router.push('/about')}>here</span> to read more
  </div>

拦截器 popstate

有些情况(比如使用custom router),你可能想监听popstate,在路由跳转前做一些动作。 比如,你可以操作 request 或强制 SSR 刷新

import Router from 'next/router'

Router.beforePopState(({ url, as, options }) => {
  // I only want to allow these two routes!
  if (as !== "/" || as !== "/other") {
    // Have SSR render bad routes as a 404.
    window.location.href = as
    return false
  }

  return true
});

如果你在beforePopState中返回 false,Router将不会执行popstate事件。 例如Disabling File-System Routing。

以上Router对象的 API 如下:

  • route - 当前路由的String类型
  • pathname - 不包含查询内容的当前路径,为String类型
  • query - 查询内容,被解析成Object类型. 默认为{}
  • asPath - 展现在浏览器上的实际路径,包含查询内容,为String类型
  • push(url, as=url) - 页面渲染第一个参数 url 的页面,浏览器栏显示的是第二个参数 url
  • replace(url, as=url) - performs a replaceState call with the given url
  • beforePopState(cb=function) - 在路由器处理事件之前拦截.

pushreplace 函数的第二个参数as,是为了装饰 URL 作用。如果你在服务器端设置了自定义路由将会起作用。

URL 对象用法

pushreplace可接收的 URL 对象(<Link>组件的 URL 对象一样)来生成 URL。

import Router from 'next/router'

const handler = () =>
  Router.push({
    pathname: '/about',
    query: { name: 'Zeit' }
  })

export default () =>
  <div>
    Click <span onClick={handler}>here</span> to read more
  </div>

也可以像<Link>组件一样添加额外的参数。

路由事件

你可以监听路由相关事件。 下面是事件支持列表:

  • routeChangeStart(url) - 路由开始切换时触发
  • routeChangeComplete(url) - 完成路由切换时触发
  • routeChangeError(err, url) - 路由切换报错时触发
  • beforeHistoryChange(url) - 浏览器 history 模式开始切换时触发
  • hashChangeStart(url) - 开始切换 hash 值但是没有切换页面路由时触发
  • hashChangeComplete(url) - 完成切换 hash 值但是没有切换页面路由时触发

这里的url是指显示在浏览器中的 url。如果你用了Router.push(url, as)(或类似的方法),那浏览器中的 url 将会显示 as 的值。

下面是如何正确使用路由事件routeChangeStart的例子:

const handleRouteChange = url => {
  console.log('App is changing to: ', url)
}

Router.events.on('routeChangeStart', handleRouteChange)

如果你不想长期监听该事件,你可以用off事件去取消监听:

Router.events.off('routeChangeStart', handleRouteChange)

如果路由加载被取消(比如快速连续双击链接)

Router.events.on('routeChangeError', (err, url) => {
  if (err.cancelled) {
    console.log(`Route to ${url} was cancelled!`)
  }
})
浅层路由

Examples
  • Shallow Routing

浅层路由允许你改变 URL 但是不执行getInitialProps生命周期。你可以加载相同页面的 URL,得到更新后的路由属性pathnamequery,并不失去 state 状态。

你可以给Router.pushRouter.replace方法加shallow: true参数。如下面的例子所示:

// Current URL is "/"
const href = '/?counter=10'
const as = href
Router.push(href, as, { shallow: true })

现在 URL 更新为/?counter=10。在组件里查看this.props.router.query你将会看到更新的 URL。

你可以在componentdidupdate钩子函数中监听 URL 的变化。

componentDidUpdate(prevProps) {
  const { pathname, query } = this.props.router
  // verify props have changed to avoid an infinite loop
  if (query.id !== prevProps.router.query.id) {
    // fetch data based on the new query
  }
}

注意:

浅层路由只作用于相同 URL 的参数改变,比如我们假定有个其他路由about,而你向下面代码样运行:

Router.push('/?counter=10', '/about?counter=10', { shallow: true })

那么这将会出现新页面,即使我们加了浅层路由,但是它还是会卸载当前页,会加载新的页面并触发新页面的getInitialProps