本例是通过2.x版本的vue来介绍:
通过 vue init webpack demo,然后 npm install axios 安装axios, 创建一个基于webpack的一个名为demo的项目,目录结构如下:
首先,我们找到入口文件
main.js
,一般的话,比如我们要请求接口使用各种ui框架,我们都会在main的js引入,这里我们引入axios来举例.
import Vue from 'vue'
import App from './App'
import router from './router'
import axios from 'axios'
Vue.config.productionTip = false
Vue.prototype.$axios = axios; // 有没有觉得这个方法这样写似曾相识
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: ' '
})
比如:我想引入一个axios当做请求的一个工具,我在main.js全局引入,通过 a x i o s 这 样 引 入 , 这 样 可 以 再 其 他 页 面 通 过 t h i s . axios这样引入 ,这样可以再其他页面通过 this. axios这样引入,这样可以再其他页面通过this.axios 调用此方法,紧接着,我们又会想到,既然请求有了,那么我们怎么样做到给请求做一下拦截呢?
import Vue from 'vue'
import App from './App'
import router from './router'
import axios from 'axios'
Vue.config.productionTip = false
Vue.prototype.$axios = axios; // 有没有觉得这个方法这样写似曾相识
//以登录为例
function getToken(){
let token = sessionStorage.getItem('token') || '';
return token;
}
//设置请求拦截
axios.interceptors.request.use(
config => {
if(getToken){
config.headers["token"] = getToken();
}
return config;
},
error => {
return Promise.reject(error);
}
)
//设置响应拦截
axios.interceptors.response.use(
response => {
let res = response.data;
if(res.code == 401){
location.href = '/' //这里可以做一些简单的处理,根据业务需求来决定
}
return Promise.resolve(res)
},
error => {
return Promise.reject(error);
}
)
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: ' '
})
像这样我们就做了一个基础的axios请求拦截和响应的功能,看起来是这么回事,但是有没有想过,把这些东西都放在main.js里面代码是不是觉得很臃肿? 后面我们再一起讲解该怎么去改,优化一下.
接下来看看基础的路由配置写法:
import Vue from 'vue'
import Router from 'vue-router'
import Login from '@/components/Login'
import List from '@/components/List'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'Login',
component: Login
},
{
path: '/list',
name: 'list',
component: List
}
]
})
平时,我们在做项目,比如做商城啊,管理后台啊这类型的项目都有一个登录,列表页等东西, 所以我们会给每一个页面指定一个路由,就会在router里面头部引入各个页面,并对各个页面的路由配置路由地址,然后将该Router暴露出去,并且在main.js中引入使用,
假设我们有20个或30个路由呢,那岂不是要引入20,30次?这样会不会太过于频繁,代码不美观,有没有办法可以简化这样的引入方式呢?
看了上面Vue的基础路由及axios的基础写法,代码臃肿,写的东西比较繁多,有没有更好的写法,让代码看起来更加简洁明了呢?
接下来,我们一起看看vue的进阶用法吧! 下面我们以post请求为例
//首先,我们在src目录下创建request文件夹,里面创建一个axios.js文件
import axios from 'axios';
//获取token
function getToken(){
let token = sessionStorage.getItem('token') || '';
return token;
}
//创建一个axios的实例
const service = axios.create({
baseURL: '/apply', //代理 api的url
timeout: 5000 //请求超时的时间
})
//request请求拦截器
service.interceptors.request.use(
config => {
if(getToken()){
config.headers["token"] = getToken();
}
return config;
},
error => {
return Promise.reject(error)
}
)
//response响应拦截器
service.interceptors.response.use(
response => {
let res = response.data;
if(res.code == 401){
// location.href = '/' 这里可以做一下操作,也可以扩展一些需求,根据项目实际情况来定
}
return Promise.resolve(res)
},
error => {
return Promise.reject(error);
}
)
export default service;
import service from './axios';
export default function requestOfPost(url, data) {
return service.post(url, data)
}
引入刚刚写好的axios文件暴露出来的方法,封装在一个函数里面,待使用的时候进行调用.
import requestOfPost from '../request/common';
export function postRequest(url,data){
return new Promise((resolve,reject)=>{
requestOfPost(url,data).then(res=>resolve(res)
,error => reject(error))
})
}
//目的是为了获得除了data数据意外的比如 headers config等
创建一个request目录下面的apiUrl.js文件
const url = {
loginUrl: '/login',
getMenuList: '/getMenuList'
}
export default url;
为什么要这样定义接口呢? 为了安全性,避免直接将接口写在文件里面,webpack打包将接口暴露在打包文件里面.
为什么要引入刚刚写好的service文件呢,因为,我们在平时开发中,不仅仅需要用到data里面的数据,还可能需要获得头部信息等其它信息,这时候就要封装一层Promise,将请求成功或失败的结果抛出,以便调用时可以拿到数据.
我们在调用的时候可以这样写
import url from "../request/apiUrl";
import { postRequest } from "../common/api";
postRequest(url.loginUrl,params).then(res=>console.log(res))
这样通过.then() 方法就可以拿到你想要的数据或者请求头等信息.
在这里提供多一种ES7的请求方式
async loginBtn() {
//当请求发送错误不会执行下面的代码
let loginData = await postRequest(url.loginUrl, params);
console.log(loginData) //这里可以直接拿到结果,不需要.then(res=>console.log(res))
},
这里要注意 async和await要一起使用,还有一点需要注意的是,如果这个请求失败了 下面的代码是不会执行了,可以适当利用try{}catch(error){}解决这一问题.
接下来我们回想一下上面写的router文件
代码臃肿,如果一个项目有很多个文件,那么必须引入很多次,这时候我们可以想想,有没有什么办法可以让这些页面不用一个一个手写引入呢?
这时候我们可以把router文件改成如下:
提取login路由文件
// src下面的router下面的login.routes.js
export default {
path: '/',
name: 'Login',
component: () => import('@/components/Login.vue'), //路由懒加载
children: [
]
}
提取list路由文件
// src下面的router下面的list.routes.js
export default {
path: '/list',
name: 'List',
component: () => import('@/components/List.vue'), //路由懒加载
children: [
]
}
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
/*
require.context函数接受三个参数
directory {String} -读取文件的路径
useSubdirectories {Boolean} -是否遍历文件的子目录
regExp {RegExp} -匹配文件的正则
require.context('./',true,/\.routes\.js/) 返回一个函数
*/
const routerList = [];
function importAll(r) {
console.log(r,'我是r') //返回一个函数
console.log(r.keys(),'我是r.keys()')//返回匹配成功模块的名字组成的数组
r.keys().forEach((key) => {
console.log(r(key),'我是r(key)') //返回 {default: {路由,组件等信息}}
routerList.push(r(key).default)
})
}
importAll(require.context('./',true,/\.routes\.js/));
const routes = [
...routerList
];
export default new Router({
mode: 'history',
routes
})
由上面代码,我们可以可知,写了一个require.context方法,用来匹配与之相关的文件,通过
r.keys()
,拿到匹配成功模块的路径组成的一个数组形式,紧接着变量这个数组,通过r(key)
将这个数组传进去,得到{default: {path: '/',component:xxx}}
这样的参数,所以我们取出对象里面的default,将这个对象添加到定义的空数组里面,将这个数据扩展到routes里面,这样就可以动态的获得与之匹配的文件.
但是,要注意的是,我们每一个模块对应的路由要分别写在router下面,并且名称后缀都为.routes.js结尾
如果我们在登录后还想对某些页面进行,是否登录后才可以跳转操作等其它功能,我们可以进行如下修改:
//router/list.routes.js
export default {
path: '/list',
name: 'List',
component: () => import('@/components/List.vue'), //路由懒加载
children: [
],
meta:{
//自定义字段
mustLogin: true
}
}
//main.js文件可以对拦截器做一些处理
router.beforeEach((to, from, next) => {
let token = sessionStorage.getItem('token');
if (to.meta.mustLogin) {
if (token) {
next();
console.log('需要登录,有token')
} else {
next({
path: '/'
});
console.log('需要登录,无token')
}
}else{
next();
console.log('无需要登录,无token')
}
})
通过在路由里面定义一个meta属性,在路由前置守卫判断,如果该 mustLogin为true说明这个页面必须登录后才可以登录,如果未登录则跳到登录页.如果在请求拦截有其他公共的操作,可以再axios.js文件下面修改 以公司返回的状态码为准,去修改即可…
今天给大家分享的就是 vue的路由(Router)使用基础及进阶和vue的请求(axios)使用基础和进阶,总的来说,其实难点不多,就是一个require.context函数的理解和使用没怎么接触过,其他都是大家平时项目中用到的东西,
写的如果有什么不足之处,恳请大家指出来,大家一起交流交流!!!