美文网首页
Vue Router的应用

Vue Router的应用

作者: CarlosLynn | 来源:发表于2023-05-31 15:55 被阅读0次

安装

NPM

npm install vue-router

Vue CLI

如果你有一个正在使用 Vue CLI的项目,你可以以项目插件的形式添加 Vue Router。CLI 可以生成上述代码及两个示例路由。它也会覆盖你的 App.vue,因此请确保在项目中运行以下命令之前备份这个文件:

vue add router

这里我们使用第二中方式安装,执行该命令后结果如下

C:\Gitee\vue-route-demo>vue add router

📦  Installing @vue/cli-plugin-router...

+ @vue/cli-plugin-router@5.0.8
updated 1 package in 4.418s

94 packages are looking for funding
  run `npm fund` for details

✔  Successfully installed plugin: @vue/cli-plugin-router

? Use history mode for router? (Requires proper server setup for index fallback in production) No

🚀  Invoking generator for @vue/cli-plugin-router...
📦  Installing additional dependencies...

added 1 package from 1 contributor in 4.568s

94 packages are looking for funding
  run `npm fund` for details

✔  Successfully invoked generator for plugin: @vue/cli-plugin-router

无论用何种方式,安装好以后, 在package.json中就可以看到安装的vue-router的版本了

  "dependencies": {
    "vue-router": "^3.5.1"
  },

基础

起步

用 Vue.js + Vue Router 创建单页应用,感觉很自然:使用 Vue.js ,我们已经可以通过组合组件来组成应用程序,当你要把 Vue Router 添加进来,我们需要做的是,将组件 (components) 映射到路由 (routes),然后告诉 Vue Router 在哪里渲染它们。下面是个基本例子:

  • 创建路由组件:
    我们创建两个组件, 一个首页, 一个关于页面。
    首页
<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png" />
    <h2>这是Home主页</h2>
    <div>欢迎来到home主页</div>
    <button @click="goBack">返回上一级</button>
  </div>
</template>
<script>
export default {
  name: "HomeView",
  methods: {
    goBack() {
      window.history.length > 1 ? this.$router.go(-1) : this.$router.push("/");
    },
  },
};
</script>

关于页面

<template>
  <div class="about">
    <h2>关于页面</h2>
   <div>欢迎来到关于页面</div>
  </div>
</template>
  • 配置路由映射。 即:组件和路由的关系
    组件创建好了, 接下来要构建组件和路由的关系。 构建路由关系,我们通常定义在router/index.js文件
import Vue from 'vue'
import VueRouter from 'vue-router'

// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter)
Vue.use(VueRouter)

// 1. 定义 (路由) 组件。
// 可以从其他文件 import 进来

import HomeView from '../views/HomeView.vue'

// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  }
]

// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
  routes
})
export default router
  • 使用路由, 通过和来展示组件
    现在组件有了, 路有关系也有了。 那么接下来就是要有个入口来展示组件或者路由了。 我们的入口只有一个, 那就是App.vue, 所以, 我们直接在这里定义两个入口即可。
<template>
  <div id="app">
    <nav>
      <!-- 使用 router-link 组件来导航. -->
      <!-- 通过传入 `to` 属性指定链接. -->
      <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </nav>
    <!-- 路由出口 -->
    <!-- 路由匹配到的组件将渲染在这里 -->
    <router-view />
  </div>
</template

main.js中启动

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
Vue.config.productionTip = false;
// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
new Vue({
  router,
  render: (h) => h(App),
}).$mount("#app");
// 现在,应用已经启动了!

通过注入路由器,我们可以在任何组件内通过 this.$router访问路由器,也可以通过 this.$route访问当前路由:

<script>
export default {
  methods: {
    goBack() {
      window.history.length > 1 ? this.$router.go(-1) : this.$router.push("/");
    },
  },
};
</script>

路由的默认配置
现在我们进入首页显示的只有导航信息, 在页面必须点击某一个按钮,才能渲染出对应组件的内容。通常我们会有一个默认组件的展示。 否则首页内容就是空的了。如何设置默认展示的路由呢?

在路由表中增加一个重定向路由

  {
    path: "/",
    redirect: "/home",
  },

这是我们进入页面将默认选中首页并展示其内容

动态路由匹配

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”来达到这个效果:
下面就以用户为例, 来实现动态路由
创建一个UserView.vue

<template>
  <div class="about">
    <h2>用户界面</h2>
    <div>欢迎你来到用户界面</div>
  </div>
</template>
<script>
export default {
  name: "UserView",
};
</script>

添加路由映射关系

const routes = [
  // 动态路径参数 以冒号开头
  { path: "/user/:userId", component: UserView},
];

这里path使用了:userId占位, 表示这里是一个占位符, 将被真实的userId替换. 后面在路由传递的时候变量需要和这里保持一致.

使用user路由
当我们动态路由到user的时候, 需要使用变量userId, 我们可以在data中定义一个变量

<template>
  <div id="app">
    <nav>
      <router-link to="/home">首页</router-link> |
      <router-link to="/about">关于</router-link>|
      <router-link v-bind:to="'/user/' + userId">用户</router-link>
    </nav>
    <router-view />
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      userId: "721",
    };
  },
};
</script>

在上面使用了v-bind:to="’/user/’+userId"路由到/user/:userId, 而userId是我们在组件中定义的一个变量.
我们看到当点击用户的时候, 浏览器的url路径变为了/user/721.

http://10.133.46.6:8080/#/user/721

将参数传递到组件

我们希望在user组件中显示, 欢迎{{用户名}}来到用户页面, 如何实现呢?
要想实现这个效果, 需要使用到this.$route对象. 这是获取路由信息的对象
一个“路径参数”使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到 this.$route.params,可以在每个组件内使用。于是,我们可以更新 User 的模板,输出当前用户的 ID:

<template>
  <div>
    <h2>用户界面</h2>
    <div>欢迎{{ userId }},来到用户界面</div>
  </div>
</template>

<script>
export default {
  name: "UserView",
  data() {
    return {
      userId: this.$route.params.userId,
    };
  },
};
</script>

你可以在一个路由中设置多段“路径参数”,对应的值都会设置到$route.params 中。例如:

模式 匹配路径 $route.params
/user/:username /user/evan { username: 'evan' }
/user/:username/post/:post_id /user/evan/post/123 { username: 'evan', post_id: '123' }

除了$route.params 外,$route对象还提供了其它有用的信息,例如,$route.query (如果 URL 中有查询参数)、$route.hash 等等。你可以查看 API 文档 的详细说明。

响应路由参数的变化

复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化) $route 对象:

const User = {
  template: '...',
  watch: {
    $route(to, from) {
      // 对路由变化作出响应...
    }
  }
}

或者使用 2.2 中引入的 beforeRouteUpdate 导航守卫

const User = {
  template: '...',
  beforeRouteUpdate(to, from, next) {
    // react to route changes...
    // don't forget to call next()
  }
}

捕获所有路由或 404 Not found 路由

常规参数只会匹配被 / 分隔的 URL 片段中的字符。如果想匹配任意路径,我们可以使用通配符 (*):

{
  // 会匹配所有路径
  path: '*'
}
{
  // 会匹配以 `/user-` 开头的任意路径
  path: '/user-*'
}

当使用通配符路由时,请确保路由的顺序是正确的,也就是说含有通配符的路由应该放在最后。路由 { path: '*' } 通常用于客户端 404 错误。如果你使用了History 模式,请确保正确配置你的服务器

当使用一个通配符时,$route.params 内会自动添加一个名为 pathMatch 参数。它包含了 URL 通过通配符被匹配的部分:

// 给出一个路由 { path: '/user-*' }
this.$router.push('/user-admin')
this.$route.params.pathMatch // 'admin'
// 给出一个路由 { path: '*' }
this.$router.push('/non-existing')
this.$route.params.pathMatch // '/non-existing'

匹配优先级

有时候,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:路由定义得越早,优先级就越高。

嵌套路由

实际生活中的应用界面,通常由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也按某种结构对应嵌套的各层组件,例如

/user/foo/profile                     /user/foo/posts
+------------------+                  +-----------------+
| User             |                  | User            |
| +--------------+ |                  | +-------------+ |
| | Profile      | |  +------------>  | | Posts       | |
| |              | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+

借助 vue-router,使用嵌套路由配置,就可以很简单地表达这种关系。
接着上节创建的 app:

<div id="app">
  <router-view></router-view>
</div>

这里的 <router-view> 是最顶层的出口,渲染最高级路由匹配到的组件。同样地,一个被渲染组件同样可以包含自己的嵌套 <router-view>。
我们的路由映射规则是: 一个路径映射一个组件. 访问两个路径, 会分别渲染两个组件.
下面来实现嵌套路由,
第一步: 创建组件,创建两个组件
HomeBanner.vue组件

<template>
  <div>
    <h2>首页banner图</h2>
    <ul>
      <li>banner图1</li>
      <li>banner图2</li>
      <li>banner图3</li>
      <li>banner图4</li>
    </ul>
  </div>
</template>
  <script>
export default {
  name: "HomeBanner",
};
</script>
  
  <style scoped>
</style>

HomeNews.vue组件:

<template>
  <div>
    <h2>首页新闻</h2>
    <ul>
      <li>第一条新闻</li>
      <li>第二条新闻</li>
      <li>第三条新闻</li>
      <li>第四条新闻</li>
    </ul>
  </div>
</template>
  
  <script>
export default {
  name: "HomeNews",
};
</script>
  
  <style scoped>
</style>
  

第二步: 创建组件路由
我们要在Home也添加子路由, 需要在路由里面增加一个children属性配置.

{
    path: "/home",
    name: "home",
    component: HomeView,
    children: [
      {
        path: "",
        redirect: "HomeNew",
      },
      {
        path: "HomeNew", //注意: 这里面没有/
        component: () => import("../components/HomeNews"),
      },
      {
        path: "HomeBanner",
        component: () => import("../components/HomeBanner"),
      },
    ],
  }

里面的路径依然是有两个部分:

一个是path路由路径: 这里需要注意的是,不需要在路径名的前面加/
另一个是component: 指定组件名称
第三步: 增加
我们要在Home页面展示子组件, 因此需要将子组件的展示放在页面上

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png" />
    <h2>这是Home主页</h2>
    <div>欢迎来到home主页</div>
    <button @click="goBack">返回上一级</button>
    <nav>
      <router-link to="/home/homeNew">新闻</router-link>
      <router-link to="/home/homeBanner">图片</router-link>
    </nav>
    <router-view></router-view>
  </div>
</template>

要注意,以 / 开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。
你会发现,children 配置就是像 routes 配置一样的路由配置数组,所以呢,你可以嵌套多层路由。

编程式的导航

除了使用 <router-link> 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
router.push(location, onComplete?, onAbort?)
注意:在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push
想要导航到不同的 URL,则使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。
当你点击 <router-link> 时,这个方法会在内部调用,所以说,点击 <router-link :to="..."> 等同于调用 router.push(...)

  • 声明式 <router-link :to="...">
  • 编程式router.push(...)
    该方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如:
// 字符串
router.push('home')

// 对象
router.push({ path: 'home' })

// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})

// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})

注意:如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path:

const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 这里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user

在 2.2.0+,可选的在 router.pushrouter.replace 中提供 onCompleteonAbort 回调作为第二个和第三个参数。这些回调将会在导航成功完成 (在所有的异步钩子被解析之后) 或终止 (导航到相同的路由、或在当前导航完成之前导航到另一个不同的路由) 的时候进行相应的调用。在 3.1.0+,可以省略第二个和第三个参数,此时如果支持 Promise,router.pushrouter.replace 将返回一个 Promise。

注意: 如果目的地和当前路由相同,只有参数发生了改变 (比如从一个用户资料到另一个 /users/1 -> /users/2),你需要使用 beforeRouteUpdate 来响应这个变化 (比如抓取用户信息)。

router.replace(location, onComplete?, onAbort?)

router.push 很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。

  • 声明式 <router-link :to="..." replace>
  • 编程式 router.replace(...)
    router.go(n)
    这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似
    window.history.go(n)
    例子
// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)

// 后退一步记录,等同于 history.back()
router.go(-1)

// 前进 3 步记录
router.go(3)

// 如果 history 记录不够用,那就默默地失败呗
router.go(-100)
router.go(100)

操作 History

你也许注意到 router.pushrouter.replacerouter.gowindow.history.pushStatewindow.history.replaceStatewindow.history.go 好像, 实际上它们确实是效仿 window.history API 的。

因此,如果你已经熟悉 Browser History APIs (opens new window),那么在 Vue Router 中操作 history 就是超级简单的。

还有值得提及的,Vue Router 的导航方法 (pushreplacego) 在各类路由模式 (historyhashabstract) 下表现一致。

命名路由

有时候,通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。

{
      path: '/user/:userId',
      name: 'user',
      component: User
}

要链接到一个命名路由,可以给 router-link 的 to 属性传一个对象:

<router-link :to="{ name: 'user', params: { userId: 123 }}">用户</router-link>

这跟代码调用 router.push() 是一回事:

router.push({ name: 'user', params: { userId: 123 } })

这两种方式都会把路由导航到 /user/123 路径。

命名视图

有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。

<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>

一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置 (带上 s):

const router = new VueRouter({
  routes: [
    {
      path: '/',
      components: {
        default: Foo,
        a: Bar,
        b: Baz
      }
    }
  ]
})

嵌套命名视图

我们也有可能使用命名视图创建嵌套视图的复杂布局。这时你也需要命名用到的嵌套 router-view 组件。我们以一个设置面板为例:

/settings/emails                                       /settings/profile
+-----------------------------------+                  +------------------------------+
| UserSettings                      |                  | UserSettings                 |
| +-----+-------------------------+ |                  | +-----+--------------------+ |
| | Nav | UserEmailsSubscriptions | |  +------------>  | | Nav | UserProfile        | |
| |     +-------------------------+ |                  | |     +--------------------+ |
| |     |                         | |                  | |     | UserProfilePreview | |
| +-----+-------------------------+ |                  | +-----+--------------------+ |
+-----------------------------------+                  +------------------------------+
  • Nav 只是一个常规组件。
  • UserSettings 是一个视图组件。
  • UserEmailsSubscriptions、UserProfile、UserProfilePreview 是嵌套的视图组件。
    注意:我们先忘记 HTML/CSS 具体的布局的样子,只专注在用到的组件上。
    UserSettings 组件的 <template> 部分应该是类似下面的这段代码:
<!-- UserSettings.vue -->
<div>
  <h1>User Settings</h1>
  <NavBar/>
  <router-view/>
  <router-view name="helper"/>
</div>

然后你可以用这个路由配置完成该布局:

{
  path: '/settings',
  // 你也可以在顶级路由就配置命名视图
  component: UserSettings,
  children: [{
    path: 'emails',
    component: UserEmailsSubscriptions
  }, {
    path: 'profile',
    components: {
      default: UserProfile,
      helper: UserProfilePreview
    }
  }]
}

重定向和别名

重定向

重定向也是通过 routes 配置来完成,下面例子是从 /a 重定向到 /b:

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 重定向的 字符串路径/路径对象
    }}
  ]
})

注意导航守卫并没有应用在跳转路由上,而仅仅应用在其目标上。在下面这个例子中,为 /a 路由添加一个 beforeEnter 守卫并不会有任何效果。

别名

“重定向”的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b,那么“别名”又是什么呢?
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。

上面对应的路由配置为:

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

“别名”的功能让你可以自由地将 UI 结构映射到任意的 URL,而不是受限于配置的嵌套路由结构。

路由组件传参

vue-router参数传递有两种方式: 第一种是: param的方式. 第二种是: query的方式

  • param方式
    创建一个MapView.vue组件
<template>
  <div>
    <h2>地图页面</h2>
    <div>欢迎来到地图页面</div>
  </div>
</template>
<script>
export default {
  name: "Map",
};
</script>

创建动态路由的时候, 定义变量

  {
    path: "/map/:city",
    name: "map",
    component: () => import("../views/MapView.vue"),
  },

我们定义了一个map/:city, 这样的动态路由. 路由可以是/map/beijng, 或者/user/shanghai
在App.vue中定义动态路由跳转的组件

<router-link v-bind:to="'/map/' + city" replace active-class="active"
        >地图</router-link
      >|
<script>
export default {
  name: "App",
  data() {
    return {
      userId: "721",
      city: "beijing",
    };
  },
};
</script>

修改MapView.vue组件
首先, 在MapView.vue脚本中获取传递过来的路由参数. 我们使用[this.$route.params.变量名]的方式获取路径参数

<template>
  <div>
    <h2>地图页面</h2>
    <div>欢迎来到{{ city }}地图页面</div>
    <div>{{ $route.params.city }}</div>
  </div>
</template>
<script>
export default {
  name: "Map",
  data() {
    return {
      city: this.$route.params.city,
    };
  },
};
</script>

以上是使用参数的方式传递变量.

  • query方式
    下面来举个案例:
    创建一个组件ProfileView.vue
<template>
  <div>
    <h2>这是一个Profile组件</h2>
  </div>
</template>
  <script>
export default {
  name: "Profile",
};
</script>
<style scoped>
</style>
  

配置路由

  {
    path: "/profile",
    component: () => import("../views/ProfileView.vue"),
  },

渲染组件

      <!-- 配置动态路由 -->
      <router-link
        v-bind:to="{
          path: '/profile',
          query: { name: 'lily', sex: '男', age: 12 },
        }"
        >档案</router-link>

来看一下效果


image.png

我们看到路径上带了?参数

http://10.133.46.6:8080/profile?name=lily&sex=%E7%94%B7&age=12

组件中获取参数

<template>
  <div>
    <h2>这是一个Profile组件</h2>
    <h4>{{ $route.query }}</h4>
    <h4>{{ $route.query.name }}</h4>
    <h4>{{ $route.query.age }}</h4>
    <h4>{{ $route.query.sex }}</h4>
  </div>
</template>

查看效果


image.png
  • 通过 props 进行传递
    在组件中使用 $route会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了其灵活性。
    取代与 $route 的耦合,通过 props 解耦
    使用 props 将组件和路由解耦:
  1. 布尔模式
    案例:
    创建StudentView.vue
    props: ["id"]用来接收收路由传来的参数
<template>
  <div>
    <h2>学生页面</h2>
    <div>欢迎{{ id }}来到学生页面</div>
  </div>
</template>

<script>
export default {
  name: "Student",
  props: ["id"],
};
</script>

配置路由:
当 props 设置为 true 时,route.params 将被设置为组件的 props

  {
    path: "/student/:id",
    component: () => import("../views/StudentView.vue"),
    props: true,
  },

渲染组件:
这里为了简化,写死传递了593066063作为id.

<router-link to="/student/593066063">学生</router-link>

看一下效果


image.png

2.对象模式
如果 props 是一个对象,它会被按原样设置为组件属性。当 props 是静态的时候有用。
举例如下:
创建VideoView.vue组建

<template>
  <div>
    <h2>视频页面</h2>
    <div>欢迎来到[{{ name }}]视频页面</div>
  </div>
</template>

<script>
export default {
  name: "Video",
  props: {
    name: {
      type: String,
      default: "Vue",
    },
  },
};
</script>

定义路由并传递参数

  {
    path: "/video",
    component: () => import("../views/VideoView.vue"),
    props: { name: "逃学威龙" },
  },

增加视图渲染

<router-link to="/video">视频</router-link>

查看效果图


image.png

函数模式

你可以创建一个函数返回 props。这样你便可以将参数转换成另一种类型,将静态值与基于路由的值结合等等。
举例说明:
定义组件

<template>
  <div>
    <h2>图片页面</h2>
    <div>欢迎来到[{{ name }}]图片页面</div>
  </div>
</template>

<script>
export default {
  name: "Image",
  props: {
    name: {
      type: String,
      default: "Vue",
    },
  },
};
</script>

配置路由
定义路由中的函数:

const dynamicPropsFn = (route) => {
  return { name: route.query.type + "of png" };
};

路由配置

  {
    path: "/image",
    component: () => import("../views/ImageView.vue"),
    props: dynamicPropsFn,
  },

渲染组件

<router-link to="/image?type=girl">图片</router-link>

当 URL 为/image?type=girl时, 将传递 {name: ‘girl of girl’} 作为 props 传给组件。
效果如下

image.png

History 模式

  1. 修改静态路由的模式为history
    我们之前都是采用hash的方式来静态路由跳转的, 但hash方式有一个缺点, 即带有#
    例如:我们跳转都Home页, 他的路径是
http://localhost:8080/#/home
http://10.133.46.6:8080/#/user/123

带有一个#, 这不符合我们通常路径的使用方法,所以,我们可以考虑将其替换为history的模式。 如何替换呢? 在router/index.js文件中

const router = new VueRouter({
  routes,
  mode: "history",
});

我点击页面切换则没有#

http://10.133.46.6:8080/about
http://10.133.46.6:8080/map
http://10.133.46.6:8080/user/123
image.png

进阶

导航守卫

  • 这里的导航,指的就是路由的跳转或者取消跳转
  • 守卫指的是: 有很多钩子方法, 允许我们在某一个过程中植入代码逻辑.
  • 常见的导航守卫有:
    全局导航守卫(包括三个: 全局前置守卫, 全局解析守卫, 全局后置守卫), 路由独享导航守卫, 组件内的守卫
    • 全局前置守卫

可以使用 router.beforeEach 注册一个全局前置守卫:

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // ...
})

当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。
每个守卫方法接收三个参数:

  • to: Route: 即将要进入的目标 路由

  • from: Route: 当前导航正要离开的路由

  • next: Function: 一定要调用该方法来 resolve 这个钩子。
    也就是说, 代码这至少是这样的

router.beforeEach((to, from, next) =>{
    next();
})

案例:全局导航守卫的方式更新title属性
在路由index.js文件中增加元数据属性, 并设置title属性值

const routes = [
  {
    path: "/",
    name: "home",
    component: HomeView,
    children: [
      {
        path: "HomeNew", //注意: 这里面没有/
        component: () => import("../components/HomeNews"),
      },
      {
        path: "HomeBanner",
        component: () => import("../components/HomeBanner"),
      },
    ],
    meta: {
      title: "首页",
    },
  },
  {
    path: "/about",
    name: "about",
    component: () => import("../views/AboutView.vue"),
    meta: {
      title: "关于",
    },
  },
  // 动态路径参数 以冒号开头
  {
    path: "/user/:userId",
    name: "user",
    component: UserView,
    meta: {
      title: "用户",
    },
  },
  {
    path: "/map/:city",
    name: "map",
    component: () => import("../views/MapView.vue"),
    meta: {
      title: "地图",
    },
  },
  {
    path: "/profile",
    component: () => import("../views/ProfileView.vue"),
    meta: {
      title: "档案",
    },
  },
  {
    path: "/student/:id",
    component: () => import("../views/StudentView.vue"),
    props: true,
    meta: {
      title: "学生",
    },
  },
  {
    path: "/video",
    component: () => import("../views/VideoView.vue"),
    props: { name: "逃学威龙" },
    meta: {
      title: "视频",
    },
  },
  {
    path: "/image",
    component: () => import("../views/ImageView.vue"),
    props: dynamicPropsFn,
    meta: {
      title: "图片",
    },
  },
];

后面在全局导航路由中设置title属性

router.beforeEach((to, from, next) => {
  console.log(to);
  console.log(from);
  document.title = to.matched[0].meta.title;
  next();
});

效果图如下:


image.png
  • 全局解析守卫

在 2.5.0+ 你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。

  • 全局后置钩子

你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:

router.afterEach((to, from) => {
  // ...
})
  • 路由独享的守卫

你可以在路由配置上直接定义 beforeEnter 守卫:

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

这些守卫与全局前置守卫的方法参数是一样的。

  • 组件内的守卫

最后,你可以在路由组件内直接定义以下路由导航守卫:

  • beforeRouteEnter
  • beforeRouteUpdate (2.2 新增)
  • beforeRouteLeave
const Foo = {
  template: `...`,
  beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}

beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。

不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。

beforeRouteEnter (to, from, next) {
  next(vm => {
    // 通过 `vm` 访问组件实例
  })
}

注意 beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对于 beforeRouteUpdate 和 beforeRouteLeave 来说,this 已经可用了,所以不支持传递回调,因为没有必要了。

beforeRouteUpdate (to, from, next) {
  // just use `this`
  this.name = to.params.name
  next()
}

这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。

beforeRouteLeave (to, from, next) {
  const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
  if (answer) {
    next()
  } else {
    next(false)
  }
}
  • 完整的导航解析流程

1.导航被触发。
2.在失活的组件里调用 beforeRouteLeave 守卫。
3.调用全局的 beforeEach 守卫。
4.在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
5.在路由配置里调用 beforeEnter。
6.解析异步路由组件。
7.在被激活的组件里调用 beforeRouteEnter。
8.调用全局的 beforeResolve 守卫 (2.5+)。
9.导航被确认。
10.调用全局的 afterEach 钩子。
11.触发 DOM 更新。
12.调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

相关文章

  • qiankun_Demo实践

    主子应用对技术栈的选择 主应用:Vue + router(history)子应用:Vue + router(his...

  • 2-9 vue-router

    vue-router vue-router 用 Vue.js + vue-router 创建单页应用,是非常简单的...

  • Vue杂记

    vue应用结构 vue-router 是占位符,放在需要显示...

  • vue2.0 vue-router

    vue-router 用 Vue.js + vue-router 创建单页应用,是非常简单的。使用 Vue.js ...

  • vue-router 配置路由

    vue-router 配置路由 用 Vue.js + vue-router 创建单页应用,是非常简单的。使用 Vu...

  • cnode社区

    面试要点:(单页应用重点在vue-router) 单页应用,页面只有一个 APP组件; vue-router实现页...

  • vue 路由的基本配置

    路由 如果需要使用 vue router 驱动单页面应用,那就App.vue 添加 ...

  • Vue-router

    简介:vue-router 是 vue 官方提供的一套 路由插件,能够帮我们实现单页面应用。 vue-router...

  • vue路由

    vue路由--- SPA应用,单页面应用vue-resouce 交互vue-router 路由根据不同url地址...

  • Vue_Router

    Vue_Router Vue Router 和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。根据用...

网友评论

      本文标题:Vue Router的应用

      本文链接:https://www.haomeiwen.com/subject/qhojedtx.html