目录(点击下面知识点可跳转)
一、什么是路由和其中映射关系(理解)
返回目录
说起路由你想起了什么?
- 路由是一个网络工程里面的术语
- 路由(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的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-router的单页面应用中,页面的路径的改变就是组件的切换
因为我们已经学习了webpack,后续开发中我们主要是通过工程化的方式进行开发的
如果安装脚手架时选择了安装路由,就不用下面安装指令了
npm install vue-router --save
- 步骤二:在模块化工程中使用它(因为是一个插件,所以可以通过vue.use()来安装路由功能)
- 第一步:导入路由对象,并且调用Vue.use(VueRouter)
- 第二步:创建路由实例,并且传入路由映射配置
- 第三步:在Vue实例中挂载创建的路由实例
删除index.js文件夹我们自己配 删除main.js中的导入
开始我们的配置,创建index.js 导入配置路由的相关信息:
import VueRouter from "vue-router";
import Vue from "vue";
Vue.use(VueRouter)
const routes=[
]
const router = new VueRouter({
routes
})
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'>
但是如果你想修改默认的这个名字:就要用到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(){
this.$router.replace('/home')
},
aboutClick(){
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声明周期函数, 执行对应的代码进行修改即可. -
但是当页面比较多时, 这种方式不容易维护(因为需要在多个页面执行类似的代码). -
有没有更好的办法呢? 使用导航守卫即可.
怎么理解导航守卫?
import VueRouter from 'vue-router'
import Vue from 'vue'
import Home from '../components/Home'
import About from '../components/About'
import User from "../components/User";
Vue.use(VueRouter)
const routes = [
{
path: '',
redirect: '/home'
},
{
path: '/home',
component: Home,
meta: {
title: '首页'
}
},
{
path: '/about',
component: About,
meta: {
title: '关于'
}
},
]
const router = new VueRouter({
routes,
mode: 'history',
})
router.beforeEach((to,form,next) => {
window.document.title = to.meta.title
next()
})
export default router
十七、vue-router-导航守卫的补充(掌握)
返回目录 全局前置守卫 每次发生路由的导航跳转时,都会触发全局前置守卫 。因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制:
const router = new VueRouter({
routes,
})
router.beforeEach((to,from,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到底是做什么的呢?
那什么时候我们会来处理异步事件呢?
- 一种很常见的场景应该就是网络请求了
- 我们封装一个网络请求的函数,因为不能立即拿到结果,所以不能像简单的3+4=7一样返回结果
- 所以往往我们会传入另外一个函数,在数据请求成功时,将数据通过传入的函数回调出去
- 如果只是一个简单的网络请求,那么这种方案不会给我们带来很大的麻烦
但是,当网络请求非常复杂时,就会出现回调地狱
- OK,以一个非常夸张的案例来说明
基本使用:
})
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");
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的链式调用(掌握)
返回目录
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);
})
|