十四、使用 Vue Router 开发单页应用(3)
创始人
2024-03-17 06:54:35
0

本章概要

  • 命名路由
  • 命名视图
  • 编程式导航
  • 传递 prop 到路由组件
  • HTML 5 history 模式

14.5 命名路由

有时通过一个名称来标识路由会更方便,特别是在链接到路由,或者执行导航时。可以在创建 Router 实例时,在routes 选项中为路由设置名称。
修改 router 目录下的 index.js ,为路由定义名字。如下:

import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '@/components/Home'
import News from '@/components/News'
import Books from '@/components/Books'
import Videos from '@/components/Videos'
import Book from '@/components/Book'
import books from '../assets/books'export default createRouter({history: createWebHashHistory(),routes: [{path: '/',redirect:{name:'news'}},{path: '/news',name:'news',component: News,},{path: '/books',name:'books',component: Books,children: [{ path: '/book/:id',name:'book', component: Book }]},{path: '/videos',name:'videos',component: Videos,},]
})

在根路径(/)的配置中,使用 redirect 参数将对该路径的访问重定向到命名的路由 news 上。当访问 http://localhost:8080/ 时,将直接跳转到 News 组件。
以下是重定向的另外两种配置方式:

{path:'/'// 指定目标路径redirect:'/news'
},
{// /search/screens -> /search?q=screenspath:'search/:searchText',redirect:to => {return { path:'/search',query:{q:to.params.searchText} }}
}

修改 App.vue ,在设置导航链接时使用命名路由。如下:


注意:to 属性的值现在是表达式,因此需要使用 v-bind 指令

修改 Books.vue ,也使用命名路由。如下:


接下来可以再次运行项目,观察效果,测试效果和前面的例子完全一样。
在路由配置中,还可以为某个路径取个别名,例如:

routes:[{ path:'/a', component: A, alias:'/b' }
]

“/a” 的别名是“/b”,当用户访问 “/b”时,URL会保持为“/b”,但是路由匹配是“/a”,就想用户正在访问“/a”一样。
别名的功能可以自由地将 UI 结构映射到任意的 URL ,而不受限于配置的嵌套路由结构。
注意别名和重定向的区别,对于重定向而言,当用户访问“/a”时,URL 会被替换成“/b”,然后匹配路由为“/b”。

14.6 命名视图

有时需要同时(同级)显示多个视图,而不是嵌套展示。例如,创建一个布局,有 header(头部)、sidebar(侧边栏)和 main(主内容) 3个视图,这时命名视图就派上用场了。可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。例如:




没有设置名字的 router-view,默认为 default。
一个视图使用一个组件渲染,因此对于同一个路由,多个视图就需要多个组件。在配置路由时,使用 components 选项。代码如下:

const router = createRouter({history:createWebHashHistory(),routes:[{path:'/',components:{default:Main,header:Header,sidebar:Sidebar}}]
})

可以使用带有嵌套视图的命名视图创建复杂的布局,这时也需要命名用到的嵌套 router-view 组件。
下面看一个设置面板的示例,如下:
在这里插入图片描述

Nav 是一个常规组件,UserSettings 是一个父视图组件,UserEmailsSubscriptions、UserProfile 和 UserProfilePreview 是嵌套的视图组件。
UserSettings 组件的模板代码类似如下形式。


User Settings

其它 3 个 组件的模板代码如下:


UserEmails Subscriptions

Edit your profile

Preview of your profile

在路由配置中按上述布局进行配置。如下:

{path:'/settings',component:UserSettings,children:[{path:'emails',component:UserEmailsSubscriptions},{path:'profile',components:{component:{default:UserProfile,helper:UserProfilePreview}}}]
}

继续例子,将图书详情信息修改为与 Books 视图统计显示。
编辑 App.vue ,添加一个命名视图。如下:


修改 router 目录下的 index.js 文件,删除 Books 组件的嵌套路由配置,将 Book 组件路由设置为顶层路由。如下:

import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '@/components/Home'
import News from '@/components/News'
import Books from '@/components/Books'
import Videos from '@/components/Videos'
import Book from '@/components/Book'
import books from '../assets/books'export default createRouter({history: createWebHashHistory(),routes: [{path: '/',redirect: {name: 'news'}},{path: '/news',name: 'news',component: News,},{path: '/books',name: 'books',component: Books},{path: '/book/:id',name: 'book',components: { bookDetail: Book }},{path: '/videos',name: 'videos',component: Videos,},]
})

至于 Books 组件内的 router-view ,删不删除都不影响 Book 组件的渲染。为了代码的完整性,可以将这些无用的代码注释删除。

Book.vue


运行项目,可以看到当单击一个图书链接时,图书的详细信息在 Books 视图同级显示了,如下:
在这里插入图片描述

14.7 编程式导航

除了使用 router-link 创建 a 标签定义导航链接,还可以使用 router 的实例方法,通过编写代码来导航。
要导航到不同的 URL ,可以使用 router 实例的 push() 方法,router.push() 方法会向 history 栈添加一个新的记录,所以当用户单击浏览器后退按钮时,将回到之前的 URL 。
当单击 router-link 时,router.push() 方法会在内部调用,换句话说,单击 router-link :to=“…” 等同于调用 router.push() 方法。
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'}})
// 使用 hash,结果是 /about#team
router.push({path:'/about',hash:'#team'})

需要注意的是,如果提供了 push,params 会被忽略。那么对于 /book/:id 这种形式的路径调用 router.push() 的方式也需要改变。一种是通过命名路由,;一种是在 path 中提供带参数的完整路径。如下:

const id = 1;
// /book/1
router.push({ name:'book',params:{id:book.id} })
// /book/1
router.push({ path:`book/${id}` })

router.push() 方法和所有其他的导航方法都返回一个 Promise ,允许等待直到导航完整,并知道结果是成功还是失败。
继续前面的例子,修改 Books.vue ,用 router.push() 方法替换 router-link 。如下:


说明:

  • 在组件实例内部,可以通过 this.router 访问路由实例,进而调用 this.router.push() 方法。
  • this.router 表示全局的路由对象,包含了用于路由跳转的方法,其属性 currentRouter 可以获取当前路由对象;this.route 表示当前路由对象,每一个路由都有一个 route 对象,可以获取对应的 name、path、params、query 等属性。

replace() 方法对应的声明式路由跳转为 《router-link :to=“…” replace》。
也可以在调用 push() 方法时,在位置对象中指定属性 replace:true 。如下:

router.push({ path:'/home',replace:true })
// 相当于
router.replace({ path:'/home' })

replace() 方法与 push() 方法用法相同,此处不再赘述。
与 window.history 对象的 forward() 、back() 、go() 方法对应的 router 实例的方法如下:

router.forward()
router.back()
router.go(n)

14.8 传递 prop 到路由组件

在组件中使用 route 会导致与路由的紧密耦合,这限制了组件的灵活性,因为它只能在某些 URL 上使用。虽然这并不一定是坏事,但是可以用一个 props 选项来解耦。如下:

const User = {template:'
User {{ $route.params.id }}
' } const routes = [{ path:'/user/id',component:User }]

可以为 User 组件,来避免硬编码 route.params.id。修改后的代码如下:

const User = {props:[ 'id' ],template:'
User{{ id }}
' } const routes = [{ path:'/user/id',component:User,props:true }]

在配置路由时,新增一个 props 选项,将它的值设置为 true 。当路由到 User 组件时,会自动获取 route.params.id 的值作为 User 组件的 id prop 的值。
对于带有命名视图的路由,必须为每个命名视图定义 props 选项。如下:

const routes = [{path:'/user/:id',component:{default:User,sidebar:Sidebar},props:{default:true,sidebar:false}}
]

当props 是一个对象时,它将按原样设置为组件 props ,这在 props 是静态的时候很有用。如下:

const routes = [{path:'promotion/from-newsletter',component:Promotion,props:{newsletterPopup:false}}
]

也可以创建一个返回 props 的函数,可以将参数转换为其他类型,或者将静态值与基于路由的值相结合。如下:

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

访问 URL:/search?q=vue ,会将 {query:‘vue’} 作为prop 传递给 SearchUser 组件。
尽量保持 props 函数为无状态的,因为它只在路由更改时计算。

14.9 HTML 5 history 模式

前面的例子中使用的是 hash 模式,该模式是通过调用 createWebHashHistory() 函数创建的,这会在 URL 中使用 “#” 标识要跳转目标的路径,如果你觉得这样的 URL 很难看,影响心情,那么可以使用 HTML 5 history 模式。
HTML 5 history 模式是通过调用 createWebHistory() 函数创建的。如下:

import { createRouter,createWebHistory } from 'vue-router'
const router = createRouter({history:createWebHistory(),routes:[// ...]
})

继续前面的例子,修改 router 目录下的 index.js 文件,将路由改为 HTML 5 history 模式。如下:

import { createRouter, createWebHistory } from 'vue-router'
// import Home from '@/components/Home'
import News from '@/components/News'
import Books from '@/components/Books'
import Videos from '@/components/Videos'
import Book from '@/components/Book'
// import books from '../assets/books'export default createRouter({history: createWebHistory(),routes: [{path: '/',redirect: {name: 'news'}},{path: '/news',name: 'news',component: News,},{path: '/books',name: 'books',component: Books},{path: '/book/:id',name: 'book',components: {bookDetail: Book},},{path: '/videos',name: 'videos',component: Videos,},]
})

再次运行项目,所有的 URL 都没有“#”了。如下:
在这里插入图片描述

不过 history 模式也有一个问题,当浏览器地址栏中直接输入 URL 或刷新页面时,因为该 URL 是正常的 URL,所以浏览器会解析该 URL 向服务器发起请求,如果服务器没有针对该 URL 的响应,就会出现 404 错误。

在 HTML 5 history 模式下,如果是通过导航链接来路由页面,Vue Router 会在内部截获单击事件,通过 JavaScript 操作 window.history 改变浏览器地址栏中的路径,在这个过程中并没有发起 HTTP 请求,所以就不会出现 404 错误。

如果使用 HTML 5 history 模式,那么需要在前端程序部署的 Web 服务器上配置一个覆盖所有情况的备选资源,即当 URL 匹配不到任何资源时,,返回一个固定的 index.html 页面,这个页面就是单页应用程序的主页面。

Vue Router 的官网给出了一些常用的 Web 服务器的配置,网址:https://router.vuejs.org/guide/essentials/history-mode.html

如果使用 Tomcat 作为前端程序的 Web 服务器,可以在项目根目录下新建 WEB-INF 子目录,在其下新建一个 web.xml 文件。代码如下:


404/index.html

按照上述配置后,Tomcat 服务器就不会再返回 404 错误页面,对于所有不匹配的路径都会返回 index.html 页面。

提示:
在基于 Vue 脚手架项目的开发中,内置的 Node 服务器本身也支持 HTML 5 history 模式,所以开发时一般不会出现问题。

相关内容

热门资讯

汽车油箱结构是什么(汽车油箱结... 本篇文章极速百科给大家谈谈汽车油箱结构是什么,以及汽车油箱结构原理图解对应的知识点,希望对各位有所帮...
美国2年期国债收益率上涨15个... 原标题:美国2年期国债收益率上涨15个基点 美国2年期国债收益率上涨15个基...
嵌入式 ADC使用手册完整版 ... 嵌入式 ADC使用手册完整版 (188977万字)💜&#...
重大消息战皇大厅开挂是真的吗... 您好:战皇大厅这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游戏...
盘点十款牵手跑胡子为什么一直... 您好:牵手跑胡子这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游...
senator香烟多少一盒(s... 今天给各位分享senator香烟多少一盒的知识,其中也会对sevebstars香烟进行解释,如果能碰...
终于懂了新荣耀斗牛真的有挂吗... 您好:新荣耀斗牛这款游戏可以开挂,确实是有挂的,需要了解加客服微信8435338】很多玩家在这款游戏...
盘点十款明星麻将到底有没有挂... 您好:明星麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【5848499】很多玩家在这款游戏...
总结文章“新道游棋牌有透视挂吗... 您好:新道游棋牌这款游戏可以开挂,确实是有挂的,需要了解加客服微信【7682267】很多玩家在这款游...
终于懂了手机麻将到底有没有挂... 您好:手机麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游戏...