Vue学习-路由router
认识路由
什么是前端渲染,什么是后端渲染?
后端渲染阶段
后端渲染: JSP - java server page
后台收到请求之后,html+css+java, java代码作用是从数据库中读取数据,并将它动态的放在页面中,页面在服务器端已经渲染好了,然后直接渲染好的页面返回给前端(html+css)
后端路由:后台处理URL和页面之间的映射关系
后端路由的缺点:
- 整个页面的模块由后端人员来编写和维护的
- 前端开发人员如果开发页面,需要通过php,Java等语言来编写页面代码
- 通常情况下HTML代码和数据以及对应的逻辑会混在一起,编写和维护都是非常糟糕的事情
前后端分离阶段
输入jd.com,先去静态资源浏览器请求静态资源(html+css+js),当浏览器引擎执行JS代码时,会触发API请求,会去后台的API服务器上请求数据。
前端渲染:浏览器中显示的网页中的大部分内容,都是由前端写的JS代码,在浏览器中执行,最终渲染出来的网页。
- 随着Ajax的出现,由了前后端分离的开发模式
- 后端只提供API来返回数据,前端通过Ajax获取数据,并且可以通过JS将数据渲染到页面中
- 这样做最大的优点就是前后端责任的清晰,后端专注于数据上,前端专注于交互和可视化上
- 并且当移动端出现后,后端不需要进行任何处理,依然使用之前的一套API即可
前端路由阶段(单页面富应用阶段)
前后端分离的基础之上,加上前端路由
SPA应用:整个网站只有一个HTML页面,一套html+css+js
前端路由:页面与静态资源的映射关系由前端来管理,改变URL,页面不会整体刷新
url的hash和HTML5的history
URL中的hash
- URL中的hash也就是锚点(#),本质上是改变window.location的href属性
- 可以通过直接赋值location.hash来改变href,但是页面不会发生刷新
location.hash = 'aaa'
HTML5中的history
history.pushState({}, '', 'home')
压入history.replaceState({}, '', 'home')
替换- replace不能返回之前的页面(替换了), push可以返回到之前的页面
history.go()
参数: -1:history.back()
1:history.forward()
Vue-router基本使用
安装vue-router
npm install vue-router --save
在模块化工程中使用vue-router(插件,可以用过Vue.use()来使用路由功能)
- 导入路由对象,并且调用Vue.use(VueRouter)
- 创建路由实例,并且传入路由映射配置
- Vue实例中挂载创建的路由实例
框架搭建
import Vue from 'vue'
// 导入路由对象,并且调用Vue.use(VueRouter)
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
// 创建路由实例,并且传入路由映射配置
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
// 先导出,然后在main.js中,Vue实例中挂载创建的路由实例
export default router
配置路由
- 创建路由组件
- 配置路由映射:组件和路径映射关系
- 使用路由:通过和
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
// 路由懒加载
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<router-view></router-view>
路由的默认值和修改为history模式
路由的默认值
{ path: '/', redirect: 'home' }
history模式
mode: history
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
router-link的其他属性
tag属性
默认渲染为a标签,想要渲染为其他元素,使用tag属性
<router-link to="/home" tag="button">首页</router-link>
<router-link to="/about" tag="button">关于</router-link>
replace属性
默认使用pushState,如果想使用replaceState,使用replace属性
<router-link to="/home" tag="button" replace>首页</router-link>
<router-link to="/about" tag="button" replace>关于</router-link>
.router-link-active
选中的router-link会自动具有.router-link-active类,可以直接通过该类设置样式,比如选中的字体变为红色
.router-link-active {
color: red;
}
.router-link-active简写模式
<router-link to="/home" tag="button" replace active-class="acive">首页</router-link>
<router-link to="/about" tag="button" replace active-class="acive">关于</router-link>
.active {
color: red;
}
统一修改active-class
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
linkActiveClass: 'active'
})
通过代码跳转路由
this.$router.push('/home');
this.$router.replace('/home')
动态路由
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<router-link to="/user/zhangsan">用户</router-link>
<router-link :to="'/user/' + userId">用户</router-link>
{ path: '/user/:userId', component: User }
或者
this.$router.push('/user/' + this.userId)
User.vue
中获取到userId
{{ $route.params.userId }}
或者
this.$route.params.userId
// $route: 处于活跃中的路由
// $router: 整个路由对象
路由的懒加载
-
当打包构建应用时,Javascript包会变得非常大,影响页面加载
-
如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样跟高效(一个路由打包一个JS文件)
-
懒加载:用到的时候再加载
// 推荐的方式
const routes = [
{ path: '/home', component: () => import('../components/Home') },
{ path: '/about', component: () => import('../components/About') }
]
或者
const About = resolve => require(['../components/About.vue'], resolve);
Vue-router嵌套路由
认识路由嵌套
- 比如在home页面中,我们希望通过/home/news和/home/message访问一些内容
- 一个路径映射一个组件,访问这两个路径也会分别渲染两个组件
创建嵌套路由的步骤
- 创建对应的子组件,并且在路由映射中配置对应的子路由
- 在组件内部使用标签
{ path: '/home', component: Home, children: [
{ path: 'news', component: HomeNews },
{ path: 'message', component: HomeMessage },
{ path: '/', redirect: 'news' }
] }
<router-link to="/home/news">新闻</router-link>
<router-link to="/home/message">消息</router-link>
Vue-router参数传递
从一个页面跳转到另一个页面,希望传递一些消息
方法1: 动态路由中讲到的方法可以传递参数
- 配置路由格式: /router/:id
- 传递的方式: 在path后面跟上对应的值
- 传递后形成的路径: /route/123, /route/abc
方法2: query方式
- 配置路由格式:/router,也就是普通配置
- 传递的方式:对象中使用query的key作为传递方式
- 传递后形成的路径: /router?id=123 , /router?id=abc
<router-link :to="{ path: '/profile', query: { name: 'xx', age: 18, height: 1.88 } }"></router-link>
或者
this.$router.push({
path: '/profile',
query: {
name: 'xx',
age: 18,
height: 1.88
}
})
{{ $route.query.name }}
或者
this.$route.query.name
Vue-router: router和route的由来
所有组件(.vue)都继承着vue的原型,vue原型上又挂载了routerg和route
Vue.prototype.$router = {
...
}
Vue.prototype.$route = {
...
}
或者
Object.defineProperty(Vue.prototype, '$router', ...);
Object.defineProperty(Vue.prototype, '$route', ...);
this.$router
就是vueRouter类的一个实例
this.$route
是处于活跃的路由
Vue-router导航守卫
需求:
在一个SPA应用中,如何改变网页的标题?
- 网页标题是通过
<title>
来显示的,但是SPA只有一个固定的HTML,切换不同的页面时,标题并不会改变 - 可以通过Javascript来修改
<title>
的内容,window.document.
- 那么在VUE项目中,如何实现?
方案1: 利用生命周期函数created实现
方案2:利用全局导航守卫 (前置钩子,前置守卫)
router.beforeEach((to, from, next) => {
// 从from跳转到to
document.title = to.matched[0].meta.title;
next();
})
{ path: '/home', component: Home, meta: { title: '首页' } }
后置钩子:
afterEach, 已经跳转完了
router.afterEach((to, from) => {
})
路由独享守卫
const router = new VueRouter({
routes: [{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
}
}]
})
keep-alive
- keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染
- router-view也是一个组件,如果直接被包在keep-alive中,所有路径匹配的到的视图组件都会被缓存
<keep-alive>
<router-view></router-view>
</keep-alive>
-
activated()
和deactivated()
钩子函数只有在被keep-alive包裹的时候才会生效 -
如果希望组件中的某一个被频繁的创建和销毁
这里 Profile,User逗号后面不要加空格
<keep-alive exclude="Profile,User"> <router-view></router-view> </keep-alive>
路径别名
vue-cli3中可以使用@
代替src
案例
App.vue
<template>
<div id="app">
<router-view></router-view>
<tab-bar>
<tab-bar-item path="/home" activeColor="red">
<img src="./assets/image/tabbar/首页.svg" slot="item-icon">
<img src="./assets/image/tabbar/首页_active.svg" slot="item-icon-active">
<div slot="item-text">首页</div>
</tab-bar-item>
<tab-bar-item path="/category" activeColor="skyblue">
<img src="./assets/image/tabbar/分类.svg" slot="item-icon">
<img src="./assets/image/tabbar/分类_active.svg" slot="item-icon-active">
<div slot="item-text">分类</div>
</tab-bar-item>
<tab-bar-item path="/cart" activeColor="green">
<img src="./assets/image/tabbar/购物车.svg" slot="item-icon">
<img src="./assets/image/tabbar/购物车_active.svg" slot="item-icon-active">
<div slot="item-text">购物车</div>
</tab-bar-item>
<tab-bar-item path="/profile">
<img src="./assets/image/tabbar/我的.svg" slot="item-icon">
<img src="./assets/image/tabbar/我的_active.svg" slot="item-icon-active">
<div slot="item-text">我的</div>
</tab-bar-item>
</tab-bar>
</div>
</template>
<script>
import TabBar from "./components/tabbar/TabBar";
import TabBarItem from "./components/tabbar/TabBarItem";
export default {
name: 'App',
components: {
TabBar,
TabBarItem
}
}
</script>
<style lang="css">
@import './assets/css/base.css';
</style>
TabBar.vue
<!-- -->
<template>
<div id="tab-bar">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'TabBar',
data () {
return {
};
}
}
</script>
<style lang='css' scoped>
#tab-bar {
display: flex;
background-color: #f6f6f6;
position: fixed;
left: 0;
right: 0;
bottom: 0;
/* 阴影 */
box-shadow: 0px -1px 1px rgba(100, 100, 100, 0.2);
}
</style>
TabBarItem.vue
<!-- -->
<template>
<div class="tab-bar-item" @click="itemClick">
<div v-if="!isActive"><slot name="item-icon"></slot></div>
<div v-else><slot name="item-icon-active"></slot></div>
<div :style="activeStyle">
<slot name="item-text"></slot>
</div>
</div>
</template>
<script>
export default {
name: 'TabBarItem',
props: {
path: String,
activeColor: {
type: String,
default: 'red'
}
},
data() {
return {
};
},
methods: {
itemClick() {
this.$router.push(this.path).catch(err => {});
}
},
computed: {
isActive() {
return this.$route.path.indexOf(this.path) !== -1;
},
activeStyle() {
return this.isActive ? { color: this.activeColor } : {};
}
}
};
</script>
<style lang='css' scoped>
.tab-bar-item {
flex: 1;
text-align: center;
height: 49px;
font-size: 14px;
}
.tab-bar-item img {
width: 24px;
height: 24px;
margin-top: 3px;
vertical-align: middle;
}
</style>
效果图
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!