单页面应用程序
-
SPA : Single Page Application 单页面应用程序
-
MPA : Multiple Page Application 多页面应用程序
-
单页 web 应用
就是只有一个 web 页面的应用,
是加载单个 HTML 页面,
并在用户与应用程序交互时, 动态更新该页面的 web 应用程序 -
区别
-
对于传统的多页面应用程序来说, 每次请求服务器返回的都是一个完整的页面
-
对于单页应用程序来说,
只有第一次会加载页面,以后的每次请求,仅仅是获取必要的数据.然后,由页面中 js 解析获取的数据,展示在页面中
-
-
单页面优势 :
- 减少了请求体积,加快页面响应速度,降低了对服务器的压力
- 更好的用户体验,让用户在 web app 感受 native app 的流畅, (局部刷新)
-
单页面劣势 :
- 开发成本高 (需要学习路由)
- 不利于 SEO
-
演示 : https://music.163.com/
零、路由介绍
- 路由 : 是浏览器 URL 中的哈希值( // hash) 与 展示视图内容 之间的对应规则。
- 简单来说,路由就是一套映射规则(一对一的对应规则), 由开发人员制定规则.
- 当 URL 中的哈希值(
//
hash) 发生改变后,路由会根据制定好的规则, 展示对应的视图内容
- 为什么要学习路由?
- 在 web App 中, 经常会出现通过一个页面来展示和管理整个应用的功能.
- SPA 往往是功能复杂的应用,为了有效管理所有视图内容,前端路由 应运而生.
- vue 中的路由 : 是 hash 和 component 的对应关系, 一个哈希值对应一个组件
一、路由的基本使用
准备工作 (3个)
- 安装 :
npm i vue-router
- 引入 :
<script src="./vue.js"></script>
// 千万注意 :引入路由一定要在引入vue之后,因为vue-router是基于vue工作的
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
- 实例路由对象 + 挂载到vue上
- 实例路由对象 :
const router = new VueRouter()
- 挂载到vue上 :
new Vue({ router,data,methods })
- 验证路由是否挂载成功, 就看打开页面,最后面有没有个
///
- 实例路由对象 :
具体步骤 (4个)
- 1.入口
- 2.路由规则
- 3.组件
- 4.出口
// 1. 入口
// 方式1 : url地址为入口 调试开发用
输入url地址 改变哈希值 `01-路由的基本使用.html///one`
// 方式2 : 声明式导航 : router-link+to (见下面介绍)
// 2. 路由规则
// path : 路由路径 【path的属性值前面要加斜杠/。】
// component : 将来要展示的路由组件
routes: [
// 【path的属性值前面要加斜杠/。】
{ path: '/one', component: One },
{ path: '/two', component: Two }
]
// 3. 组件
// 使用返回值的这个组件名称
const One = Vue.component('one', {
template: ` <div> 子组件 one </div> `
})
// 4. 出口
<!-- 出口 组件要展示的地方-->
<router-view></router-view>
// 总结
拿到入口哈希路径, 根据路由匹配规则,找到对应的组件,显示到对应的出口位置
01-路由的基本使用.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!--
准备工作 (3个)
1. 安装路由 npm i vue-router
2. 引入路由
3. 实例化路由 + 挂载到vue上
具体步骤 (4个)
1. 入口 (哈希值) 手动在url上写 /one
2. 规则 routes
3. 组件
4. 出口
-->
<div id="app">
<!-- 第四步 : 出口 占位置 【出口router-view在哪里,就在哪里显示组件。】【vue-router.js中内置了vueRouter】 -->
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 第三步 : 路由组件 【路由组件要写在路由实例对象前,否则报错。】
const One = {
template: `<div>one组件</div>`
}
// 实例化路由
const router = new VueRouter({
// 第二步 : 路由的匹配规则 一个哈希值 对应一个组件
routes: [{
path: '/one',
component: One
}]
})
const vm = new Vue({
router,
el: '//app',
data: {}
})
</script>
</body>
</html>
二、路由使用注意事项
- 入口
- 最常用的入口 是 声明式导航 router-link
<!--
router-link 组件最终渲染为 a标签, to属性转化为 a标签的href属性
to 属性的值 , 实际上就是哈希值,将来要参与路由规则中进行与组件匹配
<a href="///one" class="">ONE</a>
-->
<router-link to="/one">首页</router-link>
- 组件
const One = {
template: `<div> 子组件 one </div> `
}
- 演示 : 多个组件匹配
<div id="app">
<!-- 1 路由入口:链接导航 -->
<router-link to="/one">One</router-link>
<router-link to="/two">Two</router-link>
<!-- 4 路由出口:用来展示匹配路由视图内容 -->
<router-view></router-view>
</div>
<!-- 导入 vue.js -->
<script src="./vue.js"></script>
<!-- 导入 路由文件 -->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 3 创建两个组件
const One ={
template: '<h1>这是 one 组件</h1>'
}
const Two = {
template: '<h1>这是 two 组件</h1>'
}
// 0 创建路由对象
const router = new VueRouter({
// 2. 路由规则
routes: [
{ path: '/one', component: One },
{ path: '/two', component: Two }
]
})
const vm = new Vue({
el: '//app',
//0. 不要忘记,将路由与vue实例关联到一起!
router
})
</script>
02-多个路径.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!--
准备工作
1. 安装
2. 引入
3. 实例化+挂载
具体步骤
1. 入口
2. 规则
3. 组件
4. 出口
-->
<div id="app">
<!-- 第一步 : 入口
1. 刚才手动写 测试.开发时候用 /one /two
2. 声明式导航
-->
<!--
router-link 声明式导航
router-link 最终会编译成 a 标签
to 转化为href
作用 : 改变入口的哈希值路径
-->
<!-- 最后编译成 <a href="///one" class="">ONE</a> -->
<router-link to="/one">ONE</router-link>
<!-- <router-link to="/two">TWO</router-link> -->
<!-- 第四步 :出口 -->
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 第三步 : 组件
const One = {
template: `<div>one组件</div>`
}
const Two = {
template: `<div>two组件</div>`
}
// 实例化路由
const router = new VueRouter({
// 规则
routes: [{
path: '/one',
component: One
}, {
path: '/two',
component: Two
}]
})
const vm = new Vue({
router,
el: '//app',
data: {}
})
</script>
</body>
</html>
三、入口导航菜单高亮处理
- 点击导航 => 元素里添加了两个类
<a href="///one" class="router-link-exact-active router-link-active">One</a>
<a href="///two" class="">Two</a>
- 修改方式1 : 直接修改类的样式
.router-link-exact-active,
.router-link-active {
color: red;
font-size: 50px;
}
- 修改方式2 : 使用存在过的类样式 => 修改默认高亮类名
const router = new VueRouter({
routes: [],
// 修改默认高亮的a标签的类名
// red 是已经存在过的
linkActiveClass: 'red'
})
03-高亮状态.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<style>
/* 假如说路由是后面加进来的, 但是如果之前就已经有了一个类 */
.red {
color: red;
font-size: 50px;
}
/*
.router-link-exact-active,
.router-link-active {
color: red;
font-size: 50px;
}
*/
</style>
</head>
<body>
<div id="app">
<!-- 1. 入口 -->
<router-link to="/one">one</router-link>
<router-link to="/two">two</router-link>
<!-- 4. 出口 -->
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 3. 组件
const One = {
template: `<div>one组件</div>`
}
const Two = {
template: `<div>two组件</div>`
}
// 实例化
const router = new VueRouter({
// 2. 规则
routes: [{
path: '/one',
component: One
}, {
path: '/two',
component: Two
}],
// router-link-exact-active 【去掉router-,改为小驼峰,最后加上Class。】
linkExactActiveClass: 'red'
})
const vm = new Vue({
router,
el: '//app',
data: {}
})
</script>
</body>
</html>
04-高亮状态-精确匹配和模糊匹配.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<style>
/* 假如说路由是后面加进来的 ,但是如果之前就已经有了一个类 */
/* .red {
color: red;
font-size: 50px;
} */
.router-link-exact-active,
.router-link-active {
color: red;
font-size: 50px;
}
</style>
</head>
<body>
<!--
1. 精确匹配 和 模糊匹配 (了解)
2. router-link-exact-active: 精确匹配 当url上的路径 == href的值
3. router-link-active : 模糊匹配 当url上的路径 (包含)>= href的值
-->
<div id="app">
<!-- 1. 入口 -->
<!-- exact:加上表示只允许精确匹配,不允许模糊匹配 【只需给没有精确路由的router-link 加上 exact 即可。】-->
<router-link to="/" exact>one</router-link>
<router-link to="/two">two</router-link>
<!-- 4. 出口 -->
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 3. 组件
const One = {
template: `<div>one组件</div>`
}
const Two = {
template: `<div>two组件</div>`
}
// 实例化
const router = new VueRouter({
// 2. 规则
routes: [{
path: '/',
component: One
}, {
path: '/two',
component: Two
}]
// router-link-exact-active
// linkExactActiveClass: 'red'
})
const vm = new Vue({
router,
el: '#app',
data: {}
})
</script>
</body>
</html>
四、路由配置
4.1 动态路由 => 详情列表
导入 : 列表三个手机都要点击进去详情页, 只需要一个组件,显示不同的数据即可
// 入口
<router-link to="/detail/1">手机1</router-link>
<router-link to="/detail/2">手机2</router-link>
<router-link to="/detail/3">手机3</router-link>
<router-link to="/detail">手机4</router-link> 没有参数如何????
// 规则
routes: [
// 2 . 路由规则
{ path: '/detail/:id?', component: Detail }
]
// 获取参数的三种方式
const Detail = {
template: `
// 方式1 : 组件中直接读取
//【$route:当前路由】
<div> 显示详情页内容....{{ $route.params.id }} </div>
`,
created() {
// 方式2 : js直接读取
// 打印只会打印一次,因为组件是复用的,每次进来钩子函数只会执行一次
// 【$route:当前路由】
console.log(this.$route.params.id)
},
// 方式3 : 监听路由的参数,为什么不需要深度监听,因为一个路径变化,就会对应一个对新的路由对象(地址变)
watch: {
$route(to, from) {
console.log(to.params.id)
}
}
}
05-动态路由-详情页.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!--
动态路由
1. 使用参数接收不同的路由参数
path ='/detail/:id'
2. 参数可传可不传 path ='/detail/:id?'
-->
<div id="app">
<!-- 1. 入口 -->
<router-link to="/detail/1">手机1</router-link>
<router-link to="/detail/2">手机2</router-link>
<router-link to="/detail/3">手机3</router-link>
<router-link to="/detail">手机4</router-link>
<!-- 4. 出口 -->
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 3. 组件
const detail = {
// 经测试,在生命周期钩子函数中,要使用$route,前面得加this. ,否则报错,因为是事件;而在组件的其他地方,可加可不加
template: `<div>详情页组件 {{ $route.params.id }}</div>`
}
// 实例化
const router = new VueRouter({
// 2. 规则
routes: [{
path: '/detail/:id?',
component: detail
}]
})
const vm = new Vue({
router,
el: '#app',
data: {}
})
</script>
</body>
</html>
4.2 路由对象 - $route
-
一个路由对象 (route object) :表示当前激活的路由的状态信息,包含了当前 URL 解析得到的信息
-
一个哈希值路径 ==> 一个路由对象
-
$route.path
- 类型:
string
- 字符串,对应当前路由的路径,总是解析为绝对路径,如
"/foo/bar"
。 // 后面、?前面的内容
- 类型:
-
$route.params
- 类型:
Object
- 一个 key/value 对象,包含了动态片段和全匹配片段,如果没有路由参数,就是一个空对象。
- 类型:
-
$route.query
- 类型:
Object
- 参数对象
- 一个 key/value 对象,表示 URL 查询参数。例如,对于路径
/foo?user=1
,则有$route.query.user == 1
,如果没有查询参数,则是个空对象。
- 类型:
-
$route.hash
-
类型:
string
当前路由的 hash 值 (带
//
) ,如果没有 hash 值,则为空字符串。
-
-
$route.fullPath
- 类型:
string
- 全路径
- 完成解析后的 URL,包含查询参数和 hash 的完整路径。
- 类型:
// 演示 :
<router-link to="/detail/4?age=21//one">detail</router-link>
{ path: '/detail/:id?', component: detail }
在组件内 created打印 this.$route
> fullPath: "/detail/4?id=001//one"
> hash : "//one"
> params : {id:'4'}
> query : {age : 21}
> path : '/detail/4'
06-$route.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!--
$route:路由对象,解析的url信息,哈希值的url信息
哈希值 (#/one/4?age=30#aaa) ==> $route
-->
<div id="app">
<!-- 1. 入口 -->
<!-- <router-link to="/one/4?age=30#aaa">one</router-link> -->
<router-link to="/one/1">第一个</router-link>
<router-link to="/one/2">第二个</router-link>
<!-- 4. 出口 -->
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 3. 组件
const One = {
template: `<div>one组件 {{ $route.params.id }}</div>`,
// 经测试,在生命周期钩子函数中,要使用$route,前面得加this. ,否则报错,因为是事件;而在组件的其他地方,可加可不加
created() {
// 页面加载过程中的第一次的值,不会变化,因为created只执行一次
console.warn(this.$route.params.id)
},
// 补充mounted、updated
// mounted不能监听到 this.$route.params.id 的变化
mounted() {
console.log('mounted中的id是---', this.$route.params.id)
},
// updated能监听到 this.$route.params.id 的变化
updated() {
console.log('updated中的id是---', this.$route.params.id)
},
// 很重要的思想(★)
// 使用watch 监听 $route 路由对象,获取里面的信息 【url变了,$route跟着变。之前监听复杂类型时,是复杂类型的地址没变,只是它里面的数据变化了而已。】
watch: {
$route(newVal) {
console.warn(newVal)
console.warn(newVal.params.id)
}
}
}
// 实例化
const router = new VueRouter({
// 2. 规则
routes: [{
path: '/one/:id',
component: One
}]
})
const vm = new Vue({
router,
el: '#app',
data: {}
})
</script>
</body>
</html>
4.3 嵌套路由/子路由: children
导入 : url测试 parent 和child, 想让child 在 parent 中显示
- parent 的内部 添加 :
<router-view> </router-view>
- 规则里添加 children
- /child 和 child 的区别
- 如果是
/child
=> 那么访问就可以直接访问///child
就可以访问 子组件 - 如果是
child
=> 那么访问就应该访问///parent/child
才可以访问子组件
- 如果是
const parent = {
template: `<p>parent <router-view> </router-view> </p>`
}
const child = {
template: `<p>child</p>`
}
const router = new VueRouter({
routes: [
{
path: '/parent',
component: parent,
children: [
{ path: '/child', component: child }
]
}
]
})
07-嵌套路由.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 1. 入口 -->
<!--
需求: child组件 放到 parent组件 里面
办法: children: [路由规则]
-->
<!-- 4. 出口 -->
<router-view></router-view>
<hr />
</div>
<script src="./vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 3. 组件
const parent = {
template: `<div> parent组件 -- <router-view></router-view> </div>`
}
const child = {
template: `<div>child组件</div>`
}
// 实例化
const router = new VueRouter({
// 2. 规则
routes: [{
path: '/parent',
component: parent,
children: [{
// 子组件的path值前,加斜杆/,则浏览器的url中不需要写成 /parent/child,直接写/child即可。不加的话,就要写成 /parent/child
path: '/child',
component: child
}],
// children: [{
// path: 'child',
// component: child
// }]
// path : '/child' => 哈希值 : /child
// path : 'child' => 哈希值 : /parent/child
}]
})
const vm = new Vue({
router,
el: '#app',
data: {}
})
</script>
</body>
</html>
4.4 命名路由 ==> :to="{ name : 'xxx' }"
- 有时候,通过一个名称来标识一个路由显得更方便一些,
- 特别是在链接一个路由,或者是执行一些跳转的时候。 ===> 场景
- 你可以在创建 Router 实例的时候,在
routes
配置中给某个路由设置名称。 ==> 如何命名
// 命名
routes: [
{
path: '/parent',
name: 'parent',
component: parent
}
]
// 入口链接 + 跳转 (使用 path 和 name 的转换)
<!-- 方式1 : url手动写 -->
<!-- 方式2 : 入口链接 声明式导航 -->
<router-link to="/parent">点击</router-link>
<router-link :to="{ name : 'parent' }">点击</router-link> // 忘了 带 : 原始对象类型
<!-- 方式3 : 编程式导航 -->
fn() {
// this.$router.push('/parent')
this.$router.push({
name: 'parent'
})
}
09-命名路由.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 1. 入口 -->
<!-- 下面两个用的都是 path -->
<!--
<router-link to="/one">one</router-link>
<router-link to="/two">two</router-link>
-->
<!-- to前面不加冒号,就会把属性值当做字符串 -->
<router-link :to="{ name : 'one' }">one</router-link>
<router-link :to="{ name :'two' }">two</router-link>
<!-- 4. 出口 -->
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 3. 组件
const One = {
template: `<div>one组件</div>`
}
const Two = {
template: `<div>two组件</div>`,
created() {
console.log(this.$route.name)
}
}
// 实例化
const router = new VueRouter({
// 2. 规则
routes: [{
path: '/one',
name: 'one',
component: One
}, {
path: '/two',
name: 'two',
component: Two
}]
})
const vm = new Vue({
router,
el: '//app',
data: {}
})
</script>
</body>
</html>
4.5 命名视图:
导入 : 有时候想同时 (同级) 展示多个视图,
需求 : 访问 / 根目录 同时展示以下三个组件
- 三个组件
const header = {
template: `<p>header </p>`
}
const main = {
template: `<p>main </p>`
}
const footer = {
template: `<p>footer </p>`
}
- 规则
// 以前的那个方式只能显示三个 header
// 演示之前的效果
routes: [
{
path: '/',
components: {
default: header,
m: main,
f: footer
}
}
]
- 出口
<router-view> </router-view>
<router-view name="m"> </router-view>
<router-view name="f"> </router-view>
08-命名视图.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!--
需求 : / => 三个组件 header main footer
-->
<div id="app">
<!-- 4. 出口 -->
<router-view></router-view>
<router-view name="m"></router-view>
<router-view name="f"></router-view>
</div>
<script src="./vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 3. 组件
const header = {
template: `<div>header组件</div>`
}
const main = {
template: `<div>main组件</div>`
}
const footer = {
template: `<div>footer组件</div>`
}
// 实例化
const router = new VueRouter({
// 2. 规则
routes: [{
path: '/',
components: {
default: header,
m: main,
f: footer
}
}]
})
const vm = new Vue({
router,
el: '//app',
data: {}
})
</script>
</body>
</html>
4.6 重定向
方式1:
redirect: '/header'
方式2:
redirect: { name: 'header' }
方式3:【函数,用路由对象去判断, to:即路由对象$route。】
redirect: to => {
// console.log(to)
return {
name: 'about'
}
}
10-重定向.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 1. 入口 -->
<!-- <router-link to="/one">one</router-link> -->
<!-- 4. 出口 -->
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 3. 组件
const One = {
template: `<div>one组件</div>`
}
// 实例化
const router = new VueRouter({
// 2. 规则
routes: [
// 方式1 : path路径
{
path: '/',
redirect: '/one'
},
// 方式2 : 路由的名称
{
path: '/',
redirect: {
name: 'one'
}
},
// 方式3 : 函数,用路由对象去判断
{
path: '/',
// to:即路由对象$route
redirect: to => {
// console.log(to) // to:即路由对象$route
// if (to.XXX) {
// return { name : 'one'}
// } else {
// return {name : 'two' }
// }
return {
name: 'one'
}
}
}, {
path: '/one',
name: 'one',
component: One
}
]
})
const vm = new Vue({
router,
el: '#app',
data: {}
})
</script>
</body>
</html>
4.7 【路由给】组件传参
【路由给组件传参】
- 原始方式使用 $route获取
// 入口
<router-link to="/header/3">123</router-link>
// 规则
routes: [
{
path: '/header/:id',
component: header,
}
]
// 获取参数
const header = {
template: `<p>header {{ $route.params.id }} </p>`
}
- 布尔模式
// 入口
<router-link to="/header/3">123</router-link>
// 规则
routes: [
{
path: '/header/:id',
component: header,
// 如果 props 被设置为 true,route.params 将会被设置为组件属性
props: true
}
]
// 获取参数
const header = {
// 参数 id 当成参数
props: ['id'],
template: `<p>header {{ id }} </p>`
}
- 对象模式
// 入口
<router-link to="/header">123</router-link>
// 规则
routes: [
{
path: '/header',
component: header,
props: { foo: '0000' }
}
]
// 组件
const header = {
props: ['foo'],
template: `<p>header {{ foo }} </p>`
}
- 函数模式
// 同对象模式一样
// 区别是props值不一样
props: to => {
return { foo: '0000' }
}
- 注意 : 对象模式和函数模式参数 在props里,所以声明式导航那里就不要传参了
11-组件传参.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!--
方式1:to='/one/4' path='/one/:id?'
组件:$route.params.id
事件:this.$route.params.id
方式2: 布尔模式
路由规则里,写props:true
将参数id 作为组件的属性存在
- props: true
- 组件内 : props:['id']
- 使用: {{ id }}
方式3: 对象模式
- props : { aaa : 'bbb' }
- props: ['aaa']
- {{ aaa }}
方式4 : 函数模式
- props : to => { return { aaa : 'ccc' } }
- props:['aaa']
- {{ aaa }}
-->
<div id="app">
<!-- 1. 入口 -->
<!-- <router-link to="/one/11">one</router-link> -->
<router-link to="/one">one</router-link>
<!-- 4. 出口 -->
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
// 3. 组件
const One = {
props: ['id', 'aaa'],
template: `<div>one组件 {{ aaa }}</div>`
}
// 实例化
const router = new VueRouter({
// 2. 规则
routes: [
// props : true 将id参数作为组件的属性存在
// {
// path: '/one/:id',
// component: One,
// props: true
// }
// 将aaa 作为 组件的属性存在
// {
// path: '/one',
// component: One,
// props: {
// aaa: 'bbb'
// }
// }
// 函数
{
path: '/one',
component: One,
props: to => {
return {
aaa: 'ccc'
}
}
}
]
})
const vm = new Vue({
router,
el: '#app',
data: {}
})
</script>
</body>
</html>
五、路由进阶
5.1 元信息
- **作用 **
在路由导航的时候,可以用作判断
- 规则声明
routes: [
{
path: '/header',
component: header,
// (1)meta默认是空对象;(2)可以控制组件的显示与隐藏
meta: {
title: 'XXXX'
}
}
]
- 获取
created() {
document.title = this.$route.meta.title
}
01-元信息.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!--
3个准备工作
4个具体步骤
元信息 : 路由里添加 meta 字段
-->
<div id="app">
<router-view></router-view>
<h1 id="haha">哈哈</h1>
<h1>嘿嘿</h1>
</div>
<script src="./vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
//组件
const One = {
template: `<div>one组件</div>`,
created() {
// 有了这个meta 可以做很多事情
// console.log(this.$route.meta.title)
// 可以设置标题
document.title = this.$route.meta.title
console.log(document.querySelector('//haha').innerHTML) // 哈哈
console.log(111) // 111
}
}
const Two = {
template: `<div>two组件</div>`,
created() {
document.title = this.$route.meta.title
}
}
// 实例化 + 挂载
const router = new VueRouter({
routes: [{
path: '/one',
name: 'one',
component: One,
meta: {
title: '帅气的马哥'
}
}, {
path: '/two',
name: 'two',
component: Two,
meta: {
title: '骚气的春春'
}
}]
})
const vm = new Vue({
router,
el: '//app',
data: {}
})
</script>
</body>
</html>
5.2 编程式导航
const one = {
template: `
<div> <button @click="handleClick('back')">返回 上一页</button>
<button @click="handleClick('push')">跳转 two页</button>
<button @click="handleClick('replace')">替换 two页</button>
</div>`,
methods: {
handleClick(type) {
if (type == 'back') {
// 返回
this.$router.back()
} else if (type == 'push') {
// 跳转 有历史记录
this.$router.push('/two')
} else {
// 替换 没有历史记录
this.$router.replace('/two')
}
}
}
}
const two = {
template: `<p>two </p>`
}
02-编程式导航.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!--
入口
1. 手动url修改 /one
2. 声明式导航 <router-link to='/one'>one</router-link>
3. 编程式导航 this.$router.push('/one')
(1)前进(跳转) ==>
- this.$router.push() - 有记录 【可以后退】
- this.$router.replace() - 没有记录 【不可以后退】
(2)返回 ====> this.$router.back()
-->
<div id="app">
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
//组件
const One = {
template: `<div> one组件
<button @click="handle('push')"> 跳转到two - push </button>
<button @click="handle('back')"> 返回到/ </button>
<button @click="handle('replace')"> 跳转到two - replace </button>
</div>`,
methods: {
handle(type) {
if (type == 'push') {
// $route: 路由对象,解析url信息 (属性:.path、 .name、 .meta、 .params)
// $router: VueRouter的路由实例【 也就是下面的const router = new VueRouter(...)的变量router 】,挂载到vue实例上后,就是$router,用于编程式导航 (方法 )
// push => 有记录的 【这里的push是vue的跳转,不是原生js的】
this.$router.push('/two')
} else if (type == 'back') {
this.$router.back()
} else if (type == 'replace') {
// replace => 没有记录的
this.$router.replace('/two')
}
}
}
}
const Two = {
template: `<div>two组件</div>`
}
// 实例化 + 挂载
const router = new VueRouter({
routes: [{
path: '/one',
name: 'one',
component: One
}, {
path: '/two',
name: 'two',
component: Two
}]
})
const vm = new Vue({
router,
el: '#app',
data: {}
})
</script>
</body>
</html>
5.3 导航守卫
router.beforeEach((to, from, next) => {
// 访问 login
if (to.name == 'login') {
// 下一步
next()
} else {
// 停止跳转
next(false)
// 跳转到下一步
next({ name: 'login' }) 或者 使用路径 next('/login')
}
})
03-导航守卫.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!--
导航守卫 : 是通过跳转或者取消的方式守卫导航 A => 导航守卫 => B
需求 : 所有的页面经过登录 之后才准访问
1. => login 可以
2. => one => 访问login => 登录之后 => one
前置导航守卫 beforeEach
概念 : 是通过跳转或者取消的方式守卫导航 拦截
1. 写法 router.beforeEach( (to,from ,next)=> {} )
2. to : 目标路由对象 from : 来源路由对象 next: 下一步
3. next() 允许下一步
next(false) 不允许
next('/login') 跳转到login
-->
<div id="app">
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
//组件
const One = {
template: `<div>one组件</div>`
}
const Login = {
template: `<div>Login组件</div>`
}
// 实例化 + 挂载
const router = new VueRouter({
routes: [{
path: '/one',
name: 'one',
component: One
}, {
path: '/login',
name: 'login',
component: Login
}]
})
// 导航守卫
// /one => /login
// to : 目标路由对象($route)
// from : 来源路由对象
// next():下一步 【不写next(),就不能访问下一步。】
router.beforeEach((to, from, next) => {
// console.log('from:', from)
console.log('to:', to)
// 如果访问 login => 允许访问 next 【用to.name、to.path都可以。】
if (to.name == 'login') {
next() // next()中不用传递路径 '/login',否则会无限循环,直到报错。
} else if (to.name == 'one') {
next()
} else {
next(false); // 不允许访问,next(false) 和不写任何代码的结果一样
// next('/login'); // 如果不是login => 转到 login
// next({ name: 'login' })
}
})
const vm = new Vue({
router, // 挂载
el: '#app',
data: {}
})
</script>
</body>
</html>