什么是前端路由?
路由的概念来源于服务端,在服务端中路由描述的是 URL 与处理函数之间的映射关系。
在 Web 前端单页应用 SPA(Single Page Application)中,路由描述的是 URL 与 UI 之间的映射关系,这种映射是单向的,即 URL 变化引起 UI 更新(无需刷新页面)。
如何实现前端路由?
要实现前端路由,需要解决两个核心:
-
如何改变 URL 却不引起页面刷新?
-
如何检测 URL 变化了?
下面分别使用 hash 和 history 两种实现方式回答上面的两个核心问题。
hash 实现
-
hash 是 URL 中 hash (#) 及后面的那部分,常用作锚点在页面内进行导航,改变 URL 中的 hash 部分不会引起页面刷新
-
通过 hashchange 事件监听 URL 的变化,改变 URL 的方式只有这几种:通过浏览器前进后退改变 URL、通过
<a>
标签改变 URL、通过window.location改变URL,这几种情况改变 URL 都会触发 hashchange 事件
history 实现
-
history 提供了 pushState 和 replaceState 两个方法,这两个方法改变 URL 的 path 部分不会引起页面刷新
-
history 提供类似 hashchange 事件的 popstate 事件,但 popstate 事件有些不同:通过浏览器前进后退改变 URL 时会触发 popstate 事件,通过pushState/replaceState或
<a>
标签改变 URL 不会触发 popstate 事件。好在我们可以拦截 pushState/replaceState的调用和<a>
标签的点击事件来检测 URL 变化,所以监听 URL 变化可以实现,只是没有 hashchange 那么方便。
前端所谓路由:KV键值对。
key: URL(地址栏中的路径)
value: 相应的路由组件
注意: 项目的上中下结构
Header与Footer组件的注册
创建组件的时候,组件结构+组件的样式+图片资源
在APP.vue中引入组件=>注册组件=>使用组件
<template>
<div>
<Header></Header>
<router-view></router-view>
<!-- 在Home、Search显示,在登录、注册隐藏 -->
<Footer v-show="$route.meta.show"></Footer>
</div>
</template>
<script>
// 引入
import Header from './components/Header'
import Footer from './components/Footer'
export default {
name: '',
components: {
Header,
Footer
}
}
</script>
<style scoped>
</style>
注意: 项目采用的less样式的时候,浏览器不识别less样式,需要通过less、less-loader[安装5版本]进行处理less,把less样式变为css样式,浏览器才可以识别。如果不指定版本,它会默认安装最新版本。这里使用5版本的
npm i --save less less-loader@5
如果想让组件识别less样式,需要在style标签的身上加上lang=“less”属性
附:清除浏览器中的默认样式
@import "./iconfont.css";
/* 清除内外边距 */
body, h1, h2, h3, h4, h5, h6, hr, p, blockquote,
dl, dt, dd, ul, ol, li,
pre,
fieldset, lengend, button, input, textarea,
th, td {
margin: 0;
padding: 0;
}
/* 设置默认字体 */
body,
button, input, select, textarea { /* for ie */
/*font: 12px/1 Tahoma, Helvetica, Arial, "宋体", sans-serif;*/
font: 12px/1.3 "Microsoft YaHei",Tahoma, Helvetica, Arial, "\5b8b\4f53", sans-serif; /* 用 ascii 字符表示,使得在任何编码下都无问题 */
color: #333;
}
h1 { font-size: 18px; /* 18px / 12px = 1.5 */ }
h2 { font-size: 16px; }
h3 { font-size: 14px; }
h4, h5, h6 { font-size: 100%; }
address, cite, dfn, em, var, i{ font-style: normal; } /* 将斜体扶正 */
b, strong{ font-weight: normal; } /* 将粗体扶细 */
code, kbd, pre, samp, tt { font-family: "Courier New", Courier, monospace; } /* 统一等宽字体 */
small { font-size: 12px; } /* 小于 12px 的中文很难阅读,让 small 正常化 */
/* 重置列表元素 */
ul, ol { list-style: none; }
/* 重置文本格式元素 */
a { text-decoration: none; color: #666;}
/* 重置表单元素 */
legend { color: #000; } /* for ie6 */
fieldset, img { border: none; }
button, input, select, textarea {
font-size: 100%; /* 使得表单元素在 ie 下能继承字体大小 */
}
/* 重置表格元素 */
table {
border-collapse: collapse;
border-spacing: 0;
}
/* 重置 hr */
hr {
border: none;
height: 1px;
}
.clearFix::after{
content:"";
display: block;
clear:both;
}
/* 让非ie浏览器默认也显示垂直滚动条,防止因滚动条引起的闪烁 */
html { overflow-y: scroll; }
a:link:hover{
color : rgb(79, 76, 212) !important;
text-decoration: underline;
}
/* 清除浮动 */
.clearfix::after {
display: block;
height: 0;
content: "";
clear: both;
visibility: hidden;
}
在index.html文件中的head内全局引入文件
<!-- 引入清除默认的样式 -->
<link rel="stylesheet" href="./reset.css">
路由组件的搭建
先下载router路由插件
npm i --save vue-router
- components文件夹: 经常放置的非路由组件(共用全局组件)
- pages|views文件夹:经常放置路由组件
router文件下的index.js文件
项目当中配置的路由一般放置在router文件夹中
// 配置路由的地方
import Vue from 'vue'
import VueRouter from 'vue-router'
// 使用插件
Vue.use(VueRouter)
// 引入路由组件
import Home from '@/pages/Home'
import Search from '@/pages/Search'
import Login from '@/pages/Login'
import Register from '@/pages/Register'
// 配置路由,new一个VueRouter实例
export default new VueRouter({
routes:[
{
path: "/home",
component: Home
}, {
path: "/search/:keyword?",
component: Search,
}, {
path: "/login",
component: Login,
}, {
path: "/register",
component: Register,
}, { // 重定向,在项目跑起来的时候,访问/,立马让它定向到首页
path: '*',
name: 'Home',
},
})
总结:
路由组件与非路由组件的区别
- 路由组件一般放置在pages|views文件夹,非路由组件一般放置在components文件夹中
- 路由组件一般需要在router文件夹中进行注册(使用的即为组件的名字),非路由组件
- 注册完路由,不管路由组件、还是非路由组件身上都有$route\$router属性
$route:一般获取路由信息【路径、query、params等等】
$router:一般进行编程式导航进行路由跳转【push|replace】
注册路由:底下的写法KV一致省略V【router小写的】
注册路由信息:当这里书写router的时候,组件身上都拥有$route,$router属性
路由的跳转
路由的跳转有两种形式:
声明式导航router-link,没有其他业务逻辑,单纯地页面跳转
<!-- 声明式导航:务必要有to属性 -->
<router-link to="/login">登录</router-link>
编程式导航push|replace,可以添加其他业务逻辑
在绑定的函数中:
goSearch() {
this.$router.push("/search");
}
注意:编程式导航:声明式导航能做的,编程式导航都能做;但是编程式导航除了可以进行路由跳转,还可以做一些其他的业务逻辑
路由元信息的使用
例如,Footer组件显示与隐藏。
1.使用显示或者隐藏组件:v-if|v-show
Footer组件:在Home、Search显示Footer组件
Footer组件:在登录、注册时候隐藏的
2.使用路由元信息
我们可以根据组件身上的$route获取当前的路由信息,通过路由路径判断Footer显示与隐藏。
export default new VueRouter({
routes:[
{
path: "/home",
component: Home,
meta: {show: true}
}, {
path: "/search/:keyword?",
component: Search,
meta: {show: true},
}, {
path: "/login",
component: Login,
meta: {show: false}
}, {
path: "/register",
component: Register,
meta: {show: false}
}, { // 重定向,在项目跑起来的时候,访问/,立马让它定向到首页
path: '*',
name: 'Home',
},
})
在组件中使用路由元信息
<Footer v-show="$route.meta.show"></Footer>
注意:配置的路由的时候,可以给路由添加路由元信息【mate】,路由需要配置对象,他的key不能自定义
路由传参
路由跳转有几种方式 比如:A=>B
声明式导航:router-link(务必要有to属性),可以实现路由的跳转
编程式导航:利用的是组件实例的$router.push|replace方法,可以实现路由跳转(可以书写一些自己的业务)
路由传参有几种写法?
params参数:属于路径当中的一部分,需要注意,在配置路由的时候,需要占位
query参数:不属于路径当中的一部分,类似于ajax中的queryString /home?k=v&kv=,不需要占位
<h1>params参数{{ $route.params.keyword }}</h1>
<h1>query参数{{ $route.query.k }}</h1>
第一种:字符串形式
this.$router.push("/search/" + this.keyword + "?k=" + this.keyword.toUpperCase())
第二种:模板字符串
this.$router.push(`/search/${this.keyword}?k=${this.keyword.toUpperCase()}`)
第三种:对象(常用写法)
注意,在使用这种写法前,要给路由命名
{
path: "/search/:keyword?",
component: Search,
meta: {show: true},
name: "search"
},
this.$router.push({name: "search", params: {keyword: this.keyword}, query: {k: this.keyword.toUpperCase()}})