#在@vue/cli创建的项目中,路由用法如下。
1、安装路由
npm install vue-router@3
2:定义路由所需的组件(.vue文件)
要实现页面about 和home两个路由,我们先定义两个组件
定义页面级组件,创建views文件夹,然后创建Home.vue和About.vue
3.在src目录下创建router文件夹,并在其内创建index.js作为vue路由功能模块js文件
# src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
//引入定义好的路由所需组件
import Home from '../views/Home.vue'
#配置路由代码:
const router = new VueRouter({routes:[{
path:'/',//根目录 加载Home这个组件
//组件引入两种方法 1.直接引入 2.路由懒加载
//直接引入 component 路由所映射的组件
component:Home
},
{
path:'/about',
//路由懒加载
component: () => import('./../views/About.vue')
}
]
})
默认输出路由对象
export default router;
4.创建 router 实例,然后传 `routes` 配置 src/main.js
//在main.js中,实例化vue对象时,注册路由
# src/main.js
#通过注入路由器,我们可以在任何组件内通过 this.$router 访问路由,也可以通过 this.$route 访问当前路由
# 1. import router from './router/index.js'
new Vue({
# 2. router,//注册路由
render: h => h(App)
}).$mount('#app')
5.在页面定义导航和路由出口
#App.vue
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<!-- 定义页面导航-->
<!-- <router-link to="/"> 路由的入口 点击将会跳转的位置
根据配置好的path进行调整到执行的组件 -->
<ul>
<li>
<router-link to="/">home</router-link>
</li>
<li>
<router-link to="/about">about</router-link>
</li>
</ul>
<!-- 定义路由的出口 -->
<router-view></router-view>
</div>
</template>
路由选中默认值
选中的路由,会增加一个类名 router-link-active
全局修改路由选中时出现的类名:
#router/index.js
const router = new VueRouter({
routes:[
{
path:'/',
component:Home
},
{
path:'/about',
component: () => import('../views/About.vue')
}
],
//设置路由选中的类名为act
linkActiveClass:'act'
使用上述 linkActiveClass:‘act’,有一个问题,
当默认选中的时候,会修改类名为act ,第二个被选中的时候,也会有一个act类名,同时都有act名(act我们自定义的类名) 两种解决方法
第一种:此时,需要使用exact精准匹配(如果有二级路由这种方法不行)
在路由入口标签 添加exact属性
#App.vue
<template>
<div id="app">
<span>
# <!-- exact 精准匹配 -->
<router-link to="/" exact>Home</router-link>
</span>
<span>
<router-link to="/about" exact>About</router-link>
</span>
<img alt="Vue logo" src="./assets/logo.png" />
<!-- 出口 -->
<router-view></router-view>
</div>
</template>
第二种:
将路由的路径写完整:
#router/index.js
const router = new VueRouter({
routes:[
{
//path:'/',
path:'/home',
component:Home
},
{
path:'/about',
component: () => import('../views/About.vue')
}
],
//设置路由选中的类名为act
linkActiveClass:'act'
#App.vue
Home
About
通过路由切换,我们可以控制组件显示与否,路由组件切换的时候,默认隐藏的组件是被销毁的,注意,这里说的是默认
每一次切换,展示出来的组件,都完成了一次新的挂载
离开的组件不要被销毁:
使用
标签包裹路由出口
只想让某个组件不被销毁:
在需要进行状态保持的路由配置项中,添加自定义meta属性:
router/index.js:
{
path: '/home',
name: 'home',
component: () => import("@/views/Home.vue"),
meta: {
keepAlive: true
}
},
App.vue:
keepAlive对应的组件,只有第一次进入的时候,会走一系列的生命周期函数,再次切换回来的时候,再也不会执行mouted等声明周期函数
被keep-alive包裹的路由出口对应的路由组件,会有两个新的生命周期函数:activated(),deactivated()
actived: 当前组件被激活的时候(我们现在说的组件,都是keep-alive包裹的路由出口对应的组件),即进入当前组件的时候
deactivated: 当前组件离开的时候,即切换走当前组件的时候执行的钩子函数
#二级路由配置 router/index.js
routes:[
{
path:'/home',
children:[
// 二级路由,path分配,前面不要有 /
//redirect 重定向
{path:'/',redirect:'/home/tv'},
{path:'tv',component:()=>import('./../components/tv.vue')},
{path:'music',component:()=>import('./../components/music.vue')}
]
}
]
#在一级路由组件模版中定义二级路由导航和路由出口
<!-- 在一级路由组件模版中,定义二级路由导航 -->
<router-link to='/home/tv'>tv</router-link>
<router-link to='/home/music'>music</router-link>
<!-- 在一级路由组件模版中,定义二级路由出口-->
<router-view></router-view>
router/index.js
//路由传参
{
path: '/news/newsdetali/:newid',
component: () => import('@/components/newDetail.vue')
}
在news.vue中添加路由入口,匹配路由传参
1,第一种
views/news.vue
新闻详情
2,第二种是传递当前组件data里边的值 通过模板字符串
views/news.vue
<template>
<div>
<router-link :to="`/news/newsdetali/${num}`">新闻详情</router-link><br />
</div>
<router-view />
</div>
</template>
<script>
export default {
props: {},
data() {
return {
num: 2,
};
},
methods: {},
components: {},
};
</script>
<style scoped lang="less">
.main {
width: 100%;
margin: 30px auto;
display: flex;
justify-content: space-between;
}
</style>
components/newDetails.vue
<!-- 根据路由传参的参数名取值-->
{{ this.$route.params.newid }}
// 通过钩子函数获取参数
created() {
console.log(this.$route.params.newid);
},
router/index.js
//路由传参
{
path: '/news/newsdetali/:newid/:uid',
name: 'Detail',
component: () => import('@/components/newDetail.vue')
}
在news.vue中添加路由入口,匹配路由传参
1,params传参
views/news.vue
// 命名路由传参
<router-link :to="{ name: 'Detail', params: { newid: '101', uisd: '202' } }">
</router-link><br />
components/newDetails.vue
新闻id:{{ this.$route.params.newid }}
{{ this.$route.params.newid }}
{{ this.$route.params.uisd }}
// 通过钩子函数获取参数
created() {
console.log(this.$route.params.newid);
console.log(this.$route.params.uisd);
},
2,query传参
views/news.vue
//对象传参
//
// 命名路由传参
<router-link :to="{ name: "Detail", query: { newid: '101',uisd: '202' } }">
命名路由传参
</router-link><br />
components/newDetails.vue
<!-- 根据路由传参的参数名取值-->
新闻id:{{ this.$route.params.newid }}
<br />
{{ this.$route.query.newid }}
{{ this.$route.query.uisd }}
// 通过钩子函数获取参数
created() {
console.log(this.$route.query.newid);
console.log(this.$route.query.uisd);
},
router/index.js
{
path: '/news/newsdetali',
name: 'Detail',
component: () => import('@/components/newDetail.vue')
},
在news.vue中添加路由入口,匹配路由传参
views/news.vue
<button @click="goDetail()">点击跳转详情页路由</button>
methods: {
goDetail() {
//点击跳转到对应路由(不传参三种种写法)
//第一种
// this.$router.push("/news/newsdetali").catch((err)=>'');
//第二种
// this.$router.push({
// path: "/news/newsdetali",
//});
//第三种
this.$router.push({
name: "Detail",
});
},
},
router/index.js
//路由传参
{
path: '/news/newsdetali/:newid/:uid',
name: 'Detail',
component: () => import('@/components/newDetail.vue')
}
在news.vue中添加路由入口,匹配路由传参
views/news.vue
<button @click="goDetail()">点击跳转详情页</button>
methods: {
goDetail() {
this.$router.push({
path: "/news/newsdetali",
// 这里不可以使用params
query: {
//和路径接受的名字保持一致
newid: "301",
},
});
},
},
components/newDetails.vue
<!-- 根据路由传参的参数名取值-->
{{ this.$route.query }}
// 通过钩子函数获取参数
created() {
console.log(this.$route.query.newid);
console.log(this.$route.query.uid);
},
router/index.js
//路由传参
{
path: '/news/newsdetali/:newid/:uid',
name: 'Detail',
component: () => import('@/components/newDetail.vue')
}
在news.vue中添加路由入口,匹配路由传参
views/news.vue
methods: {
goDetail() {
this.$router.push({
name: "Detail",
params: {
//和路径接受的名字保持一致
newid: "301",
uid: "98",
},
});
},
},
components/newDetails.vue
{{ this.$route.params }}
// 通过钩子函数获取参数
created() {
console.log(this.$route.params.newid);
console.log(this.$route.params.uid);
},
router/index.js
//路由传参
{
path: '/news/newsdetali/:newid/:uid',
name: 'Detail',
component: () => import('@/components/newDetail.vue')
}
在news.vue中添加路由入口,匹配路由传参
views/news.vue
<button @click="goDetail()">点击跳转详情页</button>
methods: {
goDetail() {
this.$router.push({
name: "Detail",
params: {
//和路径接受的名字保持一致
newid: "301",
uid: "98",
},
});
},
},
components/newDetails.vue
<!-- 根据路由传参的参数名取值-->
{{ this.$route.query }}
// 通过钩子函数获取参数
created() {
console.log(this.$route.query.newid);
console.log(this.$route.query.uid);
},
用法和push一样
和push区别:
replace 跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 历史记录比较短只有一步后退的时候 直接退到起点
push -步-步记录历史记录每一-次回退都是回退到.上一次操作
使用编程式路的时,如果跳转路径通过path配置的是,参数是通过query传递的
接受参数 this.$route.query
如果跳转路径是通过name(命名式路由)配置的,参数可以通过query也可以通过params
接受参数 this. r o u t e . q u e r y t h i s . route.query this. route.querythis.route.params
query 传递的参数 和get 一样 会拼接在url路径后面
params 的参数 不会拼接在路径后面
这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)
。
// 在浏览器记录中前进一步,等同于 history.forward()
this.$router.go(1)
// 后退一步记录,等同于 history.back()
this.$router.go(-1)
// 前进 3 步记录
this.$router.go(3)
// 如果 history 记录不够用,那就默默地失败呗 就没反应
this.$router.go(-100)
this.$router.go(100)
eg:
<button @click="goback">返回上页</button>
methods:{
goback(){
this.$router.go(-1)
}
}
const router = new VueRouter({
// mode: 'hash',
mode: 'history',
}
**1.**hash路由在地址栏URL上有#,而history路由没有会好看一点
**2.**我们进行回车刷新操作,hash路由会加载到地址栏对应的页面,而history路由一般就404报错了(刷新是网络请求,没有后端准备时会报错)
**3.**hash路由支持低版本的浏览器,而history路由是HTML5新增的API。
**4.**hash的特点在于它虽然出现在了URL中,但是不包括在http请求中,所以对于后端是没有一点影响的,所以改变hash不会重新加载页面,所以这也是单页面应用的必备。
**5.**history运用了浏览器的历史记录栈,之前有back,forward,go方法,之后在HTML5中新增了pushState()和replaceState()方法(需要特定浏览器的支持),它们提供了对历史记录进行修改的功能,不过在进行修改时,虽然改变了当前的URL,但是浏览器不会马上向后端发送请求。
回答这些就行:
1、样式
hash路由在地址栏URL上有#,而history路由没有会好看一点
2、兼容性
hash路由支持低版本的浏览器,而history路由是HTML5新增的API。
3、请求的时候 hash 刷新 history 报错 路由 传递数据 #/不会发送给服务器
我们进行回车刷新操作,hash路由会加载到地址栏对应的页面,而history路由一般就404报错了(刷新是网络请求,没有后端准备时会报错)
hash的特点在于它虽然出现在了URL中,但是不包括在http请求中,所以对于后端是没有一点影响的,所以改变hash不会重新加载页面,所以这也是单页面应用的必备。
#router/index.js
// 创建VueRouter实例对象
const router = new VueRouter({
/* routes:[]定义路由配置,routes里面的每一个选项是一个对象,包含每个路由的具体配置
routes之所以是数组,因为里面包含多条路由 */
routes:
{
path: '/',
redirect: '/home'
},
{
path: '/home',
component: () => import("@/views/Home.vue"),
meta: {
titleName: '首页'
}
},
{
path: "/buy",
component: () => import("@/components/buy.vue"),
meta: {
titleName: '购买',
xiaoli: true
},
// 路由独享守卫
// beforeEnter: (to, from, next) => {
// if (window.localStorage.getItem('islogin') == "true") {
// next()
// } else {
// alert("请先登录")
// next("/login")
// }
// }
},
{
path: "/buy/:newid",
component: () => import("@/components/buy.vue"),
meta: {
titleName: '购买',
xiaoli: true
},
},
{
path: "/login",
component: () => import("@/components/login.vue"),
meta: {
titleName: '登录'
}
}
});
// 添加全局路由前置守卫
router.beforeEach((to, from, next) => {
// 判断要跳转的路径是否是/buy 同时判断登陆状态是否是未登陆 所以取反
// false if( true)
if(to.fullPath == '/buy' && !localStorage.getItem('islogin')){
next('/login');
}
next();
})
router.afterEach((to, from,) => {
// 让网页标题变化
document.title = to.meta.titleName
})
// 把当前的路由实例 暴露出去 方便其他模块调用
export default router;
#components/buy.vue
<template>
<div>
<h1>购买页</h1>
接收传递的参数:{{ this.$route.query.newid }}{{ this.$route.params.newid }}
<router-link to="/buy/002">点击购买传参2</router-link>
</div>
</template>
<script>
export default {
props: {},
data() {
return {};
},
methods: {},
components: {},
// 组件内守卫
// beforeRouteEnter(to, from, next) {
// if (window.localStorage.getItem("islogin") == "true") {
// next();
// } else {
// alert("请先登录");
// next("/login");
// }
// },
beforeRouteLeave(to, from, next) {
// alert("你要离开了吗");
// next("/home");
console.log(0);
next();
},
beforeRouteUpdate(to, from, next) {
console.log("路由传递的参数变化了");
next();
},
};
</script>
<style scoped lang="less">
</style>
路由守卫:
就是对路由进行一些保护,比如权限的验证
在路由的跳转前、后 进行校验
分为: 全局路由守卫 路由独享守卫 组件内的路由守卫
全局分为两种: 前置 后置
前置: beforeEach(to,from,next)
后置: affterEach(to,from)
路由独享守卫,写在当前路由的配置项下面,beforeEnter(to,from,next)
组件内路由守卫: beforeRouteEnter(to,from,next) 通过路由进入当前组件后
beforeRouteUpdate(to,from,next) 通过路由传值的时候触发 to 拿 params query 参数
beforeRouteLeave(to,from,next) 通过路由离开当前组件后
1、使用npm run build
命令运行
得到一个dist文件夹,里面后html、js、css文件
直接打打开html,发现打不开
需要部署在服务器上
2、创建自己的服务器
2.1、创建一个文件夹,通过vscode打开
2.2、在终端中,输入npm init -y
2.3 、安装express npm install express
2.4、在文件夹下面新建一个server.js
//server.js
const express = require('express');
const app = express();
app.get('/news', (req, res) => {
res.send({
name: '新闻三十分',
author: '陈福国'
})
})
app.listen(5005, (err) => {
if (!err) {
console.log('服务器启动成功,localhost:5005');
}
})
2.5、启动server.js node server.js
2.6、页面输入路径测试
2.7、服务器搭建成功后,新建一个static文件,把build后的静态资源全部放入当前文件夹,搞定
const express = require('express');
const app = express();
//配置静态资源路径
app.use(express.static(__dirname + '/static'))
app.get('/news', (req, res) => {
res.send({
name: '新闻三十分',
author: '陈福国'
})
})
app.listen(5005, (err) => {
if (!err) {
console.log('服务器启动成功,localhost:5005');
}
})
2.8 确保启动服务器后,输入路径http://localhost:5003 即可