目录(点击下面知识点可跳转)
- 一、什么是路由和其中映射关系(理解)
- 二、前端渲染后端渲染和前端路由后端路由(理解)
- 三、url的hash和HTML5的history(掌握)
- 四、vue-router-安装和配置方式(掌握)
- 五、路由映射配置和呈现出来(掌握)
- 六、路由的默认值和修改为history模式(掌握)
- 七、router-link的其他属性补充(掌握)
- 八、通过代码跳转路由(掌握)
- 九、vue-router-动态路由的使用(掌握)
- 十、vue-router-打包文件的解析(掌握)
- 十一、vue-router-路由懒加载的使用(掌握)
- 十二、vue-router-路由的嵌套使用(掌握)
- 十三、vue-router-参数传递一(掌握)
- 十四、vue-router-参数传递二(掌握)
- 十五、vue-router-router和route的由来(理解)
- 十六、vue-router-全局导航守卫(掌握)
- 十七、vue-router-导航守卫的补充(掌握)
- 十八、vue-router-keep-alive及其他问题(掌握)
- 十九、vue-router-keep-alive属性介绍(掌握)
- 二十、tabbar-基本结构的搭建(掌握)
- 二十一、tabbar-TabBar和TabBarltem组件封装(掌握)
- 二十二、tabbar-给TabBarltem的颜色动态控制(掌握)
- 二十三、知识回顾(了解)
- 二十四、tabbar-文件路径的引用问题(掌握)
- 二十五、Promise-Promise的介绍和基本使用(掌握)
- 二十六、Promise-Promise的三种状态和另外处理方式(掌握)
- 二十七、Promise-Promise的链式调用(掌握)
- 二十八、Promise-Promise的all方法使用(掌握)
一、什么是路由和其中映射关系(理解)
说起路由你想起了什么?
- 路由是一个网络工程里面的术语
- 路由(routing) 就是通过互联网的网络把信息从源地址传输到目的地址的活动 -----维基百科
额,啥玩意儿?没听懂
-
在生活中,我们没有听说过路由的概念呢?当然了,路由器嘛
-
路由器是做什么的?你有想过吗?
-
路由器提供了两种机制:路由和转送
- 路由是决定数据包从来源到目的地的路径
- 转送将输入端的数据转移到合适的输出端
-
路由中有一个非常重要的概念叫路由表
- 路由表本质上就是一个映射表,决定了数据包的指向
学习内容概括:
- 认识路由
- vue-router基本使用
- vue-router嵌套路由
- vue-router参数传递
- vue-router导航守卫
- keep-alive
脚手架2演练
记得选择下载路由哦
路由的更多理解大家可以查查资料,这里只是讲解怎么用
二、前端渲染后端渲染和前端路由后端路由(理解)
路由发展阶段
后端路由阶段:
早期的网站开发整个HTML页面是由服务器来渲染的,服务器直接生产渲染好对应的HTML页面, 返回给客户端进行展示.但是, 一个网站, 这么多页面服务器如何处理呢?
- 一个页面有自己对应的网址, 也就是URL.
- URL会发送到服务器, 服务器会通过正则对该URL进行匹配, 并且最后交给一个Controller进行处理.
- Controller进行各种处理, 最终生成HTML或者数据, 返回给前端.
- 这就完成了一个IO操作.
上面的这种操作, 就是后端路由
- 当我们页面中需要请求不同的路径内容时, 交给服务器来进行处理, 服务器渲染好整个页面, 并且将页面返回给客户端
- 这种情况下渲染好的页面, 不需要单独加载任何的js和css, 可以直接交给浏览器展示, 这样也有利于SEO的优化.
后端路由的缺点:
- 一种情况是整个页面的模块由后端人员来编写和维护的.
- 另一种情况是前端开发人员如果要开发页面, 需要通过PHP和Java等语言来编写页面代码
- 而且通常情况下HTML代码和数据以及对应的逻辑会混在一起, 编写和维护都是非常糟糕的事情.
前端路由阶段
前后端分离阶段:
- 随着Ajax的出现, 有了前后端分离的开发模式.
- 后端只提供API来返回数据, 前端通过Ajax获取数据, 并且可以通过JavaScript将数据渲染到页面中.
- 这样做最大的优点就是前后端责任的清晰, 后端专注于数据上, 前端专注于交互和可视化上.
- 并且当移动端(IOS/Android)出现后,后端不需要进行任何处理,依然使用之前的一套API即可
- 目前很多网站依然采用这种模式开发
互联网发展第三阶段:单页面富应用阶段
- 其实SPA最主要的特点就是在前后端分离得到基础上加了一层前端路由
- 也就是前端来维护一套路由规则
前端路由的核心是什么呢?
- 改变URL,但是页面不进行整体的刷新。
三、url的hash和HTML5的history(掌握)
URL的hash
- url的hash也就是锚点(#),本质上是改变window.location的href属性
- 我们可以通过直接赋值location.hash来改变href,但是页面不发生刷新
演示:
先把我们之前创建的Vue项目跑起来:npm run dev
试试第一种页面不跳转加载指令:
location.hash=‘url’
页面没进行跳转
再试试第二种
history.pushState({},’’,‘url’)
可以调用返回函数:(点击左箭头按钮也可以返回)
history.pushState({},’’,‘url’)
history.back()
最后试试第三种:history.replaceState({},’’,‘url’)
这种方法生成的url不能返回!!!
返回方法也有另一种:history.go()
补充说明:
上面只演示了三个方法
因为history.back()等价于history.go(-1)
history.forward()则等价于history.go(1)
所以这三个接口等同于浏览器界面的前进后退
四、vue-router-安装和配置方式(掌握)
目前前端流行的三大框架,都有自己的路由实现
- Angular的ngRouter
- React的ReactRouter
- Vue的vue-router
当然,我们的重点是vue-router
- vue-router是Vue.js官方的路由插件,它是vue.js是深度集成的,适用于构建单页面应用
- 我们可以访问其官方网站对其进行深度学习:https://router.vuejs.org/zh/
vue-router是基于路由和组件的
- 路由用于设定访问路径,将路径和组件映射起来
- 在vue-router的单页面应用中,页面的路径的改变就是组件的切换
因为我们已经学习了webpack,后续开发中我们主要是通过工程化的方式进行开发的
- 所以在后续,我们直接使用npm来安装路由即可
如果安装脚手架时选择了安装路由,就不用下面安装指令了
- 步骤一:安装vue-router
npm install vue-router --save
- 步骤二:在模块化工程中使用它(因为是一个插件,所以可以通过vue.use()来安装路由功能)
- 第一步:导入路由对象,并且调用Vue.use(VueRouter)
- 第二步:创建路由实例,并且传入路由映射配置
- 第三步:在Vue实例中挂载创建的路由实例
删除index.js文件夹我们自己配
删除main.js中的导入
开始我们的配置,创建index.js
导入配置路由的相关信息:
// 配置路由的相关信息
import VueRouter from "vue-router";
//导入Vue
import Vue from "vue";
// 1.通过Vue.use(插件),安装插件【因为VueRouter本质就是一个插件】
Vue.use(VueRouter)
// 2.创建VueRouter对象
const routes=[
]
const router = new VueRouter({
//配置路由和组件之间的映射关系
/*routes:routes*/
routes
})
// 3.将router对象传入到Vue实例中
export default router
import Vue from 'vue'
import App from './App'
//导入路由对象
import router from "./router/index";
Vue.config.productionTip = false
new Vue({
el: '#app',
//挂载路由
router,
render: h => h(App)
})
完成配置
五、路由映射配置和呈现出来(掌握)
第一步:创建路由组件
删除components包下的默认Vue文件
创建组件:
写上内容:
第二步:配置路由映射:组件和路径映射关系
第三步:使用路由:通过<router-link>和<router-view>
测试使用:
点击首页
点击关于
六、路由的默认值和修改为history模式(掌握)
我们这里还有一个不太好的实现
- 默认情况下,进入网站的首页,我们希望<router-view>渲染首页的内容
- 但是我们的实现中,默认没有显示首页组件,必须让用户点击才可以
如何可以让路径默认跳到首页,并且<router-view>渲染首页组件呢?
- 非常简单,我们只需要多配置一个映射就可以了
配置解析
- 我们在routes中又配置了一个映射
- path配置的是根路径:/
- redirect是重定向,也就是我们将根路径重定向到/home的路径下,这样就可以得到我们想要的结果了
下面这种不规范的路径我们怎么修改呢?
配置history模式:
再次打开浏览器:
七、router-link的其他属性补充(掌握)
- 在前面的 <outer-link> 中,我们只是使用了一个属性:to ,用于指定跳转的路径
- <router-link> 还有一些其他属性
- tag : tag可以指定 <router-link> 之后渲染成什么组件,比如下面的代码会被渲染成一个 <li> 元素,而不是 <a>
<router-link to='/home' tag='li'>
-
replace : replace 不会留下 history 记录,所以指定 replace 的情况下,后退键返回不能返回到上一个页面中
-
active-class :当 对应的路由匹配成功时,会自动给当前元素设置一个 router-link-active 的 class,设置 active-class 可以修改默认的名称(一般不需要改)
我们可以利用这个动态生成的class改变一些动态样式:
测试:
- 在进行高亮显示的导航菜单或者底部tabbar时, 会使用到该类
- 但是通常不会修改类的属性, 会直接使用默认的router-link-active即可
但是如果你想修改默认的这个名字:就要用到active-class
效果:
也可以在路由配置中统一修改:
八、通过代码跳转路由(掌握)
<template>
<div id="app">
<!--<router-link tag="button" to="/home" replace active-class="aaa">首页</router-link>--><!--使用路由展示组件的固定写法-->
<!--<router-link tag="button" to="/About" replace active-class="aaa">关于</router-link>-->
<!--<router-view></router-view>--><!--决定渲染出来的组件放在什么位置,占位的东西-->
<button @click="homeClick">首页</button>
<button @click="aboutClick">关于</button>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
methods:{
homeClick(){
// 通过代码的方式修改路由 vue-router
// this.$router.push('/home')//这个this.$router对象是已经生成的,不需要我们引入
this.$router.replace('/home')//清除历史
},
aboutClick(){
// this.$router.push('/About')
this.$router.replace('/About')//清除历史
}
}
}
</script>
<style>
.aaa{
background-color: red;
}
</style>
九、vue-router-动态路由的使用(掌握)
在某些情况下,一个页面的path路径可能是不确定的,比如我们进入用户界面时,希望是如下的路径:
- /user/aaaa或/user/bbbb
- 除了有前面的/user之外,后面还跟上了用户的ID
- 这种path和Component的匹配关系,我们称之为路由(也是路由传递数据的一种方式)
创建User组件:
运行测试:
现在开始我们的动态配置:
运行获取:
子组件动态获取:
子组件动态获取:
改变值:
运行:
补充:
十、vue-router-打包文件的解析(掌握)
对我们的项目进行打包:分析打包文件
十一、vue-router-路由懒加载的使用(掌握)
懒加载:用到时再加载
认识路由的懒加载
官方给出的解释:
- 当打包构建应用时,JavaScript包会变得非常大,影响页面加载
- 如果我们能把不同的路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了
官方在说什么呢?
- 首先,我们知道路由中通常会定义很多不同的页面
- 这个页面最后被打包在哪里呢?一般情况下,是放在一个js文件中
- 但是,页面这么多放在一个js文件中,必然会造成这个页面非常大
- 如果我们一次性从服务器请求下来这个页面,可能需要花费一定的时间,甚至用户的电脑上还出现了短暂空白的情况。
- 如何避免这种情况呢?使用路由懒加载就可以了
开始:
懒加载的方式一: 结合Vue的异步组件和Webpack的代码分析(强烈不推荐)
懒加载的方式二: AMD写法
const About = resolve => require([’…/components/About.vue’],resolve)
懒加载的方式三: 在ES6中,我们可以有更加简单的写法来组织Vue异步组件和Webpack的代码分割(强烈推荐)
const Home = () => import('../components/Home.vue')
重构我们的代码:
重新打包看看:把app中的js代码分离了部分出去,减轻了加载压力
建议以后开发都使用懒加载
十二、vue-router-路由的嵌套使用(掌握)
嵌套路由是一个很常见的功能
-
比如在home页面中,我们希望通过/home/news和/home/message访问一些内容
-
一个路径映射一个组件,访问这两个路径也会分别渲染两个组件
-
路由和组件的映射关系
实现嵌套路由有两个步骤: -
创建对应的子组件,并且在路由映射中配置对应的子路由
-
在组件内部使用<router-view>标签
创建两个组件:
写上内容:
配置子路由:
因为这两个子组件是在home页面显示的,所以在Home.vue中使用
运行测试:
刚刚进去的时候是没有显示新闻或者消息的,此时我们可以配个默认路径
测试:
十三、vue-router-参数传递一(掌握)
为了演示传递参数,我们这里再创建一个组件,并且将其配置好
- 第一步:创建新的组件Profile.vue
- 第二步:配置路由映射
- 第三步:添加跳转的<router-link>
传递参数主要有两种类型:params和query
- params的类型:
- 配置路由格式: /router/:id
- 传递的方式: 在path后面跟上对应的值
- 传递后形成的路径: ==/router/123,/router/abc
- query的类型
- 配置路由格式:/router,也就是普通配置
- 传递的方式:对象中使用query的key作为传递方式
- 传递后形成的路径:/router?id=123,/router?id=abc
测试:
开始传递参数:
我们写成这种形式:
运行看看:
显示参数:
运行测试:
十四、vue-router-参数传递二(掌握)
函数定义传递参数:
运行测试:
十五、vue-router-router和route的由来(理解)
$route和 $ router是有区别的
- $ router 为VueRouter实例,想要导航到不同URL,则使用$ router.push方法
- $ route为当前 router 跳转对象里面可以获取name、path、query、params等
在User.vue设置点击打印router对象
在main.js中也打印我们导入的router对象:
结果:
不再详解,理解结论的两句话即可:
- $ router 为VueRouter实例,是整个父路由(不止一个父路由对象哦)
- $ route 为活跃时某个路由对象,哪个路由活跃就是哪个路由对象
十六、vue-router-全局导航守卫(掌握)
导航守卫主要目的是监听路由跳转到哪里了
我们来考虑一个需求:在一个SPA应用中,如何改变网页的标题
- 网页标题是通过<title>来显示的,但是SPA只有一个固定的HTML,切换不同的页面时,标题并不会改变
- 但是我们可以通过JavaScript来修改<title>的内容.window.document.title = ‘新的标题’
- 那么在Vue项目中,在哪里修改?什么时候修改比较合适呢?
普通的修改方式:
-
我们比较容易想到的修改标题的位置是每一个路由对应的组件.vue文件中.
-
通过mounted声明周期函数, 执行对应的代码进行修改即可.
-
但是当页面比较多时, 这种方式不容易维护(因为需要在多个页面执行类似的代码).
-
有没有更好的办法呢? 使用导航守卫即可.
怎么理解导航守卫?
-
vue-router提供的导航守卫主要用来监听监听路由的进入和离开的.
-
vue-router提供了beforeEach和afterEach的钩子函数, 它们会在路由即将改变前和改变后触发
// 配置路由相关的信息
import VueRouter from 'vue-router'
import Vue from 'vue'
import Home from '../components/Home'
import About from '../components/About'
import User from "../components/User";
// 1.通过Vue.use(插件), 安装插件
Vue.use(VueRouter)
// 2.创建VueRouter对象
const routes = [
{
path: '',
// redirect重定向
redirect: '/home'
},
{
path: '/home',
component: Home,
meta: {
title: '首页'
}
},
{
path: '/about',
component: About,
meta: {
title: '关于'
}
},
]
const router = new VueRouter({
// 配置路由和组件之间的应用关系
routes,
mode: 'history',
})
// 前置钩子hook(前置回调)
router.beforeEach((to,form,next) => {
// 从 from 跳转到 to
window.document.title = to.meta.title
next()
})
// 3.将router对象传入到Vue实例
export default router
十七、vue-router-导航守卫的补充(掌握)
返回目录
全局前置守卫
每次发生路由的导航跳转时,都会触发全局前置守卫 。因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制:
const router = new VueRouter({
routes,
})
// 调用路由实例对象的 beforeEach 方法,即可声明"全局前置守卫"
// 每次发生路由跳转的时候,都会触发这个方法
// 全局前置守卫
router.beforeEach((to,from,next)=> {
// to 是将要访问的路由的信息对象
// from 是将要离开的路由的信息对象
// next 是一个函数,调用 next()表示放行,允许这次路由导航
})
导航钩子的三个参数解析:
- to : 即将要进入的目标的路由对象
- from:当前导航即将要离开的路由对象
- next:调用该方法后,才能进入下一个钩子
注意:如果是前置钩子beforeEach,必须要调用 next() 函数,如果是后置钩子afterEach,不需要主动调用 next() 函数
next函数的三种调用方式:
-
当前用户拥有后台主页的访问权限,直接放行: next()
-
当前用户没有后台主页的访问权限,强制其跳转到登录页面:next(’/login’)
-
当前用户没有后台主页的访问权限,不允许跳转到后台主页:next(false)
十八、vue-router-keep-alive及其他问题(掌握)
keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染
router-view也是一个组件,如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存
验证1:验证组件在跳转时是否会频繁的创建和销毁
页面刷新首页组件被创建,点击其他跳转时,首页被销毁,再点回首页时,组件又被创建
这时候加上我们的keep-alive标签:
再写上两个方法:
运行测试:
返回首页:
成功保留状态
更深入理解:
https://www.jb51.net/article/122570.htm
十九、vue-router-keep-alive属性介绍(掌握)
keep-alive是Vue内置的一个组件,可以使用被包含的组件保留状态,或避免重新渲染。
它里面有两个非常重要的属性:
1.include - 字符串或正则表达式,只有匹配的组件会被缓存
2.exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存
router-view也是一个组件,如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存:
<!--正则表达式里面不能随便加空格,这里的都好后面也不要加空格-->
<keep-alive exclude="Profile,User">
<router-view></router-view>
</keep-alive>
通过create生命周期函数来验证
1.生命周期函数回顾:mounted、 created、activated、deactivated、destroyed
2.keep-alive -> activated/deactivated,这两个函数,只有该组件被保持了状态使用了keep-alive时,才是有效的
3.首页中使用path属性记录离开时的路径,在beforeRouteLeave中记录。
使用了keep-alive页面都不会被频繁的创建和销毁,
二十、tabbar-基本结构的搭建(掌握)
一、搭建思路
1、自定义TabBar组件,位于底部,并设置样式
2、TabBar中显示的内容由外界决定,定义插槽,flex布局平分TabBar
3、自定义TabBarItem组件,设置样式,并定义两个插槽:图片和文字
4、填充插槽,实现底部TabBar效果
5、TabBar-TabBarItem和路由动态结合
TabBarItem颜色动态控制
即a、基本框架–>b、插槽–>c、路由点击切换(图片或文字颜色)–>d、路由跳转,点击哪个跳转到对应页面(使用router-view标签)–>e、动态决定isActive
效果图如下:点击哪个跳转到对应页面
二十一、tabbar-TabBar和TabBarltem组件封装(掌握)
二十二、tabbar-给TabBarltem的颜色动态控制(掌握)
二十三、知识回顾(了解)
二十四、tabbar-文件路径的引用问题(掌握)
二十五、Promise-Promise的介绍和基本使用(掌握)
ES6中一个非常重要和好用的特效就是Promise
- 但是初次接触Promise会一脸懵逼,这TM是什么东西?
- 看看官方或者一些文章对它的介绍和用法,也是一头雾水
Promise到底是做什么的呢?
- Promise是异步编程的一种解决方案
那什么时候我们会来处理异步事件呢?
- 一种很常见的场景应该就是网络请求了
- 我们封装一个网络请求的函数,因为不能立即拿到结果,所以不能像简单的3+4=7一样返回结果
- 所以往往我们会传入另外一个函数,在数据请求成功时,将数据通过传入的函数回调出去
- 如果只是一个简单的网络请求,那么这种方案不会给我们带来很大的麻烦
但是,当网络请求非常复杂时,就会出现回调地狱
- OK,以一个非常夸张的案例来说明
基本使用:
// 1、使用setTimeout
//setTimeout(() => {
// console.log("hellow world");
//},1000)
// 参数 -> 函数(resolve,reject)
// resolver。reject本身他们又是函数
//new Promise((resolve,reject) => {
// setTimeout(() => {
// console.log("hellow world");
// },1000)
})
new Promise((resolve,reject) => {
setTimeout(() => {
resolve()
},1000)
}).then(() => {
console.log("hellow world");
})
// 多次调用
// new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve()
// }, 1000)
// }).then(() => {
// console.log("hellow world");
// console.log("hellow world");
// console.log("hellow world");
// console.log("hellow world");
// setTimeout(() => {
// console.log("hellow vue.js");
// console.log("hellow vue.js");
// console.log("hellow vue.js");
// console.log("hellow vue.js");
// setTimeout(() => {
// console.log("hellow phthon");
// console.log("hellow phthon");
// console.log("hellow phthon");
// console.log("hellow phthon");
// }, 1000)
// }, 1000)
// })
new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000)
}).then(() => {
console.log("hellow world");
console.log("hellow world");
console.log("hellow world");
console.log("hellow world");
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000)
}).then(() => {
console.log("hellow vue.js");
console.log("hellow vue.js");
console.log("hellow vue.js");
console.log("hellow vue.js");
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000)
}).then(() => {
console.log("hellow phthon");
console.log("hellow phthon");
console.log("hellow phthon");
console.log("hellow phthon");
})
})
})
二十六、Promise-Promise的三种状态和另外处理方式(掌握)
Promise的三种状态
- 1、pending[待定]初始状态
- 2、fulfilled[实现]操作成功
- 3、rejected[被否决]操作失败
当promise状态发生改变,就会触发then()里的响应函数处理后续步骤;
promise状态一经改变,不会再变。
Promise对象的状态改变,只有两种可能:
从pending变为fulfilled
从pending变为rejected。
这两种情况只要发生,状态就凝固了,不会再变了。
二十七、Promise-Promise的链式调用(掌握)
// 网络请求: aaa -> 自己处理(10行)
// 处理: aaa111 -> 自己处理(10行)
// 处理: aaa111222 -> 自己处理
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('aaa')
}, 1000)
}).then(res => {
console.log(res, '第一层的10行处理代码')
return new Promise(resolve => {
resolve(res + '111')
}).then(res => {
console.log(res, '第二层的10行处理代码')
return new Promise(resolve => {
resolve(res + '222')
}).then(res => {
console.log(res, '第三层的10行处理代码')
})
})
})
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('aaa')
}, 1000)
}).then(res => {
console.log(res, '第一层的10行处理代码')
return Promise.resolve(res + '111')
}).then(res => {
console.log(res, '第二层的10行处理代码')
return Promise.resolve(res + '222')
}).then(res => {
console.log(res, '第三层的10行处理代码')
})
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('aaa')
}, 1000)
}).then(res => {
console.log(res, '第一层的10行处理代码')
return res + '111'
}).then(res => {
console.log(res, '第二层的10行处理代码')
return res + '222'
}).then(res => {
console.log(res, '第三层的10行处理代码')
})
二十八、Promise-Promise的all方法使用(掌握)
Promise.all([
new Promise((resolve, reject) => {
setTimeout(() => {
resolve("111")
}, 2000)
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
name:'得意小门生',
age:18
})
}, 1000)
})
]).then( results => {
console.log(results);
})