id vue2路由传参_Vue.js从零开始——路由(3)

fb108d94a6b0b12d78bcb2607bd33fd6.png

前几天忙于他务,所以没怎么更新过,不过今天周末了,所以补上了前一章节的样例,再更新一章节;接下来可能就没办法这么频繁的更新了,说不定我的新工作都不是前端开发而是转行了,如果是这样的话,这个就变成了纯粹的爱好,哈哈也不错。

今天这一章节,主要是来看看路由的重定向、传参、别名以及 HTML 5 History 模式。


1 重定向

当访问 /a 时,需要实际访问到 /b 这种路由方式,就是重定向,其实也是通过 routes 来完成的,比如:

const router = new VueRouter({
  routes: [
    { path: '/a', redirect: '/b' }
  ]
});

重定向的目标也可以是一个命名的路由:

const router = new VueRouter({
  routes: [
    { path: '/a', redirect: { name: 'foo' }}
  ]
});

当然也可以是一个方法,动态返回重定向目标:

const router = new VueRouter({
  routes: [
    { path: '/a', redirect: to => {
      // 方法接收 目标路由 作为参数
      // return 重定向的 字符串路径/路径对象
       return '/b';
    }}
  ]
});

还有不少有趣的用法,可以参考下面的样例:

import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

const Home = { template: '<router-view></router-view>' };
const Default = { template: '<div>default</div>' };
const Foo = { template: '<div>foo</div>' };
const Bar = { template: '<div>bar</div>' };
const Baz = { template: '<div>baz</div>' };
const WithParams = { template: '<div>{{ $route.params.id }}</div>' };
const Foobar = { template: '<div>foobar</div>' };
const FooBar = { template: '<div>FooBar</div>' };

const router = new VueRouter({
  mode: 'history',
  base: __dirname,
  routes: [
    { path: '/', component: Home,
      children: [
        { path: '', component: Default },
        { path: 'foo', component: Foo },
        { path: 'bar', component: Bar },
        { path: 'baz', name: 'baz', component: Baz },
        { path: 'with-params/:id', component: WithParams },
        // relative redirect to a sibling route
        { path: 'relative-redirect', redirect: 'foo' }
      ]
    },
    // absolute redirect
    { path: '/absolute-redirect', redirect: '/bar' },
    // dynamic redirect, note that the target route to 
    // is available for the redirect function
    { path: '/dynamic-redirect/:id?',
      redirect: to => {
        const { hash, params, query } = to;
        if (query.to === 'foo') {
          return { path: '/foo', query: null };
        }
        if (hash === '#baz') {
          return { name: 'baz', hash: '' };
        }
        if (params.id) {
          return '/with-params/:id';
        } else {
          return '/bar';
        }
      }
    },
    // named redirect
    { path: '/named-redirect', redirect: { name: 'baz' }},

    // redirect with params
    { path: '/redirect-with-params/:id', redirect: '/with-params/:id' },

    // redirect with caseSensitive
    { path: '/foobar', component: Foobar, caseSensitive: true },

    // redirect with pathToRegexpOptions
    { path: '/FooBar', component: FooBar, pathToRegexpOptions: { sensitive: true }},

    // catch all redirect
    { path: '*', redirect: '/' }
  ]
});

new Vue({
  router,
  template: `
    <div id="app">
      <h1>Redirect</h1>
      <ul>
        <li><router-link to="/relative-redirect">
          /relative-redirect (redirects to /foo)
        </router-link></li>
        <li><router-link to="/relative-redirect?foo=bar">
          /relative-redirect?foo=bar (redirects to /foo?foo=bar)
        </router-link></li>
        <li><router-link to="/absolute-redirect">
          /absolute-redirect (redirects to /bar)
        </router-link></li>
        <li><router-link to="/dynamic-redirect">
          /dynamic-redirect (redirects to /bar)
        </router-link></li>
        <li><router-link to="/dynamic-redirect/123">
          /dynamic-redirect/123 (redirects to /with-params/123)
        </router-link></li>
        <li><router-link to="/dynamic-redirect?to=foo">
          /dynamic-redirect?to=foo (redirects to /foo)
        </router-link></li>
        <li><router-link to="/dynamic-redirect#baz">
          /dynamic-redirect#baz (redirects to /baz)
        </router-link></li>
        <li><router-link to="/named-redirect">
          /named-redirect (redirects to /baz)
        </router-link></li>
        <li><router-link to="/redirect-with-params/123">
          /redirect-with-params/123 (redirects to /with-params/123)
        </router-link></li>
        <li><router-link to="/foobar">
          /foobar
        </router-link></li>
        <li><router-link to="/FooBar">
          /FooBar
        </router-link></li>
        <li><router-link to="/not-found">
          /not-found (redirects to /)
        </router-link></li>
      </ul>
      <router-view class="view"></router-view>
    </div>
  `
}).$mount('#app');

6262742ede5bad0a084966364f6eed03.gif

2 别名

重定向的意思是,当用户访问 /a 时,URL 将会被替换成 /b,然后匹配路由为 /b,别名则是:当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。

其对应的路由配置为:

const router = new VueRouter({
  routes: [
    { path: '/a', component: A, alias: '/b' }
  ]
});

这样对用户(尤其是对 URL 敏感的用户)来说,就不会产生疑问和担心了,更多的样例如下:

import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

const Root = { template: '<div>root</div>' };
const Home = { template: '<div><h1>Home</h1><router-view></router-view></div>' };
const Foo = { template: '<div>foo</div>' };
const Bar = { template: '<div>bar</div>' };
const Baz = { template: '<div>baz</div>' };
const Default = { template: '<div>default</div>' };
const Nested = { template: '<router-view/>' };
const NestedFoo = { template: '<div>nested foo</div>' };

const router = new VueRouter({
  mode: 'history',
  base: __dirname,
  routes: [
    { path: '/root', component: Root, alias: '/root-alias' },
    { path: '/home', component: Home,
      children: [
        // absolute alias
        { path: 'foo', component: Foo, alias: '/foo' },
        // relative alias (alias to /home/bar-alias)
        { path: 'bar', component: Bar, alias: 'bar-alias' },
        // multiple aliases
        { path: 'baz', component: Baz, alias: ['/baz', 'baz-alias'] },
        // default child route with empty string as alias.
        { path: 'default', component: Default, alias: '' },
        // nested alias
        { path: 'nested', component: Nested, alias: 'nested-alias',
          children: [
            { path: 'foo', component: NestedFoo }
          ]
        }
      ]
    }
  ]
});

new Vue({
  router,
  template: `
    <div id="app">
      <h1>Route Alias</h1>
      <ul>
        <li><router-link to="/root-alias">
          /root-alias (renders /root)
        </router-link></li>
        <li><router-link to="/foo">
          /foo (renders /home/foo)
        </router-link></li>
        <li><router-link to="/home/bar-alias">
          /home/bar-alias (renders /home/bar)
        </router-link></li>
        <li><router-link to="/baz">
          /baz (renders /home/baz)
        </router-link></li>
        <li><router-link to="/home/baz-alias">
          /home/baz-alias (renders /home/baz)
        </router-link></li>
        <li><router-link to="/home">
          /home (renders /home/default)
        </router-link></li>
        <li><router-link to="/home/nested-alias/foo">
          /home/nested-alias/foo (renders /home/nested/foo)
        </router-link></li>
      </ul>
      <router-view class="view"></router-view>
    </div>
  `
}).$mount('#app');

2bf06b058cd0c426024abd53a0ae1892.gif

3 路由组件传参

在组件中使用 $route 会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了灵活性。

我们可以使用 props 将组件和路由解耦:

3.1 取代与 $route 的耦合

const User = {
  template: '<div>User {{ $route.params.id }}</div>'
};
const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User }
  ]
});

3.2 通过 props 解耦

const User = {
  props: ['id'],
  template: '<div>User {{ id }}</div>'
};
const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User, props: true },

    // 对于包含命名视图的路由,你必须分别为每个命名视图添加 props 选项:
    {
      path: '/user/:id',
      components: { default: User, sidebar: Sidebar },
      props: { default: true, sidebar: false }
    }
  ]
});

这样便可以在任何地方使用该组件,使得该组件更易于重用和测试。

3.3 布尔模式

如果 props 被设置为 trueroute.params 将会被设置为组件属性。

3.4 对象模式

如果 props 是一个对象,它会被按原样设置为组件属性,当 props 是静态的时候生效。

const router = new VueRouter({
  routes: [
    { path: '/promotion/from-newsletter', 
      component: Promotion, 
      props: { newsletterPopup: false } }
  ]
});

3.5 函数模式

我们可以创建一个函数返回 props:这样可以将参数转换成另一种类型,将静态值与基于路由的值结合等等。

const router = new VueRouter({
  routes: [
    { path: '/search', component: SearchUser, props: (route) => ({ query: route.query.q }) }
  ]
});

URL /search?q=vue 会将 {query: 'vue'} 作为属性传递给 SearchUser 组件。

尽可能保持 props 函数为无状态的,因为它只会在路由发生变化时起作用;如果我们需要状态来定义 props,那么就使用包装组件,这样 Vue 才可以对状态变化做出反应。

更多的例子如下:

import Vue from 'vue';
import VueRouter from 'vue-router';
import Hello from './Hello.vue';

Vue.use(VueRouter);

function dynamicPropsFn (route) {
  const now = new Date();
  return {
    name: (now.getFullYear() + parseInt(route.params.years)) + '!'
  };
}

const router = new VueRouter({
  mode: 'history',
  base: __dirname,
  routes: [
    // No props, no nothing
    { path: '/', component: Hello },
    // Pass route.params to props
    { path: '/hello/:name', component: Hello, props: true },
    // static values
    { path: '/static', component: Hello, props: { name: 'world' }},
    // custom logic for mapping between route and props
    { path: '/dynamic/:years', component: Hello, props: dynamicPropsFn },
    { path: '/attrs', component: Hello, props: { name: 'attrs' }}
  ]
});

new Vue({
  router,
  template: `
    <div id="app">
      <h1>Route props</h1>
      <ul>
        <li><router-link to="/">/</router-link></li>
        <li><router-link to="/hello/you">/hello/you</router-link></li>
        <li><router-link to="/static">/static</router-link></li>
        <li><router-link to="/dynamic/1">/dynamic/1</router-link></li>
        <li><router-link to="/attrs">/attrs</router-link></li>
      </ul>
      <router-view class="view" foo="123"></router-view>
    </div>
  `
}).$mount('#app');

06d486045d17a6891547858317173beb.gif

4 HTML5 History 模式

vue-router 默认 hash 模式 —— 使用 URL hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。

如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。

const router = new VueRouter({
  mode: 'history',
  routes: [...]
});

当使用 history 模式时,URL 就像正常的 url,例如 http://mysite.com/user/id,并没有那个有点扎眼的 # 存在。

不过这种模式要玩好,还需要后台配置支持;因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://oursite.com/user/id 就会返回 404,这就不好了。

所以呢,我们需要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是 app 依赖的页面。

4.1 后端配置例子

注意:下列示例假设在根目录服务这个应用。

如果想部署到一个子目录,我们需要使用 ="https://cli.http://vuejs.org/zh/config/#publicpath">Vue CLI 的 publicPath 选项 和相关的 router base property;还需要把下列示例中的根目录调整成为子目录(例如用 RewriteBase /name-of-your-subfolder/ 替换掉 RewriteBase /)。

(1) Apache

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  RewriteRule ^index.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule . /index.html [L]
</IfModule>

除了 mod_rewrite,我们也可以使用 FallbackResource

(2)nginx

location / {
  try_files $uri $uri/ /index.html;
}

(3)原生 Node.js

const http = require('http');
const fs = require('fs');
const httpPort = 80;

http.createServer((req, res) => {
  fs.readFile('index.htm', 'utf-8', (err, content) => {
    if (err) {
      console.log('We cannot open "index.htm" file.');
    }

    res.writeHead(200, {
      'Content-Type': 'text/html; charset=utf-8'
    });

    res.end(content);
  })
}).listen(httpPort, () => {
  console.log('Server listening on: http://localhost:%s', httpPort);
});

(4)基于 Node.js 的 Express

对于 Node.js/Express,请考虑使用 <a href="https://github.com/bripkens/connect-history-api-fallback">connect-history-api-fallback 中间件。

(5)Internet Information Services (IIS)

  1. 安装 IIS UrlRewrite
  2. 在网站根目录中创建一个 web.config 文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="Handle History Mode and custom 404/500" stopProcessing="true">
          <match url="(.*)" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Rewrite" url="/" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

(6)Caddy

Caddyfile 当中加入:

rewrite {
    regexp .*
    to {path} /
}

(7)Firebase 主机

firebase.json 中加入:

{
  "hosting": {
    "public": "dist",
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}

4.2 警告

这里要特别留意,在这么做以后,服务器就不再返回 404 错误页面,因为对于所有路径都会返回 index.html 文件;为了避免这种情况,我们需要在 Vue 应用里面覆盖所有的路由情况,然后在给出一个 404 页面。

const router = new VueRouter({
  mode: 'history',
  routes: [
    { path: '*', component: NotFoundComponent }
  ]
});

或者,如果我们使用 Node.js 服务器,就可以用服务端路由匹配到来的 URL,并在没有匹配到路由的时候返回 404,以实现回退。

更多详情请查阅 Vue 服务端渲染文档。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值