认识路由
路由的本质是一种 对应关系 ,程序开发分为前端路由和后端路由。url 地址和真实的资源之间就有一种对应的关系,就是 路由 。
什么是前端路由
前端路由就是把不同路由对应不同的内容或页面的任务交给前端来做。对于单页的应用(SPA)来说,主要通过 URL 中的 hash (#号)来实现不同页面之间的切换。hash 有一个特点,就是 HTTP 请求中不会包含 hash 线管的内容,所以单页面程序中的页面跳转主要用 hash 来实现。前端路由是依靠 hash 值(锚点链接)的变化来实现页面内容的切换,也就是锚点与组件之间的关系 。
什么是后端路由
后端路由是由服务端进行实现,并完成资源的分发,即url 地址与资源/数据的对应关系。
Vue-router
vue-router 工作原理
vue-router 是一个 Vue.js 官方提供的路由管理器,是一个功能更加强大的前端路由器。它也是单页面应用(SPA)的核心思想之一,就是更新视图不需要重新请求页面。简而言之,vue-router 加载页面时,不会加载整个页面,指定更新某个指定的容器中的内容。
在实现页面前端路由时,提供了两种方式,分别是 hash 模式和 history模式,根据 mode 来决定采用哪一种方式。
hash 模式
vue-router 默认为 hash 模式,使用 URL的 hash 来模拟一个完整的 URL ,当 URL 改变时,页面不会重新加载。 # 是 hash 符号,中文名哈希符或者锚点,在 hash 符号后的值,称为 hash 值。 路由的 hash 模式是利用了 windows 可以监听 onhashchange 事件来实现,hash 值是用来知道浏览器动作的,对服务器没有影响, HTTP 请求中也不会包括 hash 值,同时每一次改变 hash 值,都会在浏览器的访问历史中增加一个记录,使用“后退”按钮,就可以回到上一个位置。hash 模式是根据 hash 值来发生改变,根据不同的值,渲染指定 DOM位置的不同数据
history 模式
history 模式不会出现# 号比较美观,这种模式充分利用 history.pushState() 来完成 URL 的跳转而且无须重新加载页面。使用 history 模式时,需要在路由规则配置中增加 mode:“history”,实例代码如下:
// js 文件
const router = new VueRouter({
mode:"history",
route:[...]
})
vue-router 基本使用
vue-router 可以实现用户单击页面中的 A 按钮时,页面显示 A 内容;单击 B 按钮时,页面显示 B 内容。用户单击的按钮和页面显示之间有对应的关系。
- route: 一条路由,单数形式
- routes: 一组路由,route 每一条路由组合起来,形成一个数组
- router:一个机制,充当管理路由的管理角色
注意: 必须先引入 vue.js,再引入vue-router.js 。理由:vue-router 需要在全局 VUE 的实例上挂载 vue-router 相关的属性。
vue-router.js的地址
<div id="app">
<router-link to="/login" tag="span"><button>前往登录 yzx </button></router-link>
<router-view></router-view>
</div>
<script>
var login = { //创建登录组件
template:"<h1>登陆组件</h1>"
}
var routerObj = new VueRouter({ // 设置路由匹配规则
routes:[{path:'/login',component:login}]
})
var vm = new Vue({
el:"#app",
router:routerObj, // 将路由规则对象注册到 vm 实例上
data:{}
})
</script>
路由对象的属性
路由对象(route object)当前激活的路由的状态信息,包含了当前 URL 解析得到的信息,还有 URL 匹配到的路由记录。路由对象是不可变的,每次成功地导航后都会产生一个新的对象。
this.$router
this.$router 表示全局路由器对象,项目中通过 router 路由参数注入路由之后,在任何一个页面都可以通过此属性获取到路由器对象,并调用其 push(),go()的方法。this. $router 表示当前正在用于跳转的路由对象,可以访问其 name,path,query,params 等属性。
路由对象 $route 的常用属性:
属性名 | 类型 | 说明 |
---|---|---|
$route.path | String | 对应当前路由的路径 |
$route.query | Object | 一个{key:value}对象,表示 URL 查询参数 |
$route.params | Object | 一个{key:value}对象,路由跳转携带参数 |
$route.hash | String | 在history 模式下获取当前路由的 hash 值(#),如果没有 hash 值,则为空字符串 |
$route.fullPath | String | 完成解析的 URL ,包含查询参数和 hash 的完整路径 |
$route.name | String | 当前路由的名称 |
$route.matched | Array | 路由记录,当前路由下路由声明的所有信息,从父路由(r如果有)到当前路由为止 |
$route.redirectedFrom | String | 如果存在重定向,即为重定向来源的路由 |
用户登陆注册案例
手动搭建一个 webpack + Vue 的项目,掌握相关loader 的安装与使用。熟悉webpack 的配置,文件打包,以及路由的配置和使用。登录和注册是项目开发中经常遇到的功能需求,在网页中需要登陆后才可以使用某些功能。
前期准备
初始化项目
创建目录 E:\VScodeprojects\luyou 并且切换到改目录,执行命令 npm init -y (-y 表示全部默认啦~)。这里不用跟我一样,你自己随便搞个目录也行,不要用中文目录就🆗 (npm 是需要安装的,npm install -g 安装到全局,前面安装过了,不啰嗦了哈😁)
完成之后,在该目录下会生成一个 package.json 文件,如图所示:
安装vue 和vue-router
还是刚刚的目录下,输入命令npm install vue@2.6.x vue-router@3.1.x
那个warn 警告不要管,不影响操作,哈哈哈~
执行完之后,在当前目录下自动生成一个 package-lock.json 文件
安装 webpack
项目中需要打包文件,所以需要用到打包工具,是按打包编译的功能。为了更方便使用,需要安装一些插件,输入命令 npm install webpack@4.39.x webpack-cli@3.3.x webpack-dev-server@3.8.x html-webpack-plugin@3.2.x -D (-D 表示安装到本地开发依赖)
这样就成功了,上面一些 warn 不要管,不要纠结过程,成功就行了🤣😅
需改 package.json 文件
在script 中 添加 “dev”: “webpack-dev-server --inline --hot --port 9090” (9090 是端口号,你随便写个好嘛🏹) ,别忘了,加个小逗号🚗
添加这行代码之后,当需要运行项目是,执行 npm run dev [咱等会再运行哈😘]
编写webpack.config.js 文件
创建webpack.config.js文件,配置文件代码如下:
const htmlWebpackPlugin = require('html-webpack-plugin')
module.exports={
entry:'./main.js', //配置入口文件
ouput:{ //配置输出文件
path:__dirname, //输出文件的路径
filename:'bundle.js', //指定输出的文件名称
},
resolve:{ //其他的配置选项
alias:{
'vue':'./js/vue.js' // vue.js 文件路径设置
}
},
module:{rules:[]}, //模块规则
plugins:[ //插件
new htmlWebpackPlugin({
template:'index.html' // 为index.html 自动引入打包好的bundle.js文件
}),
]
}
安装vue-loader ,vue-template-compiler
vue-loader 作用是解析和转换vue 文件,提取其中的 script ,style, html,template ,然后分别把他们交给各自对应的loader 去处理。vue-template-comlier 的作用是把 vue-loader 提取出来的 html 模板编译成对应的可执行的JavaScript 代码。安装命令:npm install vue-loader@15.7.x vue-template-compiler@2.6.x -D 安装成功如下图:
安装之后,将vue-loader 插件安装到webpack.config.js 文件中
module.exports ={
...
plgugins:[
new VueLoaderPlugin()
]
...
}
在rules数组中配置 loader 加载依赖
rules:[ //模块规则
{
test:/\.vue$/,
use:'vue-loader'
}
安装css-loader ,style-loader
css-loader 和 style 用来处理样式文件,安装命令:npm install css-loader@3.2.x style-loader@1.0.x -D
在rules数组中配置 css-loader ,style-loader 加载依赖。 能看懂吧,跟刚刚那个添加loader 依赖一样的,下图我就直接给 rules 的代码了。
test:/\.css$/,
use:['style-loader','css-loader']
安装 CSS 预处理器
通过 CSS 处理器可以使用专门的编程语言来编写页面的样式,然后编译成正常的 CSS 文件,仅供项目使用。 CSS 预处理器为 CSS 增加了一些编程的特性,用户无需考虑浏览器的兼容性问题,可以 CSS 更加简洁,更具有适用性和可读性,更易于代码的维护。Vue中常用的 CSS 预处理器 Less , Sass /SCSS 和Stylus 。本项目用的是 Sass /SCSS 安装。三种安装我都说一下哈,莫急😜
- 安装 Less 指令:npm install less-loader -D
添加 rules 规则:test:/\.less$/,use:['style-loader','css-loader','less-loader']
添加 style 样式:<style lang="less"></style>
- 安装 Sass/SCSS指令:npm install sass-loader@7.2.x node-sass@4.12.x -D
添加 rules 规则:test:/\.less$/,use:['style-loader','css-loader','sass-loader']
添加 style 样式:<style lang="scss"></style>
- 安装Stylus 指令:npm install stylue stylue-loader -D
Stylus安装之后,Vue 2.x中不需要配置就可以直接使用
添加 style 样式:<style lang="stylus"></style>
安装 MUI
MUI 是由DCloud (数字天堂) 推出的一款接近原生APP 体验的高性能前端框架,在本项目中主要用来快速搭建登录和注册页面。需要从官方网站下载 MUI ,本次使用的版本是mui-3.7.1.zip。 下载之后解压,将dist 目录下的所有文件复制到 项目的lib\mui 目录中。
在main.js添加:import './lib/mui/css/mui.css'
图片和字体文件处理
考虑到项目使用了外部的 MUI 样式库,其中包含后缀名为 ttf 的文件,webpack 无法处理该类文件,所以需要安装相应的 loader 去处理。file-loader ,url-loader 都可以在webpack 中处理图片,字体图标等文件,后者可以将图片转为base64 字符串,能更快地加载图片,并且可以通过 limit 属性对图片分情况处理,当图片< limit (单位byte) 大小时转为base64,>limit 时调用file-loader 对图片进行处理。
安装 file-loader ,url-loader 指令:npm install url-loader@2.1.x file-loader@4.2.x -D
添加 rules 规则:test:/\.(jpg|png|gif|bmp|jpeg)$/,use:'url-loader'
test:/\(ttf|eot|svg|woff|woff2)$/,use:'url-loader'
😆🙃😭早知道不写这个了,这么麻烦,亲们,你们要跟我一样坚持下去,奥力给( •̀ ω •́ )
代码实现
编写首页
在 index.html 编写代码:<div id="app"></div>
编写入口程序
在main.js 文件中,用来初始化 Vue 实例并加载需要的插件和各种公共组件。
import Vue from 'vue' //引入vue.js
import app from './App.vue' //引入 App.vue 组件
import VueRouter from 'vue-router' //引入router.js组件
Vue.use(VueRouter) //安装vue-router 路由模块
import router from './router.js' //将路由放到单独的文件中
import './lib/mui/css/mui.css'
new Vue({ //初始化 Vue实例
el:'#app', //将el 挂载到index.html 文件的<div id="app">
render:c=>c(app), //使用router.js 文件中导出的 router对象注册到 Vue 实例上
router
})
编写路由文件
在 router.js 文件,是一个单独的路由文件。需要创建 Login.vue 登录和 Regsiter 注册 两个组件。
import VueRouter from 'vue-router'
import Login from './components/Login.vue' //导入登录对应的路由组件
import Regsiter from './components/Register.vue' //导入注册对应的路由组件
var router = new VueRouter({ //创建路由对象
routers:[ //配置路由规则
{path:'/',redirect:'/login'},
{path:'/login',components:Login},
{path:'/register',components:Regsiter}
]
})
export default router
渲染路由组件
编写 App.vue文件。
<template>
<div id="app">
<div class="login-container">
<router-link to="/login" tag ="span">登录</router-link>
<router-link to="/register" tag ="span">注册</router-link>
</div>
<router-view></router-view>
</div>
</template>
<style lang="scss scoped> //scoped 表示CSS 样式只能作用与当前组件
.login-container {
display:flex;
justify-content:center;
padding-top:10px;
span{
padding:5px 20px;
border-radius:5px;
font-size:16px;
}
}
</style>
编写登录页面
编写 Login.vue ,该文件是登录页面,在页面中提供一个用户登录的表单。
<template>
<div class="login">
<div class="content">
<from class="mui-input-group login-form">
<div class="mui-input-row"><label>账号</label><input/></div>
<div class="mui-input-row"><label>密码</label><input/></div>
</from>
<div><button type="button">登录</button></div>
</div>
</div>
</template>
<style scoped></style>
编写注册页面
编写 Register.vue ,该文件是登录页面,在页面中提供一个用户注册的表单。
<template>
<div class="register">
<div class="content">
<from class="mui-input-group login-form">
<div class="mui-input-row"><label>账号</label><input/></div>
<div class="mui-input-row"><label>密码</label><input/></div>
</from>
<div><button type="button">注册</button></div>
</div>
</div>
</template>
<style scoped></style>
运行项目
切换到项目的根目录下,执行命令 npm run dev 看到下图的字就表达成功了~
打开谷歌浏览器,访问 9090 端口看到如下图的就可以了
动态路由
什么是动态路由
以上所述路由,都是严格匹配的,只有 router-link 中的to属性和路由规则中定义的路由的path 一样时,才会显示对应的component。但是在实际开发中,这种方式明显不太行啊。
注意:动态路由来回切换时,由于它都是指向同一组件,Vue不会销毁在重新创建这个组件,而是复用这个组件。
利用 watch来监听 $route 的变化,实现组件来回切换的操作,代码如下所示:
watch:{
$route(to,from){
console.log(to) //to表示要求的那个组件
console.log(from) //from表示从哪个组件过来的
}
}
query 方式传参
通过 query 方式传递参数,使用path 属性给定对应的跳转路径,在页面跳转的时候,可以在地质栏看到请求参数。
如下代码需要引用vue.js和vue-router.js:
<div id="app">
<router-link to="/user?id=01&name=yzxadmin">登录</router-link>
<router-view></router-view>
</div>
<script>
var user ={
template:'<h3>id: {{this.$route.query.id}}'+'name: {{$route.query.name}}</h3>',
created(){
console.log(this.$route)
}
}
var router = new VueRouter({
routes:[
{path:'/user',component:user}
]
})
var vm = new Vue({
el:"#app",
router
})
</script>
params 方式传参
使用parpams 方式则不需要通过查询字符串传参,而是将参数放在路径中。
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router@2.5.3/dist/vue-router.js"></script>
<div id="app">
<router-link to="/user/02/yzxadmin">登录</router-link>
<router-view></router-view>
</div>
<script>
var user = {
template:'<h3>id: {{$route.params.id}}'+'name: {{$route.params.name}}</h3>',
created(){ //组件的生命周期的钩子函数
console.log(this.$route) //用this.$route 接收参数
}
}
var router = new VueRouter({
routes:[
{path:'/user/:id/:name',component:user}
]
})
var vm = new Vue({el:"#app",router})
</script>
注意:在路由开启 history 模式后,params 方式的 URL 地址会更加简洁(不会出现#),但是此功能需要搭配服务器使用,并且在服务器中添加 history 模式的支持,不然会出现找不到的错误。因为我是个穷鬼👼,买不起服务器,如下图我是有# 号的,只能就这样了。
嵌套路由
什么是嵌套路由
说的简单一点,嵌套路由就是在路由里面嵌套它的子路由。基本格式如下:
<router-link to="父路由的地址/要去的子路由地址"></router-link>
嵌套路由的案例
<head>
<meta charset="utf-8">
<title></title>
<!-- 1.引入vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router@2.5.3/dist/vue-router.js"></script>
<style>
ul,li,h1{
padding: 0;
margin: 0;
list-style: none;
}
#app{
with:100%;
display: flex;
flex-direction: row;
}
ul{
width: 200px;
flex-direction: column;
color: #fff;
}
li{
flex: 1;
background:#f00;
margin: 5px auto;
text-align: center;
line-height: 30px;
}
.about-detail{flex:1;margin-left: 30px;}
.about-detail h1{font-size: 24px;color: #90F62B;}
</style>
</head>
<body>
<div id="app">
<ul>
<router-link to="/about" tag="li">关于博主呀</router-link>
<router-link to="/contact" tag="li">联系方式</router-link>
</ul>
<router-view></router-view>
</div>
<template id="about-tmp">
<div class="about-detail">
<h1>余憨憨的个人简介</h1>
<router-link to="/about/detail">关于博主</router-link>
<router-link to="/about/habbies">个人爱好</router-link>
<router-view></router-view>
</div>
</template>
<template id="contact-tmp">
<div class="about-detail">
<h1>联系方式</h1>
<p>啦啦啦,你想啥呢~没有联系方式昂(ˉ▽ ̄~) 切~~</p>
</div>
</template>
<script>
//组件模板对象
var about = {template:'#about-tmp'}
var contact = {template:'#contact-tmp'}
//子路由的组件模板对象
var detail = {
template:'<p>我是小仙女我是小仙女我是小仙女,实在懒得打字了</p>'
}
var habbies = {
template:'<p>唱跳rap 啦啦啦编不下去了</p>'
}
var router = new VueRouter({
routes:[
{path:'/',redirect:'/about'}, //路由重定向
{
path:'/about',
component:about,
children:[
{path:'detail',component:detail},
{path:'habbies',component:habbies}
]
},
{path:'/contact',component:contact}
]
})
var vm = new Vue({
el:"#app",
router
})
</script>
</body>
[不过发本地视频,只能转gif,就是有点模糊~,不好意思啊]
命名路由
什么是命名路由
vue-router 提供了一个隐式的引用路径,即命名路由。只是因为有时候名字有时候太长了,所以命名让路由引用起来方便一点。
命名路由案例
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router@2.5.3/dist/vue-router.js"></script>
<div id="app">
<router-link :to="{name:'user',params:{id:01}}">登录</router-link>
<router-view></router-view>
</div>
<script>
//创建 user 组件
var user = {
template:'<h3>我是 user 组件</h3>',
created(){
console.log(this.$route)
}
}
//创建路由对象
var router = new VueRouter({
routes:[{
path:'/user/:id',
name:'user',
component:user
}]
})
var vm = new Vue({
el:"#app",
router
})
</script>
命名视图
什么是命名视图
就是可以在页面中定义多个单独命名的视图,我懒得解释了,解释了又看不懂,算了我写案例吧。😭😭😭
命名视图案例
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router@2.5.3/dist/vue-router.js"></script>
<style>
html,body{margin: 0;padding: 0;}
h1{margin: 0;padding: 0;font-size: 20px;color: #fff;}
.header{background-color: aqua;height: 80px;}
.container{display: flex;height: 600px;}
.sidebar{background-color: hotpink;flex: 2;}
.main{background-color: purple;flex: 8;}
</style>
</head>
<body>
<div id="app">
<router-view></router-view>
<div class="container">
<router-view name="left"></router-view>
<router-view name="main"></router-view>
</div>
</div>
<script>
var header = {template:'<h1 class="header">header 头部区域</h1>'}
var sidebar = {template:'<h1 class="sidebar">sidebar 侧导航区域</h1>'}
var mainBox = {template:'<h1 class="main">mainBox 主体区域</h1>'}
var router = new VueRouter({
routes:[{
path:'/',
components:{
'default':header,
'left':sidebar,
'main':mainBox
}
}]
})
var vm = new Vue({
el:"#app",
router
})
</script>
</body>
颜色方面实在没啥美感,不是说我色盲,真不知道什么颜色搭建一起好看哇。尽力了😭🤪😵
编程式导航
当进行页面切换时,都是通过< router-link> 来实现,这种方式声明导航。为了更方便地在项目中开发导航功能,Vue提供了编程式导航,也就是利用JavaScript 代码来实现地址的跳转,通过 router 实例方法来实现。
router.push()
使用router.push()方法可以导航不同的 URL 地址。
router.push() 方法的参数可以是一个字符串路径,或者一个描述路径的对象。代码如下:
var router =new Vouter() //先获取 router 实例
router.push('user') //字符串形式
router.push({path:'/login?url='+this.$route.path}) //对象形式
router.push({name:'user',params:{userId:123}}) //命名路由
router.push({path:'user',query:{id:'12'}}) //带查询参数 /user?id=12
在参数对象中,如果提供了path,params 会被忽略,为了传参数,需要提供路由的name 或者手写带有参数的path,代码如下:
const userId = '123'
router.push({name:'user',params:{userId}})
router.push({path:'/user/${userId}'})
//这里的params不生效
router.push({path:'/user',params:{userId}})
query 传参
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router@2.5.3/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<button @click="goStart">跳转</button>
<router-view></router-view>
</div>
<script>
var user = {
template:'<p>用户名:{{this.$route.query.name}}</p>'
}
var router = new VueRouter({
routes:[
{path:'/user',component:user}
]
})
var vm = new Vue({
el:"#app",
methods:{
goStart(){
this.$router.push({path:'/user',query:{name:'yzxadmin'}})
}
},
router
})
</script>
</body>
params 传参
效果和query一样不放效果图,下面是我圈出来需要修改的地方,大家自行尝试哈~
router.replace()
router.replace() 和 router.push()方法累死。区别在于:为<router-link>
设置replace属性后,当单机时,就会调用router.replace(),导航后不会向 history 栈添加新的记录,而是替换当前的 history记录,代码如下:
//编程式
router.replace({path:'user'})
//声明式
<router-link :to="{path:'user'}" replace> </router-link>
router.go()
router.go()方法的参数是一个整数,表示在 history 历史记录中前进或后退多少步。类似于window.history.go() 。 this.$ router.go(-1)相当于history.back(),表示后退一步。this.$router.go(1)相当于history.forward(),表示前进一步。这里的功能就相当于前进和后退功能,浏览器地址栏会变的。
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router@2.5.3/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<button @click="goStart">跳转</button>
<button @click="goOn">前进</button>
<button @click="goBack">后退</button>
<router-view></router-view>
</div>
<script>
var user = {
template:'<p>用户名:{{this.$route.query.name}}</p>'
}
var router = new VueRouter({
routes:[
{path:'/user',component:user}
]
})
var vm = new Vue({
el:"#app",
methods:{
goStart(){
this.$router.push({path:'/user',query:{name:'yzxadmin'}})
},
goOn(){
this.$router.go(1) //前进操作
},
goBack(){
this.$router.go(-1) //后退操作
},
},
router
})
</script>
</body>
未经允许,禁止转载。文章写的有点长,希望大家给我点个赞哦~😘😘😘