如何使用路由
要使用路由功能,需要先安装路由模块
npm i vue-router
然后在src目录下,创建一个router文件夹,然后在该文件夹下创建index.js编写以下代码 :
import Vue from 'vue'
import Router from 'vue-router'
import Index from '@/views/index'
import Login from '@/views/login'
Vue.use(Router)
let router = new Router({
routes : [{
path : '/index',
component : Index
},{
path : '/login',
component : Login
},]
})
export default router;
其中Index组件和Login组件的代码如下 :
<template>
<div class='index'>
index
</div>
</template>
<template>
<div class='index'>
login
</div>
</template>
然后把App.vue代码改成这样 :
<template>
<div id="app">
<router-view/> <!--主要在这里加了一个router-view-->
</div>
</template>
<script>
export default {
name: 'App',
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>
router-view是用来显示我们上面的index和login组件的容器
然后打开main.js,增加以下代码 :
import Vue from 'vue'
import App from './App'
import router from './router' //这里!!!
Vue.config.productionTip = false
new Vue({
el: '#app',
router, //这里!!!
components: { App },
template: '<App/>'
})
完成以上工作后,路由就已经生效了。打开浏览器输入“http://localhost:8080/#/index” 或者 http://localhost:8080/#/login
路由跳转
现在我们想从login跳到index,打开login.vue,增加以下代码 :
<template>
<div class='login'>
<router-link to="/index">go to index</router-link>
</div>
</template>
router-link类似于html的a标签,to类似a标签的href。to后面带的是路由的path。
除了使用router-link来跳转外,vue还提供了下面3种方式来跳转路由,分别是 :
this.$router.push
跳转到指定url路径,并想history栈中添加一个记录,点击后退会返回到上一个页面
this.$router.replace
跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面)
this.$router.go(n)
向前或者向后跳转n个页面,n可为正整数或负整数
this.$router.push例子
<template>
<div class='login'>
<p @click="gotoIndex">go to index</p>
</div>
</template>
<script>
export default {
methods : {
gotoIndex(){
this.$router.push({
path : '/index'
});
}
}
}
</script>
运行效果 :
注意看左上角,我们是可以返回上一页的。
this.$router.replace例子
<template>
<div class='login'>
<p @click="gotoIndex">go to index</p>
</div>
</template>
<script>
export default {
methods : {
gotoIndex(){
this.$router.replace({
path : '/index'
});
}
}
}
</script>
运行效果 :
???
注意看左上角,我们不可以返回上一页
this.$router.go例子
<template>
<div class='login'>
<p @click="gotoIndex">go to index</p>
</div>
</template>
<script>
export default {
methods : {
gotoIndex(){
this.$router.push({
path : '/index'
});
setTimeout(()=>{
this.$router.go(-1);
},2000);
}
}
}
</script>
运行效果 :
该函数的作用就是类似于我们手动的点击浏览器上的前进或者返回。(负数返回,正数前进)
跳转路由的时候传参
传参
<template>
<div class='login'>
<p @click="gotoIndex">go to index</p>
</div>
</template>
<script>
export default {
methods : {
gotoIndex(){
this.$router.push({
path : '/index',
query : {
name : 'tom',
age : 18
}
});
}
}
}
</script>
获取传过来的参数
<template>
<div class='index'>
index
</div>
</template>
<script>
export default {
mounted(){
alert( `name=${this.$route.query.name},age=${this.$route.query.age}` );
}
}
</script>
需要注意的是,这是是 this.$route,不是this.$router。没有r
路由懒加载
实际上我们这里这样写,即使我们一开始没有访问Index路由,但是Index组件还是被解析了。若一个项目中有很多组件,则一开始的加载速度则会大大减低。正常情况下是,我们访问到这个路由,才去加载这个路由对应的组件。
解决方案 :
import Vue from 'vue'
import Router from 'vue-router'
const Index = ()=>import("@/views/index"); //懒加载
const Login = ()=>import("@/views/login"); //懒加载
Vue.use(Router)
let router = new Router({
routes : [{
path : '/index',
component : Index
},{
path : '/login',
component : Login
},]
})
export default router;
scrollBehavior
当从B页面跳到A页面,如果此时B页面已经被用户滑动到底部,然后点击某个按钮跳到A页面,此时的A页面也是在底部。
如下图 :
解决方案 :
mode
router有两种模式:hash模式(默认)、history模式(需配置mode: 'history')
在浏览器上输入http://localhost:8080/访问该项目,地址栏上的地址突然变成http://localhost:8080/#/login,很丑。如果要改成http://localhost:8080/login这种模式,则只需要在
即可。此时在访问项目,是没问题的。但是如果把项目打包出来然后放到服务器上运行,你会发现运行项目时,一片空白。这是因为服务器匹配不到路由是什么玩意(因为此时的静态文件只有一个index.html,并没有什么/login、/index)
解决的方法是修改服务器的代码,这里以node.js为例 :
const http = require('http');
const fs = require('fs');
const path = require('path');
const url = require('url');
const httpPort = 3000; //端口号
const staticPath = './www'; //项目的存储目录
//获取文件类型,用以写入文件头
function getFileMime(suffix) {
return new Promise((resolve, reject)=>{
fs.readFile('./data/mime.json', (err, data)=>{
if(err){
reject(err);
}else{
resolve( JSON.parse(data.toString())[suffix] );
}
});
});
}
http.createServer((req, res) => {
let urlPath = url.parse(req.url).pathname;
//路径中包含/static/css、/static/js、/static/img的,则是资源文件
if (urlPath.startsWith('/static/css') || urlPath.startsWith('/static/js') || urlPath.startsWith('/static/img')) {
fs.readFile(staticPath + urlPath, async(err, data) => {
if (err) {
console.log(err);
}
let type = await getFileMime(path.extname(urlPath));
res.writeHead(200, {'Content-Type': type + ';charset="utf-8"'});
res.end(data);
})
}
//否则是其它路径,则全部读取index.html
else {
fs.readFile(staticPath + '/index.html', 'utf-8', (err, content) => {
if (err) {
res.end(404);
console.log(err);
}
res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
res.end(content)
})
}
}).listen(httpPort, () => {
console.log('Server listening on: http://localhost:%s', httpPort);
})
/static/css、/static/js、/static/img这里指的是vue打包后的文件夹名字。我的是这样的 :
运行效果 :
这个例子的下载地址 :https://download.csdn.net/download/QQ408896436/12659140
该方法有bug,如果路由是动态路由,则会报错。本以为是我代码上有问题,所以我用express + connect-history-api-fallback 的方法来测试,也是一样,会报错。知道的大大麻烦告知一下,3Q
动态路由
比如有一个路由,他的路径是这样的 :http://localhost:8080/news/4bcvb,后面的4bcvb可以是任意的数字。
import Vue from 'vue'
import Router from 'vue-router'
const Index = ()=>import("@/views/index"); //懒加载
const Login = ()=>import("@/views/login"); //懒加载
const New = ()=>import("@/views/news"); //懒加载
Vue.use(Router)
let router = new Router({
mode : 'history',
scrollBehavior: () => ({ y: 0 }),
routes : [{
path : '/index',
component : Index
},{
path : '/login',
component : Login
},{
path : '/news/:id', //这里!!!
component : New
},]
})
export default router;
如果要获取这个参数,则 :
this.$route.params.id
这里的id必须和path : '/news/:id'这里的id是同一个名称, 跳转的时候这样写 :
this.$router.push({
path : /news/' + id,
})
路由重定向
现在我们在浏览器上输入http://localhost:8080/,则页面是空白的。因为我们设置路由的path只有3个,分别是 :
解决方案 :设置一个默认的path,当上面的路由都匹配不到的时候,默认显示这页
import Vue from 'vue'
import Router from 'vue-router'
const Index = ()=>import("@/views/index"); //懒加载
const Login = ()=>import("@/views/login"); //懒加载
const New = ()=>import("@/views/news"); //懒加载
Vue.use(Router)
let router = new Router({
mode : 'history',
scrollBehavior: () => ({ y: 0 }),
routes : [{
path : '/index',
component : Index
},{
path : '/login',
component : Login
},{
path : '/news/:id',
component : New
},{
path: '*', //这里!!!
redirect: '/login' //这里!!!
}]
})
export default router;
子路由
比如有一个"个人中心"的页面,个人中心的页面中有2个子页面 :"我的收藏"、"我的足迹"。这时候就可以使用子路由
import Vue from 'vue'
import Router from 'vue-router'
const Index = ()=>import("@/views/index");
const Login = ()=>import("@/views/login");
const New = ()=>import("@/views/news");
const My = ()=>import("@/views/my/"); //父组件
const Collection = ()=>import("@/views/my/component/collection"); //子组件
const History = ()=>import("@/views/my/component/history"); //子组件
Vue.use(Router)
let router = new Router({
mode : 'history',
scrollBehavior: () => ({ y: 0 }),
routes : [{
path : '/index',
name : 'index',
component : Index
},{
path : '/login',
name : 'login',
component : Login
},{
path : '/news/:id',
name : 'news',
component : New
},{
path : '/my', //这里!!!
name : 'my',
component : My,
children : [{
path : 'collection',
name : 'collection',
component : Collection
},{
path : 'history',
name : 'history',
component : History
}]
},{
path: '*',
redirect: '/login'
}]
})
export default router;
然后在my的路由下,使用children属性来定义子路由。然后在my组件下定义一个 <router-view/>;来显示子路由的内容。如下 :
<template>
<div class='my'>
<div class='nav'>
<ul>
<li @click="$router.push({name : 'collection'})">collection</li>
<li @click="$router.push({name : 'history'})">history</li>
</ul>
</div>
<router-view/> <!--这里-->
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.nav{
overflow: hidden;
}
li{
float: left;
list-style-type: none;
width: 50%;
}
</style>
运行效果 :
通过name来跳转路由
如果一个path的路径太长,比如上面说的嵌套路由。跳转的时候需要写一大串的路径不太方便。这时候可以通过name来跳转路由。
给每个路由添加一个name属性,跳转路由的时候:
this.$router.push({
name : 'index', //这里
query : {
name : 'tom',
age : 18
}
});
全局守卫和局部守卫