1.后端路由阶段
- 流程:用户在浏览器中输入url→发送给服务器解析→通过jsp(java serve page)把网页(包含html,css,java(java作用:从数据库中读取数据并将数据动态地放在页面中))渲染好→将网页传给浏览器(传过去的网页只有html和css)
- 后端渲染(服务端渲染):后端通过jsp/php等技术把页面渲染好了
- 后端路由:后端处理url映射到不同的页面
2.前后端分离阶段
- 简述:此时后端只负责提供数据,不负责任何阶段的内容,服务器分为静态资源服务器和提供api接口的服务器
- 流程:用户在浏览器中输入url→从静态资源服务器中获取对应网页的js html css代码→浏览器执行js代码,向api接口服务器请求数据→api服务器返回大量数据→网页中其他js代码生成带有数据的标签→通过js代码渲染到网页
- 前端渲染:浏览器中显示的网页的大部分内容都是由前端的js代码在浏览器中执行,最终渲染出来的网页
3.SPA页面
- 区别于前后端分离:此时也有静态资源服务器,前后端分离阶段中每个url对应一套js html css,spa中只有一套js html css
- 流程:用户输入url→从静态资源服务器中获取所有js html css代码→根据用户不同的操作抽取对应的 一部分 html css js到页面中,不会向静态资源服务器中再请求资源(前后端分离阶段会)
前端路由:用于映射url和相应要渲染的资源(根据用户操作如点击生成不同的url)
4.运行一个vue-router小demo
-
我的步骤:
- 1.在router文件夹里面创建index.js,创建router实例
- 2.创建对应组件 并建立映射关系
- 3.在main.js里面导入有映射关系的index.js,挂载router实例(这样才可以在所有组件中使用
$router
,等同于操作Vue.prototype.$router
) - 4.将main.js所解析的App.vue template里写上router-link表签
-
标准步骤:
- 1.导入路由对象,并且调用 Vue.use(VueRouter)
- 2.创建路由实例,并且传入路由映射配置
- 3.在Vue实例中挂载创建的路由实例
- 4.创建路由组件 并 配置路由映射: 组件和路径映射关系(我在第二步先做也没问题)
- 5.使用路由: 通过
<router-link/>
(用于显示标签)和<router-view>
(用于给组件占位)
5.路由的默认路径
- 意义:打开网站默认显示主页
- 用法(默认访问home):
const routes = [
{
path: '', //缺省是默认的意思
redirect: "/home" //redirect是重定向, 也就是将默认路径重定向到/home的路径下
},
{
path: "/home",
component: home
},
{
path: "/about",
component: about
}
];
6.history模式
- 意义:非history模式中url里面含有 # 号
- 用法:创建路由实例的时候,属性里面添加 mode 属性即可
const router = new VueRouter({
routes,
mode: "history"
});
7.router-link的一些属性
- 改变router-link样式:tag=其他标签
- 取消history.pushState()模式,采用history.replace()模式:replace
- 当
<router-link>
对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class, 设置active-class可以改变配对成功的元素的样式 - 举例:
App.vue:
<template>
<div id="app">
<router-link to="/about" tag="button" replace active-class="active">关于</router-link>
<router-link to="/home" tag="button" replace active-class="active">首页</router-link>
<router-view></router-view>
</div>
</template>
- 效果:
8.用代码转跳路由
- 用法:
this.$router.push("address")/this.$router.replace("address")
<template>
<div id="app">
<router-view></router-view>
<button @click="homeClick">首页</button>
<button @click="aboutClick">关于</button>
</div>
</template>
<script>
export default {
name: 'App',
methods: {
homeClick() {
console.log("homeClick");
this.$router.push("/home"); //等同于pushState,可以换成replace
},
aboutClick() {
console.log("aboutClick");
this.$router.push("/about");
}
}
}
</script>
- 效果和普通转跳一致
9.动态路由
- 意义:组件页template里获取 当前路由页面的参数
- 步骤:
- 1.注册User组件并建立动态映射
- 2.App.vue 里面 link-router v-bind动态绑定to属性
- 3.$route.params获取当前路由页面的参数
User.js:
<template>
<div>
<h2>我是User</h2>
<h2>{{this.$route.params.userId}}</h2>
</div>
</template>
- 效果:
10.路由懒加载
- 意义:上面第3点说到:前端路由阶段,从静态资源服务器中获取所有js html css(获取的都是js,拿到再解析)代码。所有js文件一起获取量大,效率低,所以希望当路由被访问的时候才加载对应组件(js)
- 写法:将import转化为箭头函数的写法,其他无需改变,重新打包可以看到每个组件占一个js文件(dist/static/js)
// import Home from "../components/Home";
// import About from "../components/About";
// import User from "../components/User";
const Home = () => import("../components/Home");
const About = () => import("../components/About");
const User = () => import("../components/User");
11.二级路由
- 意义:在home页面中, 我们希望通过/home/news和/home/message访问一些内容
- 步骤:
- 1.创建对应页面并建立映射关系
- 2.在home.vue里面写router-link
- 代码:
Home.vue:
<template>
<div>
<h2>我是Home</h2>
<router-link to="/home/news">新闻</router-link>
<router-link to="/home/message">消息</router-link>
<router-view> </router-view>
</div>
</template>
- 结果:
12.参数传递方式
- 方式一:通过to属性的query传递参数
- 意义:这样页面可以访问url中的query参数(参考url组成)
- 方式:router-link to属性中传入query参数,组件页面再通过$route.query访问
- 代码:
App.vue
<router-link :to="{
path:'/profile',
query:{
height: 188,
weight: 140,
age :19
}
}" tag="button" replace active-class="active">用户</router-link>
Profile.vue:
<template>
<div>
<h2>我是Profile</h2>
<ul>
<li>{{$route.query.age}}</li>
<li>{{$route.query.weight}}</li>
<li>{{$route.query.height}}</li>
</ul>
</div>
</template>
- 效果:
- 方式二:用$router.push传值
- 代码:
App.vue:
<button @click="profileClick">档案</button>
profileClick() {
this.$router.push({
path: "/profile",
query: {
height: 188,
weight: 140,
age: 19
}
})
}
Profile.vue:
<template>
<div>
<h2>我是Profile</h2>
<ul>
<li>{{$route.query.age}}</li>
<li>{{$route.query.weight}}</li>
<li>{{$route.query.height}}</li>
</ul>
</div>
</template>
效果同上
13.$route
和$router
的区别
- $router:为VueRouter实例,可以认为是全局的路由对象,包含了所有路由的对象和属性,无论在哪里打印都一样
- $router:为当前router跳转对象,包含当前url解析得到的数据,里面可以获取name、path、query、params等
在当前路由页面打印:
$router可以看做是建立映射关系时创建的routes数组里的当前页面对应对象的扩充
const routes = [
{
path: "/user/:userId",
component: User
},
{
path: "/profile",
component: Profile
} //就是这个对象的扩充
];
14.全局导航守卫
- 介绍:导航守卫主要用来监听监听路由的进入和离开的
- 意义:有一个需求,用户转跳页面的时候页面标题也相应改变,通常情况联想到在页面(组 件)生命周期函数中加载的时候改变标题,但是还有一种更好的方法,就是全局路由守卫方法,在index.js里面调用vue-router提供的beforeEach钩子函数, 它们会在路由即将改变前和改变后触发.(router就是全局)
写法:
index.js:
//导航钩子的三个参数解析:
//to: 即将要进入的目标的路由对象.
//from: 当前导航即将要离开的路由对象.
//next: 调用该方法后, 才能进入下一个钩子
router.beforeEach((to, from, next) => {
next(); //这个规定要写,不写转跳异常
document.title = to.matched[0].meta.title;
// to是route路由对象,所以所有参数都是在route里面取出来的,matched[0]因为有子组件时to.meta.title为空
console.log(to);
});
- 打印结果:
15.keep-alive的作用
- 意义:有一个需求,用户转跳页面再返回原来页面的时候,希望页面内容是转跳前的内容
方法:在home.vue(转跳前组件)中添加beforeRouteLeave方法(离开导航守卫)记录转跳出去前页面的最终路径,用一个变量保存,返回时,actived周期函数调用this.$router.push(this.path);,转跳最终路径,注意actived在有keep-alive的情况下才能回调 - 代码:
App.vue:
<keep-alive>
<router-view> </router-view>
</keep-alive>
Home.vue:
<script>
export default {
name: "home",
activated() {
console.log("home activated");
this.$router.push(this.path);
},
deactivated() {
console.log("home deactivated");
}, //失活周期函数,也要加上,不加报错
beforeRouteLeave (to, from, next) {
next();
this.path = this.$route.path;
},
data(){
return{
path: "/home/news"
}
}
}
</script>
- 效果:
- keep-alive 有两个非常重要的属性:
include - 字符串或正则表达,只有匹配的组件会被缓存
exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存
<keep-alive include="Home">
<router-view> </router-view>
</keep-alive>
16.属性传值props和路由搭配使用举例
- 意义:点击触发页面转跳和活跃路由颜色改变
- 代码:
App.vue:
<tab-bar-item path="/home" activeColor="pink"> </tab-bar-item>
TabBarItem.vue:
<template>
<div class="tab-bar-item" @click="itemClick">
<div v-if="!isActive"><slot name="item-image"> </slot></div>
<div v-else><slot name="item-image-active"> </slot></div>
<div :style="isActive ? {color: activeColor}: {}"><slot name="item-text"> </slot></div>
<!--v-if和v-else 作用于图片激活情况,:style作用于文字颜色样式-->
</div>
</template>
<script>
export default {
name: "TabBarItem",
data(){
return{
// isActive: true
}
},
methods: {
itemClick(){
this.$router.push(this.path);
}
},
props: {
path:{
type: String
},
activeColor: {
type: String
}
},
computed:{
isActive(){
return this.$route.path == this.path;
}
}
}
</script>
- 代码逻辑:封装好的组件标签属性里传值(props用法,每个标签传值不同),组件内部收到值并可以使用,作为判断活跃的依据,再进行下一步操作