共计 7240 个字符,预计需要花费 19 分钟才能阅读完成。
学习列表
初学 Vue(一)– Vue 简略入门
初学 vue(二)– 条件渲染、修饰符、循环
初学 vue(三)– 生命周期、过滤器、监听属性、计算属性
初学 vue(四)– axios 前后端交互、组件
单页面应用程序
- 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 : 路由门路
// 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>
- 组件
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'
})
四: 路由配置
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 : 组件中间接读取
<div> 显示详情页内容....{{$route.params.id}} </div>
`,
created() {
// 形式 2 : js 间接读取
// 打印只会打印一次, 因为组件是复用的, 每次进来钩子函数只会执行一次
console.log(this.$route.params.id)
},
// 形式 3 : 监听路由的参数, 为什么不须要深度监听, 因为一个门路变动, 就会对应一个对新的路由对象(地址变)
watch: {$route(to, from) {console.log(to.params.id)
}
}
}
4.2 路由对象 – $route
- 一个 路由对象 (route object) 示意以后激活的路由的状态信息,蕴含了以后 URL 解析失去的信息
- 一个哈希值门路 ==> 一个路由对象
-
$route.path
- 类型:
string
- 字符串,对该当前路由的门路,总是解析为绝对路径,如
"/foo/bar"
。 # 前面? 后面的内容
- 类型:
-
$route.params
- 类型:
Object
- 一个 key/value 对象,蕴含了动静片段和全匹配片段,如果没有路由参数,就是一个空对象。
- 一个 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'
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}
]
}
]
})
4.4 命名路由
- 有时候,通过一个名称来标识一个路由显得更不便一些,
- 特地是在 链接一个路由 ,或者是执行一些 跳转 的时候。===> 场景
- 你能够在创立 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'})
}
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>
4.6 重定向
redirect: '/header'
redirect: {name: 'header'}
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'}
}
- 留神 : 对象模式和函数模式参数 在 props 里, 所以申明式导航那里就不要传参了
4.8 嵌套路由
理论生存中的利用界面,通常由多层嵌套的组件组合而成。同样地,URL 中各段动静门路也按某种构造对应嵌套的各层组件。
借助 vue-router
,应用嵌套路由配置,就能够很简略地表白这种关系。
- 单层路由
<div id="app">
<router-view></router-view>
</div>
const User = {template: '<div>User {{ $route.params.id}}</div>'
}
const router = new VueRouter({
routes: [{ path: '/user/:id', component: User}
]
})
这里的 <router-view>
是最顶层的进口,渲染最高级路由匹配到的组件。同样地,一个被渲染组件同样能够蕴含本人的嵌套 <router-view>
。例如,在 User
组件的模板增加一个 <router-view>
-
嵌套路由
- 模板配置
const User = { template: ` <div class="user"> <h2>User {{$route.params.id}}</h2> <router-view></router-view> </div> ` }
- 路由配置:要在嵌套的进口中渲染组件,须要在
VueRouter
的参数中应用children
配置
const router = new VueRouter({
routes: [
{ path: '/user/:id', component: User,
children: [
{
// 当 /user/:id/profile 匹配胜利,// UserProfile 会被渲染在 User 的 <router-view> 中
path: 'profile',
component: UserProfile
},
{
// 当 /user/:id/posts 匹配胜利
// UserPosts 会被渲染在 User 的 <router-view> 中
path: 'posts',
component: UserPosts
}
]
}
]
})
留神,以 /
结尾的嵌套门路会被当作根门路。这让你充沛的应用嵌套组件而无须设置嵌套的门路。
五 : 路由进阶
5.1 元信息
- 规定申明
routes: [
{
path: '/header',
component: header,
meta: {title: 'XXXX'}
}
]
- 获取
created() {document.title = this.$route.meta.title}
- 作用 :
-
在路由导航的时候, 能够用作判断
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>`}
5.3 导航守卫
router.beforeEach((to, from, next) => {
// 拜访 login
if (to.name == 'login') {
// 下一步
next()} else {
// 进行跳转
next(false)
// 跳转到下一步
next({name: 'login'}) 或者 应用门路 next('/login')
}
})