返回目录
说起路由你想起了什么?
额,啥玩意儿?没听懂
在生活中,我们没有听说过路由的概念呢?当然了,路由器嘛
路由器是做什么的?你有想过吗?
路由器提供了两种机制:路由和转送
路由中有一个非常重要的概念叫路由表
学习内容概括:
脚手架2演练
记得选择下载路由哦
路由的更多理解大家可以查查资料,这里只是讲解怎么用
返回目录
路由发展阶段
后端路由阶段:
早期的网站开发整个HTML页面是由服务器来渲染的,服务器直接生产渲染好对应的HTML页面, 返回给客户端进行展示.但是, 一个网站, 这么多页面服务器如何处理呢?
上面的这种操作, 就是后端路由
后端路由的缺点:
前端路由阶段
前后端分离阶段:
互联网发展第三阶段:单页面富应用阶段
返回目录
URL的hash
演示:
先把我们之前创建的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
vue-router是基于路由和组件的
因为我们已经学习了webpack,后续开发中我们主要是通过工程化的方式进行开发的
如果安装脚手架时选择了安装路由,就不用下面安装指令了
npm install vue-router --save
删除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 to='/home' tag='li'>
replace : replace 不会留下 history 记录,所以指定 replace 的情况下,后退键返回不能返回到上一个页面中
active-class :当 对应的路由匹配成功时,会自动给当前元素设置一个 router-link-active 的 class,设置 active-class 可以修改默认的名称(一般不需要改)
我们可以利用这个动态生成的class改变一些动态样式:
测试:
但是如果你想修改默认的这个名字:就要用到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>
返回目录
在某些情况下,一个页面的path路径可能是不确定的,比如我们进入用户界面时,希望是如下的路径:
创建User组件:
运行测试:
现在开始我们的动态配置:
运行获取:
子组件动态获取:
子组件动态获取:
改变值:
运行:
补充:
返回目录
返回目录
懒加载:用到时再加载
认识路由的懒加载
官方给出的解释:
官方在说什么呢?
开始:
懒加载的方式一: 结合Vue的异步组件和Webpack的代码分析(强烈不推荐)
懒加载的方式二: AMD写法
const About = resolve => require([’…/components/About.vue’],resolve)
懒加载的方式三: 在ES6中,我们可以有更加简单的写法来组织Vue异步组件和Webpack的代码分割(强烈推荐)
const Home = () => import('../components/Home.vue')
重构我们的代码:
重新打包看看:把app中的js代码分离了部分出去,减轻了加载压力
建议以后开发都使用懒加载
返回目录
嵌套路由是一个很常见的功能
比如在home页面中,我们希望通过/home/news和/home/message访问一些内容
一个路径映射一个组件,访问这两个路径也会分别渲染两个组件
创建对应的子组件,并且在路由映射中配置对应的子路由
在组件内部使用
创建两个组件:
写上内容:
配置子路由:
因为这两个子组件是在home页面显示的,所以在Home.vue中使用
运行测试:
刚刚进去的时候是没有显示新闻或者消息的,此时我们可以配个默认路径
测试:
返回目录
为了演示传递参数,我们这里再创建一个组件,并且将其配置好
传递参数主要有两种类型:params和query
运行测试:
返回目录
返回目录
$route和 $ router是有区别的
在User.vue设置点击打印router对象
在main.js中也打印我们导入的router对象:
结果:
不再详解,理解结论的两句话即可:
返回目录
我们来考虑一个需求:在一个SPA应用中,如何改变网页的标题
普通的修改方式:
我们比较容易想到的修改标题的位置是每一个路由对应的组件.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
返回目录
全局前置守卫
每次发生路由的导航跳转时,都会触发全局前置守卫 。因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制:
const router = new VueRouter({
routes,
})
// 调用路由实例对象的 beforeEach 方法,即可声明"全局前置守卫"
// 每次发生路由跳转的时候,都会触发这个方法
// 全局前置守卫
router.beforeEach((to,from,next)=> {
// to 是将要访问的路由的信息对象
// from 是将要离开的路由的信息对象
// next 是一个函数,调用 next()表示放行,允许这次路由导航
})
导航钩子的三个参数解析:
注意:如果是前置钩子beforeEach,必须要调用 next() 函数,如果是后置钩子afterEach,不需要主动调用 next() 函数
当前用户拥有后台主页的访问权限,直接放行: next()
当前用户没有后台主页的访问权限,强制其跳转到登录页面:next(’/login’)
当前用户没有后台主页的访问权限,不允许跳转到后台主页:next(false)
返回目录
keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染
router-view也是一个组件,如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存
验证1:验证组件在跳转时是否会频繁的创建和销毁
页面刷新首页组件被创建,点击其他跳转时,首页被销毁,再点回首页时,组件又被创建
这时候加上我们的keep-alive标签:
再写上两个方法:
运行测试:
返回首页:
成功保留状态
更深入理解:
https://www.jb51.net/article/122570.htm
返回目录
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页面都不会被频繁的创建和销毁,
返回目录
一、搭建思路
1、自定义TabBar组件,位于底部,并设置样式
2、TabBar中显示的内容由外界决定,定义插槽,flex布局平分TabBar
3、自定义TabBarItem组件,设置样式,并定义两个插槽:图片和文字
4、填充插槽,实现底部TabBar效果
5、TabBar-TabBarItem和路由动态结合
TabBarItem颜色动态控制
即a、基本框架–>b、插槽–>c、路由点击切换(图片或文字颜色)–>d、路由跳转,点击哪个跳转到对应页面(使用router-view标签)–>e、动态决定isActive
效果图如下:点击哪个跳转到对应页面
返回目录
返回目录
返回目录
返回目录
返回目录
ES6中一个非常重要和好用的特效就是Promise
Promise到底是做什么的呢?
那什么时候我们会来处理异步事件呢?
但是,当网络请求非常复杂时,就会出现回调地狱
// 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状态发生改变,就会触发then()里的响应函数处理后续步骤;
promise状态一经改变,不会再变。
Promise对象的状态改变,只有两种可能:
从pending变为fulfilled
从pending变为rejected。
这两种情况只要发生,状态就凝固了,不会再变了。
返回目录
// 网络请求: 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.all([
new Promise((resolve, reject) => {
setTimeout(() => {
resolve("111")
}, 2000)
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
name:'得意小门生',
age:18
})
}, 1000)
})
]).then( results => {
console.log(results);
})