首先简单说一下单页面应用程序
单页面应用程序
- SPA : single page application 单页面应用程序
- MPA : Multiple Page Application 多页面应用程序
- 单页面 web 应用
- 就是只有一个web页面的应用
- 是加载单个HTML页面
- 并在用户与应用程序交互时,动态更新该页面的wen应用程序
- 区别
- 对于传统的多页面应用程序来说,每次请求服务器返回的都是一个完整的页面
- 对于单页面应用程序来说 :
- 只要第一次加载页面, 以后每次请求 仅仅是获取必要的数据, 然后由 页面中 js 解析 获取的数据展示在页面中
- 单页面优势 :
- 减少了请求体积 , 加快页面响应速度 ,降低了对服务器的压力
- 更好的用户体验 , 让用户在 web app 感受 native app 的流畅 (局部刷新)
- 单页面的劣势
- 开发成本高 ( 需要学习路由 )
- 不利于SEO
路由
介绍路由 :
- 路由 : 是浏览器URL 中的哈希值( #hash ) 与 展示视图内容之间的对用规则
- 简单的来说 : 路由就是一套映射规则(一对一的对应规则),由开发人员制定规则
- 当URL中的哈希值(#hash) 发生改变后, 路由会根据制定好的规则,展示对用的视图内容
- 为什么要学习路由 ?
- 渐进式 => vue => vue-router (管理多个页面)
- 在web App中 , 经常会出现通过一个页面来展示和管理整个应用的功能
- SPA 往往是功能复杂的应用 , 为了有效管理所有视图内容,前端路由 应运而生
- vue 中的路由 : 是hash 和 component 的对应关系 , 一个哈希值对应一个组件
一 : 路由的基本使用
准备工作 (3个)
- 安装 : npm i vue-router
- 引入 : 在引入vue之后引用 <script src="./node_modules/vue-router/dist/vue-router.js">
- 实例路由对象 + 挂载到vue上
具体步骤(4个)
- 1. 入口
- 2. 路由规则
- 3. 组件
- 4. 出口
// 1. 入口
// 方式1 : url 地址为入口 调试开发用
输入 url 地址 改变哈希值
// 方式2 : 声明式导航 : router-link + to
// 2. 路由规则
path : 路由路径
component : 将要展示的路由组件
routes : [
{path : '/one',component : One},
{path : '/two',component : Two}
]
// 3. 组件
// 使用返回值的这个组件名称
const One = Vue.component('one',{
template : `<div>子组件 one </div>`
})
// 4 . 出口
// 也就是组件要展示的地方
<router-view></router-view>
# 总结
拿到入口 哈希路径 ,根据路由匹配规则,找到对应的组件,显示到对用的出口位置
二 : 路由使用注意事项
-
入口
- 最长用的 入口是 声明式导航 router-link
// router-link 组件 最终被渲染为 a 标签 // to属性转化为a标签的href 属性 // to属性的值 , 实际上就是哈希值 , 将来要参与路由规则中进行匹配 <router-link to='/one'>首页</router-link>
- 最长用的 入口是 声明式导航 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>
三 : 入口导航菜单高亮处理
-
点击导航 => 元素里添加了两个类
<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'
})
精确匹配和模糊匹配
-
精确匹配 : router-link-exact-active 类名 : 只有当
浏览器地址栏中的哈希值 与 router-link 的 to 属性值,完全匹配对,才会添加该类
-
模糊匹配: router-link-active 类名 : 只要
浏览器地址栏中的哈希值
包含 router-link 的 to 属性值,就会添加该类名 -
解决办法 : 加个 exact
<router-link to="/" exact>
One
</router-link>
-
注意 : 精确匹配和模糊匹配,只对添加类名这个机制有效,与路由的匹配规则无关!!!
四 : 路由配置
4.1 动态路由 => 详情列表
导入 : 列表的三个手机都要点击进去详情页 , 只需要一个组件 , 显示不同的数据即可
入口 : to="/detial/3"
规则 : path : '/detail/:id ?'
获取值 : 组件 ---> $route.params.id
事件中 ---> this.$route.params.id
监听 ---> $route(to){ to.params.id } 或者 watch
4.2 路由对象 - $route
- 一个路由对象(route object) 表示当前激活的路由的状态信息, 包含了当前url解析得到的信息
- 一个哈希值路径 ===> 一个路由对象
- 路由对象
- 例如 : /detail/4?age=21#one
- $route.name : 路由规则名称
- $route.params : 路由参数 对象 -----> { id : '4' }
- $route.query : 查询参数 对象 -----> {age=21}
- $route.path : 哈希 值 路径 -----> '/detail/4'
- $route.hash 当前路由的hash 值 -----> "#one"
- $route.fullPath 全路径 -----> /detail/4?age=21#one
- 例如 : /detail/4?age=21#one
4.3 嵌套路由
作用 : 想在一个组件(child)显示在另一个组件(parent) 里
如何使用 :
- 在parent组件里留一个出口 Parent : --- <router-view></router-view>
- 规则 children children:[{ path:'/child' , componemt:'Child' }]
/child和child的区别 :
- 如果是 /child => 那么直接访问就可以了 #/child
- 如果是 child => 那么直接访问就应该访问#/parent/child 才可以了
4.4 命名路由 name
- 有时候,通过一个名称来标识一个路由显得更方便一些
- 特别是在创建一个路由 , 或者执行一些跳转的时候
- 你可以在创建ROuter实例的时候,在routers配置中给某个路由设置名称
# 命名 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' }) }
4.5 命名视图
作用 : 一个哈希值路径显示多个组件
如何使用 :
1. 规则里面 { path :'/', components : {
default : header,
m : main,
f :footer
} }
2. 出口 : <router-view /> <router-view name='m' /> <router-view name='f' />
4.6 重定向
作用 : 改变路由规则
使用 :
{path:'/',redirect : ''}
// 1
redirect: '/header'
// 2
redirect: { name: 'header' }
// 3
redirect: to => {
// console.log(to)
return {
name: 'about'
}
}
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' } }
路由进阶
一 . 元信息
- 作用 : 给路由添加一些自己的信息 在导航路由的时候,可以用作判断
- 规则 : {path :'/one' .... meta : { title : '春' '}}
- 获取 : $route.meta.title
二. 导航守卫
说明 : 通过跳转或者取消的方式 , 守卫导航 比如 : 先登录,在去home,要不然就会跳登录页
方法
router.beforeEach((to, from, next) => {
// 访问 login
if (to.name == 'login') {
// 下一步
next()
} else {
// 停止跳转
next(false)
// 跳转到下一步
next({ name: 'login' }) 或者 使用路径 next('/login')
}
})
$route 和 $router 的区别
$route : 路由对象 ---> url解析对象 ----> path/name/meta -----> 都是属性
$router : 路由实例 ---> new VueRouter() ---> 编程式导航 -----> 跳转用的 ---> push back replace