webpack和axios 总结!

472 阅读3分钟

webpack 4

一,webpack 4 在这些版本中 它的速度更快了,大型的项目节约了90%的构建的时间,

同时它内置了更多默许配置,变更了许多API

webpack 是一个模块打包工具

webpack是基于Node.js 开发的一个模块项目打包工具,

想要下载webpack需要安装node.js环境

二,webpack安装命令

  1. cnpm install webpack --save
  2. cnpm install webpack-cli --save-dev
  3. 卸载命令:cnpm uninstall webpack webpack-cli -g
  4. 检查局部安装webpack命令:npx webpack -v
  5. 查看webpack都有什么版本:cnpm info webpack
  6. 安装指定webpack版本:cnpm install webpack@版本号 webpack-cli -D
  7. 按照css打包配置loader加载器 : cnpm install style-loader css-loader --save-dev
  8. 安装js 打包配置expose-loader: cnpm install jquery --save-dev
  9. cnpm install expose-loader --save-dev
  10. 打包命令: cnpm run build

html webpackPlugin 会在打包结束后,自动生成一个html文件,并把打包生成的js自动引入到这个html文件中。

Loader是什么?

  1. 配置loader

  a、安装js处理包:babel-loader babel-ccore babel-preset-env并配置

    babel-preset-env 可以根据配置的env只编译那些还不支持的特性,

{ test: /.js$/, use: { loader: 'babel-loader', options: { presets: ['env'], cacheDirectory: true //配置允许缓存,加快编译速度 } } }

  1. 安装css处理包 node-sass sass-loader(代码中使用sass,less的配置跟sass一样,只要安装less对应的处理插件即可) 安装css分离处理插件 extract-webpack-text-plugin,把css样式从html页面摘出来放到单独的文件中 sass-loader 依赖于 node-sass,所以这里不要忘记安装 node-sass;首先引入extract-webpack-text-plugin,并new出两个对象来,分别处理css和less,传参为处理后样式的保存路径。

    const ExtractTextPlugin = require("extract-text-webpack-plugin");

    const extractCss = new ExtractTextPlugin('css/[name].css'); const extractLess = new ExtractTextPlugin('css/[name].css');

  2. module中配置loader的rules:

{ test: /.scss$/, use: extractCss.extract({ fallback: "style-loader", use: "css-loader" }) },

  1. plugins里添加extractCss和extractLess插件:

plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname,'src/index.html') }), extractCss, extractLess ]

  1. img,字体等文件loader安装配置 url-loader file-loader 注意:文档里介绍url-loader是基于file-loader封装的支持更多配置的loader,但是经测试发现,url-loader并不能单独使用,需要同时安装file-loader才可以 {//加载图片loader配置 test: /.(png|jpg|gif)/, use: [ { loader: 'url-loader', options: { limit: 8192 //大小限制 } } ] }, {//加载字体等loader配置 test: /.(eot|svg|ttf|woff|woff2)(?\S*)?/,
 use:{
     loader: 'file-loader'
 }
}
6. 在根目录下创建webpack.config.js文件,文件名必须是webpack.config
const path = require('path');//处理路径信息
const config = {
 mode:'development', // development || production
 entry:path.resolve(dirname,'./src/js/index.js'),//webpack 打包入口文件
 output:{
     path:path.resolve(dirname,'./dist'),//打包完成放置位置
     filename:'main.js'//打包后的文件名,这个可以随便取名
 },
 module:{//例如如何解读css,图片如何转换,压缩等
     rules:[
         {
             test:'/.js/', //匹配所有的js文件
             exclude:/node_modules/,//除了node_modules以外
         },
         {
             test:/.css/, //正则选中是css的文件 loader:'style-loader!css-loader' //如果都是css文件的话,都会加载这个模块 }, { test: require.resolve('jquery'), //require.resolve 用来获取模块的绝对路径 use: [{ loader: 'expose-loader', options: 'jQuery' }, { loader: 'expose-loader', options: '$' }] } ] }, //插件,用于生产模板和各项功能 plugins:[], //配置webpack开发服务器功能 devServer:{ // 设置基本目录结构 contentBase:path.resolve(__dirname,'./dist/'), //服务器的ip地址 可以使用ip也可以使用localhost host:'localhost', //服务器压缩是否开启 compress:true, //配置服务端口号,端口号可自行修改 port:9999 } } module.exports = config

一个完整实用的axios封装

1.先引入 import axios from 'axios'
import qs from 'qs'
import router from '../router';
import store from '../store/index';

// 创建axios实例
var instance = axios.create({ timeout: 1000 * 12});
// 设置post请求头
// instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; (可以不在这里封装)

拦截器

instance.interceptors.request.use(
config => {
// 登录流程控制中,根据本地是否存在token判断用户的登录情况
// 但是即使token存在,也有可能token是过期的,所以在每次的请求头
中携带token
// 后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码
// 而后我们可以在响应拦截器中,根据状态码进行一些统一的操作。
const token = store.state.token;
token && (config.headers.Authorization = token);
return config;
},
error => Promise.error(error)
)

响应拦截器

instance.interceptors.response.use(

// 请求成功
res => res.status === 200 ? Promise.resolve(res) : Promise.reject(res),
// 请求失败
error => {
const { response } = error;
if (response) {
// 请求已发出,但是不在2xx的范围
errorHandle(response.status, response.data.message);
return Promise.reject(response);
} else {
      // 处理断网的情况
      // eg:请求超时或断网时,更新state的network状态
      // network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
      // 关于断网组件中的刷新重新获取数据,会在断网组件中说明
          store.commit('changeNetwork', false);
     }
});

1.去掉了之前get和post方法的封装,通过创建一个axios实例然后export default方法导出,这样使用起来更灵活一些。

2.去掉了通过环境变量控制baseUrl的值。考虑到接口会有多个不同域名的情况,所以准备通过js变量来控制接口域名。这点具体在api里会介绍。

3.增加了请求超时,即断网状态的处理。说下思路,当断网时,通过更新vuex中network的状态来控制断网提示组件的显示隐藏。断网提示一般会有重新加载数据的操作,这步会在后面对应的地方介绍。

4.公用函数进行抽出,简化代码,尽量保证单一职责原则。

复制代码 复制代码 // 一些方法的封装

/**

  • 跳转登录页
  • 携带当前页面路由,以期在登录页面完成登录后返回当前页面 */ const toLogin = () => {
    router.replace({
    path: '/login',
    query: {
    redirect: router.currentRoute.fullPath
    }
    });
    }

/**

  • 请求失败后的错误统一处理
  • @param {Number} status 请求失败的状态码 */ const errorHandle = (status, other) => { // 状态码判断 switch (status) { // 401: 未登录状态,跳转登录页
    case 401: toLogin(); break; // 403 token过期 // 清除token并跳转登录页 case 403: tip('登录过期,请重新登录'); localStorage.removeItem('token'); store.commit('loginSuccess', null); setTimeout(() => { toLogin(); }, 1000); break; // 404请求不存在 case 404: tip('请求的资源不存在'); break; default: console.log(other); }}

复制代码

article.js:

复制代码 /**

  • article模块接口列表
    */

import base from './base'; // 导入接口域名列表
import axios from '@/utils/http'; // 导入http中创建的axios实例
import qs from 'qs'; // 根据需求是否导入qs模块

const article = {
// 新闻列表
articleList () {
return axios.get(${base.sq}/topics);
},
// 新闻详情,演示
articleDetail (id, params) {
return axios.get(${base.sq}/topic/${id}, {
params: params
});
},
// post提交
login (params) {
return axios.post(${base.sq}/accesstoken, qs.stringify(params));
}
// 其他接口…………
}

export default article;
复制代码

index.js:

这里这里呢新建了一个api文件夹,里面有一个index.js和一个base.js,以及多个根据模块划分的接口js文件。index.js是一个api的出口,base.js管理接口域名,其他js则用来管理各个模块的接口。 复制代码 /**

  • api接口的统一出口 */ // 文章模块接口
    import article from '@/api/article';
    // 其他模块的接口……

// 导出接口
export default {
article,
// ……
}
复制代码

base.js:

复制代码
/**

export default base;
复制代码
.请求的配置更灵活,你可以针对某个需求进行一个不同的配置。关于配置的优先级,axios文档说的很清楚,这个顺序是:在 lib/defaults.js 找到的库的默认值,然后是实例的 defaults 属性,最后是请求的 config 参数。后者将优先于前者。

最后,为了方便api的调用,我们需要将其挂载到vue的原型上。在main.js中

复制代码 import Vue from 'vue'
import App from './App'
import router from './router' // 导入路由文件
import store from './store' // 导入vuex文件
import api from './api' // 导入api接口

Vue.prototype.$api = api; // 将api挂载到vue的原型上
复制代码
在页面中这样调用接口:

复制代码
methods: {
onLoad(id) {
this.$api.article.articleDetail(id, {
api: 123
}).then(res=> {
// 执行某些操作
})
} } 复制代码
再提一下断网的处理,这里只做一个简单的示例

复制代码

// refresh.vue
beforeRouteEnter (to, from, next) {
next(vm => {
vm.$router.replace(from.fullPath)
})
} 。

这下面贴一下自己封装的。比上面稍简单些,灵活度不是很高,但适合小白,初学者配置使用,算是很实用吧。

复制代码
import axios from 'axios'
// import qs from 'qs'
axios.interceptors.request.use(config => {
let append = document.getElementsByName('body')
append.innerHTML = '<img style="position:fixed;\n' +
' left:47%;\n' +
' top:40%;\n' +
' transform: translateY(-50%),translateX(-50%);"' +
' src="../../static/img/loading2.gif"/>'
return config
}, err => {
return Promise.resolve(err)
})

let base= ‘’ // 接口域名

export const request = (url, params,method,Func,isJson) => {
// let _this = this;
axios({
method: method,
url: ${base}${url},
data: method=== 'post'? params: '',
transformRequest: [function (data) {
if(isJson === 1) {
// debugger // 判断是否json格式或者是表单提交形式
return JSON.stringify(data)
}
let ret = ''
for (let it in data) {
ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
}
return ret // 便于直接取到内部data
}],
headers: {
// 认证和请求方式 'Content-Type': isJson === 1 ? 'application/json' :
'application/x-www-form-urlencoded',
'authorization':sessionStorage.getItem('principal'),
'token':sessionStorage.getItem('token')
},
params: method=== 'get'? params: '',
}).then(data=>{
console.log(data)
if (data.data.code === 200) {
Func(data.data.data)
}else if(data.data.code === 406){
alert(data.data.message)
}else if(data.data.code === 401){
window.location.href=''//上线用这个地址
// window.location.href='/'
}else if(data.data.code === 400 || data.data.code === 505 || data.data.code === 404|| data.data.code === 500){
alert('网络异常')
}else if(data.data.code === 4011){
// window.location.href = '' //本地
window.location.href = '' //线上
}else if(data.data.code === 4012){
console.log(1111)
request('token/refresh',{
'authorization': sessionStorage.getItem('principal'),
'refreshToken': sessionStorage.getItem('refreshToken')
},'get',(res)=>{
//缓存新的token
console.log(res)
let token = res.token;
let principal = res.principal;
let refreshToken = res.refreshToken;
sessionStorage.setItem("token", token);
sessionStorage.setItem("principal", principal);
sessionStorage.setItem("refreshToken", refreshToken);
request(url, params,method,Func);
});
}
})
}

// post
export const postRequest = (url, params,Func,isJson) => {
request(url, params,'post',Func,isJson)
}

// uploadFileRequest 图片上传
export const uploadFileRequest = (url, params) => {
return axios({
method: 'post',
url: ${base}${url},
data: params,
headers: {
'Content-Type': 'multipart/form-data',
'authorization':sessionStorage.getItem('principal'),
'token':sessionStorage.getItem('token')
// 'authorization':'admin',
// 'token':'740a1d6be9c14292a13811cabb99950b'
}
})
}

// get

export const getRequest = (url, params,Func,isJson) => {
request(url, params,'get',Func,isJson)
}
main.js 引入

import {getRequest,postRequest} from './api/http'
Vue.prototype.getRequest = getRequest;     
Vue.prototype.postRequest = postRequest