-
传统的多页面应用程序,每次请求服务器返回的都是一整个完整的页面
-
单页面应用程序只有第一次会加载完整的页面
-
以后每次请求仅仅获取必要的数据,减少了请求体积,加快页面响应速度,降低了对服务器的压力
-
SPA更好的用户体验,运行更加流畅
缺点
-
开发成本高 (需要学习路由)
vue-router react-router
-
不利于 SEO 搜索引擎优化 谷歌浏览器在解决这个问题 ssr:服务端渲染 server side rendering
路由介绍
-
路由 : 是浏览器 URL 中的哈希值( # hash) 与 展示视图内容(组件) 之间的对应规则
-
简单来说,路由就是一套映射规则(一对一的对应规则), 由开发人员制定规则.-
-
当 URL 中的哈希值(
#
hash) 发生改变后,路由会根据制定好的规则, 展示对应的视图内容(组件)
-
-
为什么要学习路由?
-
渐进式 =>vue => vuer-router (管理组件之间的跳转)
-
在 web App 中, 经常会出现通过一个页面来展示和管理整个应用的功能.
-
SPA 往往是功能复杂的应用,为了有效管理所有视图内容,前端路由 应运而生.
-
-
vue 中的路由 : 是 hash 和 component 的对应关系, 一个哈希值对应一个组件
路由基础01
1. 前端路由 - 工作模式原理
基本思路:
-
用户点击了页面上的路由链接
-
导致了 URL 地址栏中的 Hash 值发生了变化
-
前端路由监听了到 Hash 地址的变化
-
前端路由把当前 Hash 地址对应的组件渲染都浏览器中
<template>
<div>
<a href="#one">ONE</a>
<a href="#two">TWO</a>
<a href="#three">THREE</a>
<component :is="is"></component>
</div>
</template>
created() {
window.onhashchange = () => {
console.log(location.hash.slice(1))
this.is = location.hash.slice(1)
}
},
2. 路由的基本使用
-
安装 :
yarn add vue-router
2.1 准备工作( 3个 )
-
引入
import VueRouter from 'vue-router'
// 把路由当成插件一样安装
Vue.use(VueRouter)
-
实例路由对象 :
let router = new VueRouter()
-
把路由挂载到vue实例上
new Vue({
router, +
render: h => h(App),
}).$mount('#app')
2.2 具体步骤 ( 3个 )
-
1.入口
-
2.规则
-
3.出口
# 1. 入口
// 浏览器 url 地址栏 ==> #/one 和 #/two
# 2. 路由规则
// path : 路由路径
// component : 将来要展示的路由组件
routes: [
{ path: '/one', component: One },
{ path: '/two', component: Two }
]
# 3. 出口
<router-view></router-view>
-
画图 逻辑
# 总结
拿到入口哈希路径, 根据路由匹配规则,找到对应的组件,显示到对应的出口位置
3. 声明式导航
<!-- 1. 改变入口 -->
<router-link to='/one'>one</router-link>
<router-link to='/two'>two</router-link>
4. 让当前导航高亮 (精确匹配 和 模糊匹配)
需求: 点击切换后, 让当前导航高亮
.router-link-exact-active, .router-link-active{
color: red;
font-size: 50px;
}
5 演示高亮问题
// 地址栏 输入 / 或者 /two 会有问题的 或者点击演示
<router-link to="/">one</router-link>
<router-link to="/two">two</router-link>
-
精确匹配 : router-link-exact-active 类名 : 只有当
浏览器地址栏中的哈希值 与 router-link 的 to 属性值,完全匹配对,才会添加该类
( 上 == 下 ) -
模糊匹配: router-link-active 类名 : 只要
浏览器地址栏中的哈希值
包含 router-link 的 to 属性值,就会添加该类名 (上 > 下)
-
解决办法1 : 只使用精确匹配
.router-link-exact-active {
color: red;
font-size: 30px;
}
-
解决方法2 : 添加 exact (推荐)
.router-link-exact-active,
.router-link-active {
color: red;
font-size: 30px;
}
<router-link to="/" exact>one</router-link>
<router-link to="/two">two</router-link>
路由基础02
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 }
]
# 获取参数的两种方式
<template>
<div>
<h1>one {{ $route.params.id }}</h1>
</div>
</template>
<script>
export default {
watch : {
$route(obj){
console.log('id:',obj.params.id);
}
}
}
</script>
2. 路由对象 - $route
-
一个路由对象 (route object) 表示当前激活的路由的状态信息,包含了当前 URL 解析得到的信息
-
一个哈希值路径 ==> 一个路由对象
-
$route.path
-
类型:
string
-
字符串,对应当前路由的路径,总是解析为绝对路径,如
"/foo/bar"
。 -
# 后面?前面的内容
-
-
$route.params
-
类型:
Object
-
url参数对象
-
一个 key/value 对象,包含了动态片段和全匹配片段,如果没有路由参数,就是一个空对象。
-
-
$route.query
-
类型:
Object
-
查询参数对象
-
一个 key/value 对象,表示 URL 查询参数。例如,对于路径
/foo?user=1
,则有$route.query.user == 1
,如果没有查询参数,则是个空对象。
-
# 演示 :
<router-link to="/detail/4?age=21">detail</router-link>
{ path: '/detail/:id?', component: detail }
在组件内 created打印 this.$route
> params : {id:'4'}
> query : {age : 21}
> path : '/detail/4'
3. 嵌套路由 (子路由)
3.1 模板结构
<style>
.home {
200px;
height: 200px;
border: 4px solid lime;
}
.list {
200px;
height: 200px;
border: 4px solid red;
}
.one,
.two {
border: 3px solid #000;
100px;
height: 100px;
}
</style>
const home = {
template: `<div class='home'>home <router-view /> </div>`,
}
const list = {
template: `<div class='list'>list</div>`,
}
const one = {
template: `<div class='one'>one</div>`,
}
const two = {
template: `<div class='two'>two</div>`,
}
-
parent 的内部 添加 :
<router-view> </router-view>
-
规则里添加 children
-
那么访问就应该访问
#/home/one
才可以访问子组件
const router = new VueRouter({
// 2. 规则
routes: [
{
path: '/home',
component: home,
children: [
{ path: '/one', component: one },
{ path: '/two', component: two },
],
},
{ path: '/list', component: list },
],
})
4. 编程式导航
跳转的三种方式
1-声明式导航 通过导航组件跳转
2-编程式导航 通过js代码来实现跳转
-
解释
# push() 跳转 保留历史记录 (可返回)
go(1)
# back() 返回
go(-1)
# replace() 跳转 不保留历史记录 (不可返回)
-
代码
// one组件
methods: {
jump() {
// this.$router.push('/two')
// this.$router.go(1)
this.$router.replace('/two')
},
},
}
// two组件
methods: {
back() {
// this.$router.back()
this.$router.go(-1)
},
},
5. 命名路由
有时候,通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。
-
场景1 : 重定向
-
场景2 : 声明式导航链接跳转
//1
<router-link to='/home'>123</router-link>
//2
<router-link :to='{ name : "home" }'>123</router-link>
-
场景3 : 编程时导航跳转传参
6. 重定向
-
方式1 : 路径
routes: [
{ path: '/', redirect: '/home'}
]
-
方式2 : 对象
routes: [
{ path: '/', redirect: { name: 'home' }}
]
7. 编程时跳转页面传参
// 字符串
router.push('home')
// 对象
router.push({ path: 'home' })
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})