关于axios:掌握-Axios-的-put-请求实现数据更新的最佳方式

在前端开发中,咱们常常须要与后端服务器进行数据交互。其中,PUT 申请是一种罕用的办法,用于向服务器发送更新或批改数据的申请。通过发送 PUT 申请,咱们能够更新服务器上的资源状态。 Axios 是一个风行的 JavaScript 库,用于在浏览器和 Node.js 中进行 HTTP 申请。它提供了简略易用的 API,使得发送 PUT 申请变得非常便捷。在本文中,咱们将探讨 Axios 的 PUT 申请应用办法,并介绍不同的传参写法。 Axios PUT 申请的应用办法Axios 的应用前提是在我的项目中装置了 Axios。如果你还未装置,能够通过以下命令装置: npm install axios或yarn add axios接下来,咱们就能够在代码中引入并应用 Axios 进行 PUT 申请。 首先,在你的 JavaScript 文件中,应用以下形式引入 Axios: import axios from 'axios';而后,咱们能够通过 Axios 的 put 办法来发送 PUT 申请。上面是根本的应用形式: axios.put(url, data, config) .then(response => { // 申请胜利后的解决 }) .catch(error => { // 申请失败后的解决 });url: 要发送 PUT 申请的服务器端地址。data: 要发送的数据,通常是一个 JavaScript 对象,会被转换成 JSON 格局发送到服务器端。config: 可选参数,用于设置申请的配置,如申请头等。罕用的传参写法接下来,咱们将介绍几种常见的传递参数的写法。 ...

September 8, 2023 · 2 min · jiezi

关于axios:useResource声明式API与useMock基于依赖注入的mock工具

前不久组内的萌新用不晓得从哪里学来的技术,说要封装一套 axios 库供大家应用。 等他开发完,在 code review 环节,大家看到他写的代码都面面相觑,不晓得该如何评估。 我一时间也不晓得该如何评估,只能揭示他不要写死代码,目前 axios 还没入选开源库,前期有可能换成其余替代品。 会后我专门到网上搜一番,发现二次封装 axios 的案例的确不少,但给我感觉其实都一丘之貉,不见得哪个更优良。 过后咱们刚从Java切换到Go,因为Go对于 swagger 反对不够好,前后端对接的接口文档须要手写。 有时候后端批改了接口没有告诉前端,常常遇到互相扯皮的事件。 我突发奇想,既然Go对注解、装璜器的反对很不好,前端的 typescript 语法跟 Java 十分相似,为什么不把Java那套照搬到前端? 不仅能解决前端接口封装的问题,还能躲避go不反对swagger文档的问题。 useResource:申明式API说干就干,我参考 Open Feign 的设计,Feign 的设计很大水平上借鉴了 Spring MVC 。 只是 Feign 次要面向客户端,而 Spring MVC 面向服务端,两者的注解大同小异,Feign 兼容后者而已。 interface GitHub { @RequestLine("GET /repos/{owner}/{repo}/contributors") List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo); @RequestLine("POST /repos/{owner}/{repo}/issues") void createIssue(Issue issue, @Param("owner") String owner, @Param("repo") String repo);}显然这种申明式API的设计,比那些二次封装 axios 的计划优雅太多了,真正做到形象接口与具体实现拆散。 申明式API能够不改变业务代码的前提下,依据理论状况把具体实现在原生 fetch 和 axios 之间切换。 装璜器其实说照搬Java的说法是不正确的,Typescript 只有装璜器的说法,并没有注解。 ...

September 4, 2023 · 6 min · jiezi

关于axios:Vue中requestjs封装

request.js import axios, { AxiosRequestConfig } from "axios";import qs from "qs";// 创立axios实例const instance = axios.create({ baseURL: process.env.VUE_APP_BASEURL, timeout: 6000, // headers: { // "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", // token: // "MTY1Mjk1Mjg4OC42ODM2Nzg0JjJkNzUyOWQwOWU3NTU2OTE0OTU4NzI3ODUxNzkwYTNjZGMwZmRjNjAzNGQ4MGE1YzFkODE1NGVmYzk4MmMyYjM=", // },});// 申请拦截器instance.interceptors.request.use( (config) => { // 申请头和token判断等 return config; }, (err) => { return Promise.reject(err); });//响应拦截器instance.interceptors.response.use( (res) => { return res.data; }, (error) => { if (error && error.response) { switch (error.response.status) { case 400: error.message = "申请谬误(400)"; break; case 401: error.message = "未受权,请登录(401)"; break; case 403: error.message = "回绝拜访(403)"; break; case 404: error.message = `申请地址出错: ${error.response.config.url}`; break; case 405: error.message = "申请办法未容许(405)"; break; case 408: error.message = "申请超时(408)"; break; case 500: error.message = "服务器外部谬误(500)"; break; case 501: error.message = "服务未实现(501)"; break; case 502: error.message = "网络谬误(502)"; break; case 503: error.message = "服务不可用(503)"; break; case 504: error.message = "网络超时(504)"; break; case 505: error.message = "HTTP版本不受反对(505)"; break; default: error.message = `连贯谬误: ${error.message}`; } } else { if (error.message == "Network Error") error.message == "网络异样,请查看后重试!"; error.message = "连贯到服务器失败,请分割管理员"; } return Promise.reject(error); });//get申请export function get(url: string, params = {}) { return new Promise((resolve, reject) => { instance .get(url, { params: params, }) .then((response) => { resolve(response); }) .catch((err) => { reject(err); }); });}//post申请export function post(url: string, params = {}) { return new Promise((resolve, reject) => { instance .post(url, qs.stringify(params)) .then((response) => { resolve(response); }) .catch((err) => { reject(err); }); });}// delete申请export function deleteFn(url: string, params: AxiosRequestConfig<any> | undefined) { return new Promise((resolve, reject) => { instance .delete(url, params) .then((response) => { resolve(response); }) .catch((err) => { reject(err); }); });}// put申请export function put(url: string, params: any) { return new Promise((resolve, reject) => { instance .put(url, qs.stringify(params)) .then((response) => { resolve(response); }) .catch((err) => { reject(err); }); });}export default instance;调用: ...

September 1, 2023 · 2 min · jiezi

关于axios:axios-二次封装的两个小点文件下载和-put-请求的-params-传参

一、应用 axios 下载文件1、创立一个对象,用于配置接口信息 let myObj={ url: process.env.VUE_APP_BASE_API + api/studentList', method: 'get', fileName: 'studengListFile', params:{接口的params参数} }2、封装一个 axios 下载文件的办法 exportMethod(data) { axios({ method: data.method, url: `${data.url}`, responseType: 'blob', params:data.params?data.params:null }).then((res) => { if(res.data.type=='application/octet-stream'){ const link = document.createElement('a') let blob = new Blob([res.data], {type: 'application/vnd.ms-excel'}) link.style.display = 'none' link.href = URL.createObjectURL(blob) link.download = data.fileName //下载的文件名 document.body.appendChild(link) link.click() document.body.removeChild(link) return; } var reader=new FileReader() reader.onload=e=>{ let res=JSON.parse(e.target.result); let error_html="<p><div>"+(i18n.tc(res.key) || 'Error'); error_html+="</div></p>"; let msg= Message({ dangerouslyUseHTMLString:true, message: error_html, type: 'error', duration: 5 * 1000 }) } reader.readAsText(res.data) }).catch(error => { console.log('接口调用失败:',error) })}3、调用办法,并传入后面配置的接口对象 ...

May 11, 2023 · 1 min · jiezi

关于axios:axios进度条功能onDownloadProgress函数total参数为undefined问题

问题形容应用axios发申请,想要实现一个申请的后果进度比方当网络慢的状况,或者某个申请返回的数据量比拟大的状况等最常见的就是下载一个大文件,要查看大文件下载的进度axios的onDownloadProgress函数曾经帮咱们封装好了是基于原生的ProgressEvent套壳子的比方咱们下载一个流文件,要出现下载的进度,在这里打印一下进度事件 axios({ method: "get", responseType: "blob", // 流文件为blob类型 url: "http://ashuai.work:10000/getDoc", onDownloadProgress(ProgressEvent) { console.log('进度事件', ProgressEvent); }}).then(({ data }) => { console.log('接口申请实现',data);});打印后果如下图: 这里为何拿不到total的值? 是因为接口的响应头,没有返回Content-Length属性所以ProgressEvent就拿不到这个值,所以就没有total的值,就为undefined请看响应头 Content-Length 大家能够简要了解成为一个接口返回的内容的总大小,单位字节,咱们晓得了某个时刻loaded多少字节,晓得总字节,就能够得出百分比了解决方案让后端在响应头上加上Content-Length即可 让后端在响应头上加上Content-Length即可 让后端在响应头上加上Content-Length即可 笔者这里应用express演示一下代码: route.get('/getDoc', (req, res) => { res.header('Access-Control-Allow-Origin', '*'); // fs.statSync读取文件信息,读取当前目录下的study.docx文件 let docxUrl = './doc/study.docx' const Myfilesize = fs.statSync(docxUrl).size // 拿到文件字节大小 // 设置申请头 res.writeHead(200, { 'Content-Type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'content-length': Myfilesize // 加上即可 }) let readStream = fs.createReadStream(docxUrl) // 流文件pipe管道返回 readStream.pipe(res);})加上当前,响应头就有Content-Length了,就能失常了 这样的话,进度条成果也就有了 ...

April 13, 2023 · 1 min · jiezi

关于axios:vue3之axios封装集成

前言最近在写admin我的项目时,想对axios方面进行一个彻底的重造,除了惯例的错误信息拦挡外,减少一些新的性能,目前已实现:loading加载、谬误主动重试、谬误日志记录、勾销反复申请,两头也遇到过一些问题,这里记录下如何解决的,心愿对你有所帮忙。 ps:这里应用的vue3+ts+vite根底配置先装置axios:# 抉择一个你喜爱的包管理器# NPM$ npm install axios -s# Yarn$ yarn add axios# pnpm$ pnpm install axios -s初始化axiosimport type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";import axios from "axios";const service: AxiosInstance = axios.create({ baseURL: '/api', timeout: 10 * 1000, // 申请超时工夫 headers: { "Content-Type": "application/json;charset=UTF-8" }});辨别不同环境理论我的项目中,咱们可能分开发环境、测试环境和生产环境,所以咱们先在根目录建设三个文件:.env.development ,.env.production, .env.test 其中 vite 内置了几个办法获取环境变量: 如果你想自定义一些变量,必须要以 VITE_结尾,这样才会被vite检测到并读取,例如咱们能够在刚刚建设三种环境下定义title,api等字段,vite会主动依据以后的环境去加载对应的文件。 # development# app titleVITE_APP_Title=Vue3 Basic Admin Dev# baseUrlVITE_BASE_API= /dev# public pathVITE_PUBLIC_PATH = /# production# app titleVITE_APP_Title=Vue3 Basic Admin# baseUrlVITE_BASE_API= /prod# public pathVITE_PUBLIC_PATH = /# test# app titleVITE_APP_Title=Vue3 Basic Admin Test# baseUrlVITE_BASE_API= /test# public pathVITE_PUBLIC_PATH = /批改axios baseUrl: ...

March 8, 2023 · 5 min · jiezi

关于axios:前端axios调接口实现下载文件的解决方案

有任何问题都能够留言征询。 背景我的项目中有个下载接口,下载的是zip压缩包文件。 但后端返回的是二进制流数据,而不是间接下载一个zip文件。 前端用的是axios来发申请。 解决方案其实这个二进制流数据格式是比拟常见的,对应的content-type是application/octet-stream。 如下截图所示: 接口响应的content-type是application/octet-stream,并且content-disposition是attachment; filename=sslfile.zip。 那此时前端能够怎么解决呢? 有问题可群征询:https://public-1253796280.cos... 详情 请查看原文。

October 28, 2022 · 1 min · jiezi

关于axios:Axios函数柯里化封装-Get

可运行残缺代码<!DOCTYPE html><html><head> <meta charset="UTF-8"> <title></title> <script src="https://unpkg.com/vue@next"></script> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script></head><body> <div id="hello-vue"> {{ message }} </div></body><script>// 函数柯里化// url 不变, 参数变动function get(url) { return function(params) { return axios.get(url + params) .then(res => { console.log('res ', res.data) }) }}// const HelloVueApp = { data() { return { message: 'Hello Vue!!' } }, mounted() { const baseUrl = 'https://www.fastmock.site/mock/320dcea3c1fbc2abb8bc0f60c25569f7/api' // axios.get(`${baseUrl}/blog/1`) // .then((res) => { // console.log('res ', res.data) // }) const getBlog = get(`${baseUrl}/blog/`) getBlog(1) getBlog(2) },}// Vue.createApp(HelloVueApp).mount('#hello-vue')</script></html>

June 29, 2022 · 1 min · jiezi

关于axios:axios-response-data-返回空字符串

最近对做vue3我的项目时封装了一下axios作为网络申请工具,遇到了一个问题:发送post申请时,服务器返回的response data 为空字符串。然而 postman 测试能够失常返回数据(服务器是以json格局返回的数据)揣测是 axios 的配置出了问题。查看config过后是依照axios官网写的配置: const config = { timeout: options.timeout || 15000, headers: options.headers, url: '', method: 'GET', params: {}, data: {}, withCredentials: false, paramsSerializer: function (params) { return qs.stringify(params, {arrayFormat: 'brackets'}) }, transformResponse: [function (data) { // Do whatever you want to transform the data return qs.stringify(data); }],}根本是从官网抄了一些过去。 return new Promise((resolve, reject) => { axios.request({ ...this.config }) .then(response => { console.log('response======', response) resolve(response.data) }) .catch(err => { console.log(err) reject(err.data) })})打印出的response如下: ...

May 28, 2022 · 1 min · jiezi

关于axios:Axios-源码解读-源码实现篇

在上两期,咱们解说了 Axios 的源码: Axios 源码解读 —— request 篇Axios 源码解读 —— 网络申请篇明天,咱们将实现一个繁难的 Axios,用于在 Node 端实现网络申请,并反对一些根底配置,比方 baseURL、url、申请办法、拦截器、勾销申请... 本次实现所有的源码都放在 这里,感兴趣的能够看看。 Axios 实例本次咱们将应用 typescript + node 来实现相干代码,这样对大家了解代码也会比拟清晰。 这里,先来实现一个 Axios 类吧。 type AxiosConfig = { url: string; method: string; baseURL: string; headers: {[key: string]: string}; params: {}; data: {}; adapter: Function; cancelToken?: number;}class Axios { public defaults: AxiosConfig; public createInstance!: Function; constructor(config: AxiosConfig) { this.defaults = config; this.createInstance = (cfg: AxiosConfig) => { return new Axios({ ...config, ...cfg }); }; }}const defaultAxios = new Axios(defaultConfig);export default defaultAxios;在下面,咱们次要是实现了 Axios 类,应用 defaults 存储默认配置,同时申明了 createInstance 办法。该办法会创立一个新的 Axios 实例,并且会继承上一个 Axios 实例的配置。 ...

January 18, 2022 · 5 min · jiezi

关于axios:学会了axios封装世界都是你的

我的项目中对axios进行二次封装随着前端技术的倒退,网络申请这一块,越来越多的程序猿抉择应用axios来实现网络申请。然而单纯的axios插件并不能满足咱们日常的应用,因而咱们应用时,须要依据我的项目理论的状况来对axios进行二次封装。 接下来就我对axios的二次封装具体的说说,次要包含申请之前、返回响应以及应用等。 「1、申请之前」 个别的接口都会有鉴权认证(token)之类的,因而在接口的申请头外面,咱们须要带上token值以通过服务器的鉴权认证。然而如果每次申请的时候再去增加,不仅会大大的加大工作量,而且很容易出错。好在axios提供了拦截器机制,咱们在申请的拦截器中能够增加token。 // 申请拦挡axios.interceptors.request.use((config) => { //....省略代码 config.headers.x_access_token = token return config}, function (error) { return Promise.reject(error)})当然申请拦截器中,除了解决增加token以外,还能够进行一些其余的解决,具体的依据理论需要进行解决。 「2、响应之后」 申请接口,并不是每一次申请都会胜利。那么当接口申请失败的时候,咱们又怎么解决呢?每次申请的时候解决?封装axios对立解决?我想一个略微谋求代码品质的码农,应该都会抉择封装axios进行对立解决吧。axios不仅提供了申请的拦截器,其也提供了响应的拦截器。在此处,能够获取到服务器返回的状态码,而后依据状态码进行绝对应的操作。 // 响应拦挡axios.interceptors.response.use(function (response) { if (response.data.code === 401 ) {//用户token生效 //清空用户信息sessionStorage.user = ''sessionStorage.token = ''window.location.href = '/';//返回登录页return Promise.reject(msg)//接口Promise返回谬误状态,错误信息msg可有后端返回,也能够咱们本人定义一个码--信息的关系。} if(response.status!==200||response.data.code!==200){//接口申请失败,具体依据理论状况判断 message.error(msg);//提醒错误信息return Promise.reject(msg)//接口Promise返回谬误状态} return response}, function (error) { if (axios.isCancel(error)) { requestList.length = 0// store.dispatch('changeGlobalState', {loading: false})throw new axios.Cancel('cancel request')} else { message.error('网络申请失败,请重试')} return Promise.reject(error)}) 当然响应拦截器同申请拦截器一样,还能够进行一些其余的解决,具体的依据理论需要进行解决。 「3、应用axios」 axios应用的时候个别有三种形式: 执行get申请axios.get('url',{ params:{},//接口参数}).then(function(res){ console.log(res);//解决胜利的函数 相当于success}).catch(function(error){ console.log(error)//错误处理 相当于error}) ...

November 11, 2021 · 1 min · jiezi

关于axios:axios是如何取消发生请求的

接口分析https://github.com/axios/axio... 应用形式一const CancelToken = axios.CancelToken;const source = CancelToken.source();axios.post('/user/12345', { name: 'new name'}, { cancelToken: source.token}).catch(function (thrown) { if (axios.isCancel(thrown)) { console.log('Request canceled', thrown.message); } else { // handle error }});source.cancel('Operation canceled by the user.');应用形式二const CancelToken = axios.CancelToken;let cancel;axios.get('/user/12345', { cancelToken: new CancelToken(function executor(c) { cancel = c; })});cancel();就是增加cancelToken参数,值是能够一个对象,有能够勾销的操作。 源码剖析参考应用案例,定位axios.CancelToken,找到源码https://github.com/axios/axio... isCancel.js 判断是否cancel对象module.exports = function isCancel(value) { return !!(value && value.__CANCEL__);};Cancel.js 结构cancel对象,用于标识cancel的message信息function Cancel(message) { this.message = message;}Cancel.prototype.toString = function toString() { return 'Cancel' + (this.message ? ': ' + this.message : '');};Cancel.prototype.__CANCEL__ = true;module.exports = Cancel;CancelToken.jsvar Cancel = require('./Cancel');function CancelToken(executor) { // 执行器必须是函数 if (typeof executor !== 'function') { throw new TypeError('executor must be a function.'); } var resolvePromise; // 创立一个promise,并记录resolve办法,以便在执行器中应用 this.promise = new Promise(function promiseExecutor(resolve) { resolvePromise = resolve; }); var token = this; // cancel的外围办法:用reason来记录勾销起因,并用来判断是否曾经勾销过。并resolve掉下面的promise executor(function cancel(message) { if (token.reason) { // Cancellation has already been requested return; } token.reason = new Cancel(message); resolvePromise(token.reason); });}// 判断是否曾经勾销,如果勾销了,则抛出勾销起因CancelToken.prototype.throwIfRequested = function throwIfRequested() { if (this.reason) { throw this.reason; }};// 静态方法,返回一个实例// 应用形式二的实质就是以下的实现CancelToken.source = function source() { var cancel; var token = new CancelToken(function executor(c) { cancel = c; }); return { token: token, cancel: cancel };};module.exports = CancelToken;搜寻代码cancelToken,定位ib/core/dispatchRequest.js ...

August 20, 2021 · 2 min · jiezi

关于axios:前端网络层优化

旧计划在一个js文件堆放所有接口,间接用axios的post/get办法来封装好。调用端,要思考不同接口的不同状态码、返回的不同格局 问题在日常的开发需要,会遇到同一个我的项目可能会对接不同的后端开发团队,他们的接口不尽相同,如接口前缀、登录态验证的形式、数据返回的格局(数据字段、状态码)等等,从而减少前端对接口调用代码的凌乱。 剖析如何兼顾不同的接口标准?前端如何设计才能够让调用端是统一的,不须要理睬接口的细节? 拆散出变的因素,一一剖析:门路前缀、数据返回格局(状态码字段、信息字段、数据字段)、示意胜利的状态码。不难看出其实就是对axios的调用,门路前缀在实例化的时候传递的,其它都是在数据返回的时候解决的。所以要对不同的后端接口标准新建不同axios实例,对不同的实例,在返回的时候,依照对应的格局返回。 新计划基于axios再封装, ajax.jsimport axios from 'axios';import qs from 'qs';import useInterceptors from './interceptors';class AJAX { constructor(cfg) { // 胜利标记key this.reqSuccessKey = cfg.reqSuccessKey || 'code'; // 胜利标记value this.reqSuccessValue = cfg.reqSuccessValue || [200]; // 音讯key this.msgKey = cfg.msgKey || 'msg'; // 数据key this.dataKey = cfg.dataKey || 'data'; // url前缀 this.basePathPrefix = cfg.basePathPrefix || ''; // 实例化axios this.instance = axios.create({ baseURL: cfg.basePathPrefix, timeout: cfg.timeout || 30000 }); // 初始化interceptors useInterceptors(this.instance) } get(url) { return this.fetch(url); } post(url) { return this.fetch(url, 'post'); } fetch(url, method='get') { return async (query = {}, config = {}) => { if (method === 'get') { query = { params: query }; } try { const res = await this.instance[method](url, query, config); if (this.reqSuccessValue.includes(res[this.reqSuccessKey])) { return res[this.dataKey]; } throw res; } catch (e) { throw e; } }; } }export default AJAX;interceptors.jsconst request = [];const response = [];const interceptors = { request, response};export default function (ajax) { Object.keys(interceptors).forEach(key => { interceptors[key].forEach(interceptor => { ajax.interceptors[key].use(interceptor); }); });}其余在网络层通常还有以下需要: ...

August 18, 2021 · 1 min · jiezi

关于axios:axios发送请求

基于promise的异步ajax申请库axios.interceptors.request.use() 增加申请拦截器axios.interceptors.response.use() 增加响应拦截器get: axios({ url, method, params})axios.get(url[,config])post: axios({ url, method, data})axios.post(url[,config])用axios.create()创立一个新的axios发申请: cosnt requset = axios.create({ //根底门路 baseURL:'http://localhost:8000/'})requset({ method:'POST', url:'/login',//写接口名字就能够,省略域名 data})

May 17, 2021 · 1 min · jiezi

关于axios:跨域-跨域报错

报错蕴含:: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute. 解决办法:axios.defaults.withCredentials = false;(把 ture改为false 即可)

May 14, 2021 · 1 min · jiezi

关于axios:axios的cancelToken

axios的config中提供了一个cancelToken的属性来勾销申请。 用法用法一利用CancelToken.source办法,它会返回带有CancelToken实例和cancel办法的对象。将CancelToken实例赋值给config.cancelToken。在须要勾销申请时调用cancel办法就会勾销带有与这个cancel绝对应的token的所有申请。 var CancelToken = axios.CancelToken;var source = CancelToken.source();axios.get('/user/12345', {//get申请在第二个参数 cancelToken: source.token}).catch(function(thrown) {});axios.post('/user/12345', {//post申请在第三个参数 name: 'new name'}, { cancelToken: source.token});source.cancel('不想申请了');用法二通过实例化一个CancelToken对象,并传入一个回调函数,赋值cancel办法。 var CancelToken = axios.CancelToken;var cancel;axios.get('/user/12345', { cancelToken: new CancelToken((c)=>cancel=c)//实例化一个CancelToken对象,赋值cancel办法}).catch(function(thrown) {});cancel()第一种用法只是在第二种用法上多包了一层,实质差不多 原理剖析// axios/lib/cancel/CancelToken.js'use strict';var Cancel = require('./Cancel');function CancelToken(executor) { if (typeof executor !== 'function') { throw new TypeError('executor must be a function.'); } /** * 定义一个未来能执行勾销申请的promise对象,当这个promise的状态为实现时(fullfilled), * 就会触发勾销申请的操作(执行then函数)。而执行resolve就能将promise的状态置为实现状态。 * 这里把resolve赋值给resolvePromise,就是为了在这个promise外能执行resolve而扭转这个promise的状态 * 留神这个promise对象被赋值给CancelToken实例的属性promise,未来定义then函数就是通过这个属性失去promise */ var resolvePromise; this.promise = new Promise(function promiseExecutor(resolve) { resolvePromise = resolve; }); /** * 将CancelToken实例赋值给token * 执行executor函数,将cancel办法传入executor, * cancel办法可调用resolvePromise办法,即触发勾销申请的操作 */ var token = this; executor(function cancel(message) { if (token.reason) { // 勾销已响应 返回 return; } token.reason = new Cancel(message); // 这里执行的就是promise的resolve办法,扭转状态 resolvePromise(token.reason); });}CancelToken.prototype.throwIfRequested = function throwIfRequested() { if (this.reason) { throw this.reason; }};// 这里能够看清楚source函数的真面目CancelToken.source = function source() { var cancel; var token = new CancelToken(function executor(c) { // c 就是CancelToken中给executor传入的cancel办法 cancel = c; }); return { token: token, cancel: cancel };};module.exports = CancelToken;CancelTokenCancelToken是一个构造函数,通过new CancelToken()失去的是一个实例对象,创立时它只有一个属性promise, 它的值是一个能触发勾销申请的Promise对象。 ...

April 18, 2021 · 3 min · jiezi

关于axios:axios中断请求

浏览器被动中断中断的起因有以下几个: 发动这次申请的DOM元素被删除了。(eg:一个img元素节点,在图片加载实现之前就可怜被删掉了)开发者做了一些使加载数据变得不必要的事件。(eg:你加载了一个iframe,接着间接扭转了src或者用document.write重写了内容)有大量的申请指向同一个服务器,之前申请的谬误表明雷同后续的申请是行不通的(DNS查问谬误、或是排在后面诶对雷同申请是有谬误的,比方400状态码)手动中断中断起因次要有: 同一接口雷同申请参数反复申请同一接口不同参数反复申请跳转页面勾销上个页面的接口申请中断请求的实现办法中断请求的实现原理

March 4, 2021 · 1 min · jiezi

关于axios:axios增强版封装

概述axios库自身曾经很好应用了。然而具体到业务层面,会波及到几个十分高频触发的情景须要提取解决。最罕用的可能如下: 勾销反复的申请。(频繁操作或者state频繁更新导致组件频繁render触发的多次重复申请)失败主动发动重试。(因为网络稳定或者服务器不稳固起因,重发可进步成功率的状况)主动缓存申请后果。(对于实时性要求不高的接口,能够缓存后果,防止申请)思路实现勾销对于axios的勾销机制原理,有一篇文章剖析过了,有趣味的能够跳转查看axios的cancelToken勾销机制原理 剖析: 首先要对立治理多个申请,所以比拟容易想到 应用一个队列来治理申请,而后思考到每个申请的唯一性,就天然会想到Map数据结构。Map申请治理数据结构增加和删除的机会,天然是利用axios提供的申请/响应拦截器来解决。而后每次开始申请和完结申请的时候,检测Map数据申请构造,如果有进行清理。重试重试retry的话,在上述根底上,在响应拦截器里监听如果 error失败,那么再次发动申请即可 缓存cache性能应该是最简略的,只须要在 响应拦截器里缓存response,而后在每次开始申请的时候,检测是否有缓存的response,如果有,则间接返回即可。 技术实现主动勾销先实现主动勾销性能,根据上述剖析,咱们首先须要一个Map数据结构来存储申请。代码如下: class MAxios { private requestMap = new Map();}而后咱们须要一个对外的启动申请的接口函数,承受一些配置项参数。在此函数里,咱们须要实例化axios申请,为了方便管理,使每个申请间的配置互不烦扰,咱们采纳一个申请一个实例的治理。此外还须要对每个申请增加 申请、响应拦截器。伪代码如下: class MAxios { private requestMap = new Map(); private interceptorsRequest(instance: AxiosInstance) {} private interceptorsResponse(instance: AxiosInstance) {} private interceptors(instance: AxiosInstance) { this.interceptorsRequest(instance); this.interceptorsResponse(instance); } /** * 实例工厂函数 */ private getAxiosInstance(config: IConfig) { const instance = axios.create(); return instance; } public request(options: IConfig) { const config = Object.assign({}, defaultConfig, options); // 工厂函数获取axios实例 const instance = this.getAxiosInstance(); // 增加拦截器 this.interceptors(instance); // 返回申请 return instance.request(config); }}接下来咱们着重实现 拦截器细节。对申请拦截器和响应拦截器别离剖析。 ...

March 3, 2021 · 5 min · jiezi

关于axios:promise封装axios方法

axios获取后盾数据的办法插件promise解决异步的办法封装在理论我的项目里为了更不便的应用axios获取后盾数据,这里咱们用promise封装一下vue我的项目里封装办法咱们个别放在utils文件夹里src下新建一个utils文件夹,index.js文件/* eslint-disable no-unused-vars */import axios from 'axios';// const get = () => {// console.log('get申请');// }// const post = () => {// console.log('post申请')// }// export{// get,// post// }// process.env.NODE_ENV环境let baseURL;if(process.env.NODE_ENV=='development'){ baseURL = 'http://192.168.3.40/xxx'}else{ baseURL = 'http://47.114.48.244/xxx'}或者简写: baseURL = process.env.VUE_APP_BASE_API;// baseURL es6 办法const $http = axios.create({ baseURL,})// create 是axios自带的办法export const get = (url,params)=>{ params = params || {}; return new Promise((resolve,reject)=>{ // axiso 自带 get 和 post 办法 $http.get(url,{ params, }).then(res=>{ if(res.data.status===0){ resolve(res.data); }else{ alert(res.data.msg) } }).catch(error=>{ alert('网络异样'); }) })}export const post = (url,params)=>{ params = params || {}; return new Promise((resolve,reject)=>{ $http.post(url,params).then(res=>{ if(res.data.status===0){ resolve(res.data); }else{ alert(res.data.msg); } }).catch(error=>{ alert('网络异样'); }) })}这里用到了的知识点1.baseURL2.axios的create办法3.promise以及axios的get和post ...

February 26, 2021 · 1 min · jiezi

关于axios:axios与axioscreate的区别

参考原文:https://www.cnblogs.com/fsg6/... axios.create()是增加了自定义配置的新的axios 例如:用axios发送申请: axios({ method:'POST', url:'http://localhost:8000/login', data})用axios.create()创立一个新的axios发申请: cosnt requset = axios.create({ //根底门路 baseURL:'http://localhost:8000/'})requset({ method:'POST', url:'/login', data})益处:、1.能够简化门路写法2.当根底门路发生变化时不便批改,有利于保护

February 26, 2021 · 1 min · jiezi

关于axios:axios的cancelToken取消机制原理

最近封装axios,应用到勾销机制,发现应用十分简便,那么axios是如何实现的呢?简略钻研了一下 应用形式axios 如何勾销一个申请提供了两种应用模式: 第一种 调用CancelToken的静态方法sourceconst CancelToken = axios.CancelToken;const source = CancelToken.source();axios.post('/user/12345', { name: 'new name'}, { cancelToken: source.token})source.cancel('Operation canceled by the user.');第二种 本人实例化let cancel;axios.get('/user/12345', { cancelToken: new CancelToken(function executor(c) { cancel = c; })});cancel();OK,能够看到应用非常简单,两种应用形式情理是一样的,分两步: 获取cancelToken实例,注入申请的配置参数须要勾销的时候,调用 提供的cancel办法剖析剖析之前,用了几分钟思考了一下,可能是利用了状态机来管制的,具体怎么实现的,没想好。间接扒拉代码。 CancelToken.js间接找CancelToken类,代码非常简单,如下: function CancelToken(executor) { if (typeof executor !== 'function') { throw new TypeError('executor must be a function.'); } var resolvePromise; this.promise = new Promise(function promiseExecutor(resolve) { resolvePromise = resolve; }); var token = this; executor(function cancel(message) { if (token.reason) { return; } token.reason = new Cancel(message); resolvePromise(token.reason); });}CancelToken.prototype.throwIfRequested = function throwIfRequested() { if (this.reason) { throw this.reason; }};CancelToken.source = function source() { var cancel; var token = new CancelToken(function executor(c) { cancel = c; }); return { token: token, cancel: cancel };};概括一下外围逻辑就是,在实例上挂载了一个 promise,而后把 promise的实例 和 更改promise状态的 resovle函数对外抛出。 ...

January 19, 2021 · 1 min · jiezi

关于axios:axios发送请求时params和data的区别

在应用axios时,留神到配置选项中蕴含params和data两者,认为他们是雷同的,实则不然。 因为params是增加到url的申请字符串中的,用于get申请。 而data是增加到申请体(body)中的, 用于post申请。 比方对于上面的get申请: axios({ method: "get", url: "http://www.tuling123.com/openapi/api?key=20ff1803ff65429b809a310653c9daac", params: { info: "西安天气" },})如果咱们将params批改为data,显然是不能申请胜利的,因为get申请中不存在data这个选项。 总结1、HTTP申请过程中,get申请:表单参数以name=value&name1=value1的模式附到url的前面; 2、post申请:表单参数是在申请体中,也是name=value&name1=value1的模式在申请体中。POST表单申请提交时,应用的Content-Type是application/x-www-form-urlencoded,而应用原生AJAX的POST申请如果不指定申请头RequestHeader,默认应用的Content-Type是text/plain;charset=UTF-8。在html中form的Content-type默认值:Content-type:application/x-www-form-urlencoded如果应用ajax申请,在申请头中呈现 request payload导致参数的形式扭转了 ,那么解决办法就是:headers: {'Content-Type':'application/x-www-form-urlencoded'}或者应用ajax设置:$.ajaxSetup({contentType: 'application/x-www-form-urlencoded'});

January 6, 2021 · 1 min · jiezi

关于axios:axios-各种请求方式传递参数格式

为不便起见,为所有反对的申请办法提供了别名 在应用别名办法时, url、method、data 这些属性都不用在配置中指定axios.request(config)axios.get(url[, config])axios.delete(url[, config])axios.head(url[, config])axios.post(url[, data[, config]])axios.put(url[, data[, config]])axios.patch(url[, data[, config]])axios.request(config)//原始的Axios申请形式axios({ method: 'post', url: '/user/12345', data: { firstName: 'Fred', lastName: 'Flintstone' }, timeout: 1000, ...//其余相干配置}); axios.get(url[, config])axios.get('demo/url', { params: { id: 123, name: 'Henry', }, timeout: 1000, ...//其余相干配置}) axios.delete(url[, config])//如果服务端将参数作为java对象来封装承受axios.delete('demo/url', { data: { id: 123, name: 'Henry', }, timeout: 1000, ...//其余相干配置})//如果服务端将参数作为url参数来承受,则申请的url为:www.demo/url?a=1&b=2模式axios.delete('demo/url', { params: { id: 123, name: 'Henry', }, timeout: 1000, ...//其余相干配置}) axios.post(url[, data[, config]])axios.post('demo/url', { id: 123, name: 'Henry',},{ timeout: 1000, ...//其余相干配置}) ...

January 6, 2021 · 1 min · jiezi

关于axios:简单的request-封装

import axios from 'axios';import {notification} from 'antd';import {router} from 'umi';import Cookies from 'js-cookie';const codeMessage = { 200: '服务器胜利返回申请的数据。', 201: '新建或批改数据胜利。', 202: '一个申请曾经进入后盾排队(异步工作)。', 204: '删除数据胜利。', 400: '收回的申请有谬误,服务器没有进行新建或批改数据的操作。', 401: '用户没有权限(令牌、用户名、明码谬误)。', 403: '用户失去受权,然而拜访是被禁止的。', 404: '收回的申请针对的是不存在的记录,服务器没有进行操作。', 406: '申请的格局不可得。', 410: '申请的资源被永恒删除,且不会再失去的。', 422: '当创立一个对象时,产生一个验证谬误。', 500: '服务器产生谬误,请查看服务器。', 502: '网关谬误。', 503: '服务不可用,服务器临时过载或保护。', 504: '网关超时。',};function checkStatus(response) { if (response.status >= 200 && response.status < 300) { return response; } const errortext = codeMessage[response.status] || response.statusText; if (response.status !== 401) { notification.error({ message: `申请谬误 ${response.status}: ${response.url}`, description: errortext, }); } const error = new Error(errortext); error.name = response.status; error.response = response; throw error;};// 设置axios的返回拦挡(超时)axios.interceptors.response .use(response => { return response; }, error => { if (error.message.includes('timeout')) { return Promise.reject(error); // reject这个错误信息 } // 判断申请异样信息中是否含有超时timeout字符串 return Promise.reject(error); });export default function request(url, params = {}, method = "get") { try { let token = Cookies.get('Authorization'); if (token) { axios.defaults.headers.common["Authorization"] = JSON.parse(token); } // axios.defaults.headers.common["Cookie"] = ''; } catch (e) { console.error(e) } const options = { // `url` 是用于申请的服务器 URL url: url, // `method` 是创立申请时应用的办法 get 或者 post 是小写 method: method, // `baseURL` 将主动加在 `url` 后面,除非 `url` 是一个相对 URL。 // 它能够通过设置一个 `baseURL` 便于为 axios 实例的办法传递绝对 URL // baseURL: baseURL.baseURL, headers: { 'Content-Type': 'application/json; charset=UTF-8', }, timeout: 6000 }; if (method === "post") { options.data = JSON.stringify(params); } else { options.params = {...params}; } return axios(options) .then(checkStatus) .then(response => response.data) .catch((error) => { if (!Cookies.get('currentHistory')) { Cookies.set('currentHistory', window.location.href); } try { let status = error.response.status; if (status === 401) { window.redirectToLoginPage(); } if (status === 403) { router.push('/exception/403'); return; } if (status <= 504 && status >= 500) { router.push('/exception/500'); return; } if (status >= 404 && status < 422) { router.push('/exception/404'); } } catch { router.push('/exception/404'); } return {code: -500} })}window.request = request;

December 21, 2020 · 2 min · jiezi

关于axios:axios中delete请求传参方法

axios中delete申请传参办法1.开发环境 vue+axios2.电脑系统 windows10专业版3.在使vue+axios开发的过程中,咱们依据我的项目的需要可能会应用 axios中的 delete 申请,上面我来分享一下,delete申请办法和传参。4.失常的写法,代码如下: this.$axios.delete('/api/chendelete',{ params: { // 申请参数拼接在url上 id: 12 } }).then((res)=>{ console.log(res); })4-1:效果图如下:5.封装过的申请办法,代码如下: export function fetchDelete(url,param) { return new Promise((resolve, reject) => { axios.delete(url,{params: { // 申请参数拼接在url上 param }}) .then(response => { resolve(response); }, err => { reject(err); }) .catch((error) => { reject(error) }) })}5-1.在vue模板中应用: let a:any={ "name":"111", "pass":"000" } chenDelete(a).then((res)=>{ console.log(res); })5-2.效果图如下:6.本期的分享到了这里就完结啦,是不是很nice,让咱们一起致力走向巅峰!

October 30, 2020 · 1 min · jiezi

关于axios:axios封装和传参

axios封装和传参1.开发环境 vue+typescript2.电脑系统 windows10专业版3.在开发的过程中,咱们会常常应用到 axios进行数据的交互,上面我来说一下,axios封装和传参!4-1:上面构造如下: 4-2:request.js代码如下: import axios from 'axios'import qs from 'qs'axios.defaults.timeout = 2000000; //响应工夫axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; //配置申请头// axios.defaults.baseURL = 'http://192.168.137.208:3000/'; //配置接口地址//POST传参序列化(增加申请拦截器)axios.interceptors.request.use((config) => { //在发送申请之前做某件事 // config.headers.Accept="appliaction/json,text/plan"; if(config.method === 'post'){ config.data = qs.stringify(config.data); } return config;},(error) =>{ console.log('谬误的传参') return Promise.reject(error);});// axios.interceptors.response.use((res) => {// //对响应数据做些事// if (!res.data) {// return Promise.resolve(res);// }// return res;// }, (error) => {// console.log(error);// console.log('网络异样')// return Promise.reject(error);// });//返回状态判断(增加响应拦截器)axios.interceptors.response.use((res) =>{ //对响应数据做些事 if(!res.data.success){ return Promise.resolve(res); } return res;}, (error) => { console.log('网络异样') return Promise.reject(error);});//返回一个Promise(发送post申请)export function fetchPost(url,param) { return new Promise((resolve, reject) => { axios.post(url,param) .then(response => { resolve(response); }, err => { reject(err); }) .catch((error) => { reject(error) }) })}// 返回一个Promise(发送get申请)export function fetchGet(url,param) { return new Promise((resolve, reject) => { axios.get(url,{params:param}) .then(response => { resolve(response) }, err => { reject(err) }) .catch((error) => { reject(error) }) })}export default { fetchPost, fetchGet,}//留神:申请头的配置,决定了传参的办法和格局,申请头的配置至关重要5.SheBei.ts代码如下: ...

October 17, 2020 · 1 min · jiezi

关于axios:一套全面又有实际意义的axios封装api管理方案

[toc] 前言性能点此文次要是基于vuecli3我的项目中axios封装及api治理的实际记录及过程中的踩坑播种,性能根本都是依据工作中需要实现。需要背景是,在同一套申请配置下,实现以下次要性能: [x] 自定义申请配置[x] 设置全局拦截器[x] 响应胜利及异样的全局拦挡对立解决[x] 避免反复申请(勾销以后反复的申请)[x] 路由切换勾销以后所有pending状态的申请(可配置白名单)[x] 独自勾销收回的某个申请[x] api对立治理axios一些个性在开始之前,首先明确一些axios的个性,这些个性会影响到某些性能的实现形式: 通过axios.create()办法创立的实例对象只有常见的数据申请办法,没有勾销申请、并发申请等办法。可通过Object.keys()将所有的key打印进去比照得悉。axios拦截器是能够累加的,每增加一个拦截器,就会返回一个对应的拦截器id,也就是无奈通过新增拦挡的形式笼罩或者扭转已有拦截器的配置。但能够利用拦截器id通过axios.interceptors.request.eject(InterceptorId)办法移除指定拦截器。对于同一个axios对象,如果全局拦截器中设置了CancelToken属性,就无奈在独自的申请中再通过此属性勾销申请。移除全局拦截器能够解决这个问题,但又会有另一个问题,拦截器移除后就永远生效了,影响是全局的。axios中以别名的模式(axios.get、axios.post)发申请,不同的申请形式参数的写法是不一样的,次要是put/post/patch三种办法与其余不太一样自定义申请配置根目录下新建plugins/axios/index.js文件,自定义axios的申请配置。 这里process.env.VUE_APP_BASEURL是一个定义好的变量,值为"/webapi"; 设置超时工夫timeout为10s。如下: import axios from 'axios'axios.defaults.baseURL = process.env.VUE_APP_BASEURLaxios.defaults.timeout = 10000axios.defaults.headers['custom-defined-header-key'] = 'custom-defined-header-value'// 自定义申请头:对所有申请办法失效axios.defaults.headers.common['common-defined-key-b'] = 'custom value: for all methods'// 自定义申请头:只对post办法失效axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';// 自定义申请头:只对get办法失效axios.defaults.headers.get['get-custom-key'] = 'custom value: only for get method';export default axios"main.js"文件: import request from '@/plugins/axios/index.js'Vue.prototype.$request = request这样在组件内就能够通过this.$request(options)或者this.$request.get(options)的办法来申请数据了。 对常见的响应状况对立解决这里次要是在"响应拦截器"中,对于一些常见的申请状态码和跟后端约定好的申请返回码做对立的前置解决。 新建axios.handleResponse.js文件,用于解决常见的失常响应: # axios.handleResponse.js// 解决响应错误码export default (response) => { const status = response.status // 如果http响应状态码response.status失常,则间接返回数据 if ((status >= 200 && status <= 300) || status === 304) { return response } // status不失常的话,依据与后端约定好的code,做出对应的提醒与解决 // 返回一个带有code和message属性的对象 else { const code = parseInt(response.data && response.data.code) // msg为服务端返回的错误信息,字段名自定义,此处以msg为例 let message = (response.data || {}).msg switch (code) { case 400: break case 4001: if (process.server) return message = message || '登录设施数量超出限度' // store.commit('savehttpResult', { res: response.data }) break case 403: message = message || '未登录' break case 404: message = message || '申请地址谬误' break case 412: message = message || '未找到无效session' break default: // message = message || err.response.data.msg break } return { code, message } }}新建plugins/axios/axios.handleError.js文件,用于解决常见的异样响应: ...

October 6, 2020 · 7 min · jiezi

关于axios:Vue中-axios-delete请求参数

vue中axios 的delete和post,put在传值上有点区别;post和put有三个参数,url,data和config,所以在应用这两个时,能够写成axios.post(api,{id:1}),axios.put(api,{id:1}),然而delete只有两个参数:url和config,data在config中,所以须要写成 axios.delete(api,{data:{id:1}}) 如果是服务端将参数当作Java对象来封装接管则 参数格局为:{data: param}var param={id:1,name:'zhangsan'}this.$axios.delete("/ehrReferralObjPro", {data: param}).then(function(response) { }如果服务端将参数当做url 参数 接管,则格局为:{params: param},这样发送的url将变为http:www.XXX.com?a=…&b=…var param={id:1,name:'zhangsan'}this.$axios.delete("/ehrReferralObjPro", {params: param}).then(function(response) { }axios 数组传值时,我传到后盾的是两个字符串数组,然而将参数当成url参数接管时,如果是失常传值,将数组作为一个申请参数传值时,后盾接口接管不到匹配的参数,百度之后应用JSON.stringify(),然而应用当前,后盾多了一对双引号,最初把后盾改成对象封装接管参数,应用的第一种。

September 22, 2020 · 1 min · jiezi

关于axios:post-get-请求方式下载文件

export function downFile(url,parameter,method){ return axios({ url: url, params: parameter, method:method , responseType: 'blob' })}downFile(this.url.exportXlsUrl,param,'get').then((data)=>{ if (!data) { this.$message.warning("文件下载失败") return } if (typeof window.navigator.msSaveBlob !== 'undefined') { window.navigator.msSaveBlob(new Blob([data]), fileName+'.xls') }else{ let url = window.URL.createObjectURL(new Blob([data])) let link = document.createElement('a') link.style.display = 'none' link.href = url link.setAttribute('download', fileName+'.xls') document.body.appendChild(link) link.click() document.body.removeChild(link); //下载实现移除元素 window.URL.revokeObjectURL(url); //开释掉blob对象 } })

September 1, 2020 · 1 min · jiezi

关于axios:axios传递数组参数总结

想要传这样的内容: axios.post(url,{ ids: [1,2,3], type: 1}).then((res) => {})援用 import axios from 'axios'import qs from 'qs'get / delete申请形式解决形式如下 axios.get(url, { params: { ids: [1,2,3], type: 1 }, paramsSerializer: params => { return qs.stringify(params, { indices: false }) }})axios.delete(url, { params: { ids: [1,2,3], type: 1 }, paramsSerializer: params => { return qs.stringify(params, { indices: false }) }})post / put 申请形式解决形式如下 axios.post(url, qs.stringify( params: { ids: [1,2,3], type: 1 }, { indices: false }))axios.put(url, qs.stringify( params: { ids: [1,2,3], type: 1 }, { indices: false }))其余相似。这样一来,数组参数就会转换为如下的模式url?ids=1&ids=2&id=3 ...

August 14, 2020 · 1 min · jiezi

关于axios:vue全家桶之aixos详解

Axios是什么? Axios是一个基于promise的HTTP库,能够用在浏览器和node.js中 Axios的特点从浏览器中创立XMLHttpRequests从node.js创立https申请反对Promise API拦挡申请数据和响应数据勾销申请主动转换JSON数据客户端反对进攻XSRF如何引入?应用npm引入$ npm install axios应用bower引入$ bower install axios应用cdn引入<script src="https://unpkg.com/axios/dist/axios.min.js"></script>应用xhr封装ajax申请参数//4.响应的json数据主动解析为js的对象/数组 function axios({ url, method='GET', params={}, data={} }) { //返回一个Promise对象 return new Promise((resolve,reject) => { //解决method(转大写) method = method.toUpperCase() //解决query参数(拼接到url上) id=1&xxx=abc /* { id: 1, xxx: 'abc' } */ let queryString = '' Object.keys(params).forEach(key => { queryString += `${key}=${params[key]}&` }) if (queryString) { // 去除最初的& queryString = queryString.substring(0,queryString.length-1) // 接到url url += '?' + queryString } //1.执行异步ajax申请 //创立xhr对象 const request = new XMLHttpRequest() //关上连贯(初始化申请,没有申请) request.open(method, url, true) //发送申请 if (method === 'GET' || method === 'DELETE') { request.send() //异步的 }else if(method==='POST' || method === 'PUT'){ request.setRequestHeader('Content-Type','application/json;charset=utf-8')//通知服务器申请体的格局是 request.send(JSON.stringify(data)) //发送json格局的申请参数 } //绑定状态的监听 request.onreadystatechange = function () { //发送申请是异步的,绑定状态的监听为同步因而该函数放哪后面和前面都能够 if (request.readyState !== 4) { return } // 如果响应状态码在[200,300]之间代表胜利,否则失败 //es6解构赋值 const {status, statusText} = request //如果申请胜利了,调用resolve() if (status>=200 && status<=299) { // 筹备后果数据对象response const response = { data:JSON.parse(request.response), //响应体解析好的数据 status, //响应体的状态码 statusText //响应体对应的文本 } resolve(response) }else{ //如果申请失败了,调用reject() reject(new Error('request error status is ' + status)) } } }) }指定默认配置 在文档中具备三个罕用的全局axios默认值: ...

August 14, 2020 · 3 min · jiezi

关于axios:vue页面消毁时取消axios当面所有请求

勾销axios申请,须要理解axios里的 cancelToken 属性{ ... method, data, //`cancelToken`定义了一个用于勾销申请的cancel token //详见cancelation局部 cancelToken: new cancelToken(function(cancel){ })}首页定义一个数组进行贮存每个申请的cancelToken, 能够贮存到Vue对象、vuex、window等,在跳转路由时勾销申请即可;

August 11, 2020 · 1 min · jiezi

关于axios:axios请求

axios基于 http 客户端的 promise,面向浏览器和 nodejs 特点浏览器端发动 XMLHttpRequests 申请node 端发动 http 申请反对 Promise API监听申请和返回转化申请和返回勾销申请主动转化 json 数据客户端反对抵挡装置npm 装置$ npm install axios bower 装置$ bower install axios 通过 cdn 引入<script src="https://unpkg.com/axios/dist/axios.min.js"></script> axios 罕用的办法axios.get(url[, config]) //get 申请用于列表和信息查问axios.delete(url[, config]) //删除axios.post(url[, data[, config]]) //post 申请用于信息的增加axios.put(url[, data[, config]]) //更新操作axios相干配置属性url是用于申请的服务器URL method是创立申请时应用的办法,默认是get baseURL将主动加在url后面,除非url是一个相对URL。它能够通过设置一个baseURL便于为axios实例的办法传递绝对URL transformRequest容许在向服务器发送前,批改申请数据,只能用在'PUT','POST'和'PATCH'这几个申请办法 headers是行将被发送的自定义申请头 headers:{'X-Requested-With':'XMLHttpRequest'},params是行将与申请一起发送的URL参数,必须是一个无格局对象(plainobject)或URLSearchParams对象 params:{ID:12345},auth示意应该应用HTTP根底验证,并提供凭据 这将设置一个Authorization头,覆写掉现有的任意应用headers设置的自定义Authorization头 auth:{username:'janedoe',password:'s00pers3cret'},'proxy'定义代理服务器的主机名称和端口 auth示意HTTP根底验证该当用于连贯代理,并提供凭据 这将会设置一个Proxy-Authorization头,覆写掉已有的通过应用header设置的自定义Proxy-Authorization头。 proxy:{host:'127.0.0.1',port:9000,auth::{username:'mikeymike',password:'rapunz3l'}},

August 5, 2020 · 1 min · jiezi

全栈的自我修养-0003Axios-的简单使用

<h1> 全栈的自我涵养: Axios 的简略应用 </h1> You should never judge something you don't understand.你不应该去评判你不理解的事物。Table of Contents 介绍简略应用 GETDELETEPUTPOSTPATCH汇总应用 application/x-www-form-urlencoded 形式一:应用 URLSearchParams形式二:应用 qs 进行编码应用 multipart/form-dataResponse 构造Config 罕用配置参考介绍Axios 是一个基于 Promise 的 HTTP 库,能够用在浏览器和 node.js 中。 Github开源地址: https://github.com/axios/axios 如果你原来用过 jQuery 应该还记的 $.ajax 办法吧 简略应用如果依照HTTP办法的语义来裸露资源,那么接口将会领有安全性和幂等性的个性,例如GET和HEAD申请都是平安的, 无论申请多少次,都不会扭转服务器状态。而GET、HEAD、PUT和DELETE申请都是幂等的,无论对资源操作多少次, 后果总是一样的,前面的申请并不会产生比第一次更多的影响。 上面列出了 GET,DELETE,PUT, PATCH 和 POST 的典型用法: GETaxios#get(url[, config])从办法申明能够看出 第一个参数url必填,为申请的url第二个参数 config 选填, 对于config 的属性见下文GET 办法用来查问服务资源, 不应该在这里对服务资源进行批改 应用get 办法进行申请,参数能够间接拼接在 url 中axios.get('/user?id=12345') .then(response => { // 如果胜利返回(http 状态码在 200~300),则可获取对应的 response console.log(response); }) .catch(error => { // 异样 console.log(error); }) .then(() => { // always executed });应用get 办法进行申请,参数独自作为一个对象传入, 该参数会拼接在url 中let request_params = { id: 123456 }axios.get('/user', { params: request_params }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }) .then(function () { // always executed });DELETEaxios#delete(url[, config])从办法申明能够看出 ...

July 9, 2020 · 6 min · jiezi

取消重复请求只让最后一次请求通过

axios 请求拦截 取消重复请求(多次重复异步,结束pending状态)前端开发中,会涉及很多异步事件处理,页面展示的处理关系最密切的就是loading图层,但是loading交互在一些时候会不太友好,后端同学也不喜欢loading状态(后端同学:这不就是说我的接口返回慢嘛?我的锅!) 前端函数节流防抖也是一个解决方法,但是又有一个问题是,我们处理的是异步,只要有异步就会有等待,比如,防抖时间是1s,异步事件触发了两次,就需要最快2s完成,假设第一次异步3s返回,第二次异步0.5秒返回;那出现的情况就是,第一次触发的3s异步,1s内没有返回,1s后第二次触发异步,第一次的异步还没有返回,第二次的异步就就开始了,0.5秒后第二次异步返回了,但是最终结果响应的是第一次的异步。 解决方案:利用axios可以很方便的取消重复请求的pending状态,结束重复请求,只让最后一次请求通过 官方文档:http://www.axios-js.com/zh-cn/docs/#%E5%8F%96%E6%B6%88let pending = []; //声明一个数组用于存储每个请求的取消函数和axios标识let cancelToken = axios.CancelToken;let removePending = (config) => { console.log('pending',pending); for(let p in pending){ if(pending[p].u === config.url.split('?')[0] + '&' + config.method) { //当当前请求在数组中存在时执行函数体 pending[p].f(); //执行取消操作 pending.splice(p, 1); //数组移除当前请求 } }}//请求拦截service.interceptors.request.use(function(config) { /*.....*/ removePending(config); //在一个axios发送前执行一下取消操作 config.cancelToken = new cancelToken((c)=>{ // pending存放每一次请求的标识,一般是url + 参数名 + 请求方法,当然你可以自己定义 pending.push({ u: config.url.split('?')[0] +'&' + config.method, f: c});//config.data为请求参数 }); /*.....*/})

June 28, 2020 · 1 min · jiezi

vue中使用axios对同一个接口连续请求导致返回数据混乱的问题

业务上出现一个问题:如果连续对同一个接口发出请求,参数不同,有时候先请求的比后请求的返回数据慢,导致数据顺序混乱,或者数据被覆盖的问题,所以需要控制请求的顺序。 解决方法: 1.直接跟后台沟通,将所有参数放到数组里后台统一接收并返回所有数据再由前端进行数据的拆分使用。 2.对于出现返回的数据混乱问题。假设场景: 页面中需要对三个部门请求对应的部门人员,三个部门人员的数据为一个二维数组,连续发送请求,但由于返回数据的顺序不定,导致数组中的数据顺序不是按照部门的顺序。解决方法:使用promise.all + axios。 //获取部门人员的请求getDepartPerson (departData) { let that = this return new Promise(function(resolve,reject) { that.$axios({ method: 'get', url: ..., params: { ... } }).then(res => { const data = res.data.map(item => { return { value: item.userId, label: item.userName } }) resolve(data) }) }) }, //使用promise.all控制返回的数据顺序setPersonData() { const data = [{ departId: 1, departName: '部门1' }, { departId: 2, departName: '部门2' }, { departId: 3, departName: '部门3' }] let promise1 = this.getDepartPerson(data[0]) let promise2 = this.getDepartPerson(data[1]) let promise3 = this.getDepartPerson(data[2]) console.log(promise1,promise2,promise3) let that = this Promise.all([promise1,promise2,promise3]).then(value => { console.log(value) //value返回的数据是按顺序的 }) }, 这里要注意在promise中this不能指向vue的,所以在promise使用前赋值 ...

November 5, 2019 · 2 min · jiezi

Axiosfetch

Import

October 17, 2019 · 1 min · jiezi

基于-axios-的封装请求

import axios from 'axios'const baseURL = process.env.NODE_ENV === 'development' ? 'http://localhost:4000' : 'http://localhost:4000'axios.interceptors.request.use( config => { let requestName = config.data.requestName if (requestName) { if (axios[requestName] && axios[requestName].cancel) { axios[requestName].cancel(`${requestName} 请求被取消`) } config.cancelToken = new axios.CancelToken(c => { axios[requestName] = {} axios[requestName].cancel = c }) } return config }, error => { return Promise.reject(error) })axios.interceptors.response.use( config => { return config }, error => { console.log(error) let errMsg = '' if (error && error.response) { const map = new Map([ [400, '错误请求'], [401, '未授权,请重新登录'], [403, '拒绝访问'], [404, '请求错误,未找到该资源'], [405, '请求方法未允许'], [408, '请求超时'], [500, '服务器端出错'], [501, '网络未实现'], [502, '网络错误'], [503, '服务不可用'], [504, '网络超时'], [505, 'http版本不支持该请求'] ]) const defaultErrorMsg = `连接错误,服务器返回的状态码为 ${error.response.status}` errMsg = map.get(error.response.status) || defaultErrorMsg } else { errMsg = "连接到服务器失败" } return Promise.reject(errMsg) })export default ({ url, data = {}, params = {}, ...args }) => { return new Promise((resolve, reject) => { axios({ baseURL, url, params, data: { ...data, requestName: url.split('/').slice(-1).pop() }, ...args }) .then(res => resolve(res)) .catch(err => { console.log(err) reject(err) }) })}/** get 请求: await request({ method: 'get', url: '/user/12345', params: { name: 'Bob', age: 20 } }) post 请求: await request({ method: 'post', url: '/user/12345', data: { name: 'Bob', age: 20 } }) */

October 13, 2019 · 1 min · jiezi

重磅从0实现一个axios网络请求框架百分之七十的功能

我们知道,axios是前端一个非常优秀的对于网络请求的框架,其特点主要是请求方便、功能多(如拦截器)。那么作为一枚前端开发人员,了解并能够使用axios其实是基础,深入了解其实现原理才是比较重要的,当然,如果能徒手撸一个axios类似的框架出来,那就是相当的不错了。这篇文章会从以下几个大的点来实现一个axios框架: axios的本质是什么?axios默认值、参数的实现常见请求方式:get、post、delete在axios中的实现真正请求(XMLHttpRequest)的实现axios拦截器的实现打包发布同时希望你了解以下的一些知识点: webpackaxios框架的基本使用Es6的Proxy、Class等XMLHttpRequesthttp协议...等axios的本质是什么使用axios框架的时候,我们大部分情况都是以模块的形式引入进行使用,如: import axios from 'axios'发出一个get请求,如: axios.get('/user')或axios('/user')从中可以看出,axios的本质就是一个函数,那么就先来实现一个axios的雏形。(本篇文章实现利用es6的calss去实现)。 axios.js class Axios{ constructor(){ }}export default new Axios();index.js import axios from './axios'这里毫无疑问可以看出,axios现在只是一个Axios的实例,并不是一个函数,那么要怎样将axios变成一个函数?这就需要两个知识点:Axios的构造函数是可以进行返回值操作、利用ES6的Proxy。更进一步的Axios类的代码如下: class Axios{ constructor(){ return new Proxy(function(){},{ apply(fn,thisArg,agrs){ } }) }}export default new Axios();这样我们得到的一个Axios实例axios就是一个函数了。这里简单提一下,Proxy在进行函数处理的使用,apply是很有用的,使用它我们就可以对一个函数进行代理处理了。 看看打印出来的内容: 接下来,要怎样才能够实现axios('/user')或axios.get('/user')这样的效果呢?,我们知道了axios是一个函数,那么给一个函数增加一个属性(也是函数),就能够解决这个问题了。先来简单看下函数式的写法: 继续完善Axios类中的代码: class Axios{ constructor(){ const _this = this; return new Proxy(function(){},{ apply(fn,thisArg,agrs){ }, get(fn,key){ return _this[key]; }, set(fn,key,val){ _this[key] = val; return true; } }) } get(){ console.log('get request'); }}export default new Axios();这样就实现了axios('/user')或axios.get('/user')这样的效果了。 ...

October 6, 2019 · 3 min · jiezi

使用webpackdevserver创建mock-server

项目地址:https://github.com/yuanyuansh... 在开发基于 api 交互、前后端分离的网页应用时,经常会遇到几个问题: 前端页面已经编排好了,但是后台接口还没准备好我们希望服务器返回特定类型的数据,以测试某页面在特定条件下是否存在问题,但作为前端我们一般不会接触到后端代码和数据库,每次都找后端添加模拟数据又很麻烦。为解决这两个问题,最简单的解决办法就是搭建一个 mock server,专门返回需要的模拟数据。 webpack-dev-server 是我们开发 vue、react 时必备的工具,既然是一个服务器,那么我们是不是可以让他实现一个 mock server 的功能。 原理:通过 webpack-dev-server 的 before 钩子,可以在 webpack-dev-server 上添加我们需要的 mock server 功能,而不需要另行搭建服务器。 只需要少许修改就能 webpack-dev-server 当做 mock server 来用,并且对同一 URL 下的 GET、POST、PATCH 等不同的 HTTP METHOD 做分别处理,支持热切换。 使用方法很简单,在 webpack.dev.conf.js 的 devServer 中添加新钩子 before,将所有请求交由 apiMocker 处理,然后当需要使用模拟数据时,只需要将请求的 URL 改为 webpack 服务器上既可。项目地址webpack_api_mocker 安装npm install mocker-api --save-dev使用package.json中配置 "dev-mock": "cross-env MOCK=true webpack-dev-server --inline --progress --config build/webpack.dev.conf.js"webpack.dev.conf.js中配置 devServer: { before (app) { if (process.env.MOCK) { apiMocker(app, path.resolve('mock/mocker'), { proxy: apiDomainMap, changeHost: true }) } } }apiDomainMap.js配置 ...

August 21, 2019 · 1 min · jiezi

笔记js异步下载文件

之前因为懒,异步请求的下载都是直接写在a标签里,请求权限让后端做特殊处理判断,就像这样<a href="getRequestUrl">点击下载</a>现在觉得这样处理不太好,一个是后端权限要做单独判断,另一个是如果调用接口报错就没办法处理了,研究之后修改了一下,项目用了axios这个lib,所以是针对axios的request和response做了修改,不过对于原生写法和其他库,原理是一样的1.将请求的responseType设置为blobfunction exportData(p) { return axios({ url: '/data/export', method: 'get', params: p, responseType: 'blob' });}2.对response进行处理因为项目里用了response拦截器来处理响应,所以我在拦截器里做了处理,也可以单独处理。 axios.interceptors.response.use( response=> { // ... // Blob类型处理 let checkType = response.config.responseType; if(checkType === "blob" && res.type === 'application/octet-stream') { // 正常下载时直接返回响应数据 return response.data } else if(checkType === "blob" && res.type === 'application/json') { // 请求出错时,接口返回的内容是json,于是将blob中的内容取出 let reader = new FileReader(); reader.onload = function(event){ let content = reader.result; // blob中的内容 Message({ message: JSON.parse(content).desc, type: 'error', duration: 5 * 1000 }) }; reader.readAsText(response.data); return Promise.reject('error') } // ... }, error => { // ... })3.html页面自动开始下载exportData(para).then(res => { let content = res; let aTag = document.createElement('a'); let blob = new Blob([content]); aTag.download = 'Datas.xlsx'; // 也可以让后端设置文件名,通过headers返回 aTag.href = URL.createObjectURL(blob); aTag.click(); URL.revokeObjectURL(blob);}).finally(() => {})参考博客:https://www.cnblogs.com/coder...

July 3, 2019 · 1 min · jiezi

vuecli的npm包

为了方便在项目的中使用的vue框架,自己搭建了一套vue-cli,欢迎大家使用,并提出问题,谢谢 1.安装npm包cnpm(npm) install create-frame-vue -g 2.使用create-frame-vue指令就可以创建项目 使用指令后你可以看到这么的 指令完成之后创建的项目 npm install && npm run serve 即可启动项目。 欢迎大家使用,希望大家提供好的建议或意见,谢谢大家

June 27, 2019 · 1 min · jiezi

vuecli30-axios-跨域多个代理

在使用vue-cli3.0 结合 axios 请求后台多个server,遇到跨域问题,进行以下几个步骤的改动,就可解决1、vue.config.js devServer: { open: true, port: 8081, proxy: { '/api': { target: process.env.TARGET1, changeOrigin: true, pathRewrite: { '^/api': '', }, logLevel: 'debug', }, '/ips': { target: process.env.TARGET2, changeOrigin: true, pathRewrite: { '^/ips': '', }, logLevel: 'debug', }, }, },2、.env TARGET1= "http://10.50.60.100:8088"TARGET2= "http://10.50.60.100:50050"3、api export function test1(data) { return request({ url: 'api/test1', method: 'post', data, });}export function test2(data) { return request({ url: 'ips/test2', method: 'post', data, });}

June 26, 2019 · 1 min · jiezi

axios重复点击取消上一次请求封装

使用场景重复点击或者多tab标签使用一个视图等(当然也可以用加载中或者透明背景禁止请求中再次点击) 封装代码来自于互联网 let pending = []; //声明一个数组用于存储每个请求的取消函数和axios标识let cancelToken = axios.CancelToken;let removePending = (config) => { for(let p in pending){ if(pending[p].u === config.url + '&' + config.method) { //当当前请求在数组中存在时执行函数体 pending[p].f(); //执行取消操作 pending.splice(p, 1); } }}// http请求拦截器axios.interceptors.request.use(config => { removePending(config); //在一个axios发送前执行一下取消操作 config.cancelToken = new cancelToken((c)=>{ // 这里的axios标识我是用请求地址&请求方式拼接的字符串,当然你可以选择其他的一些方式 pending.push({ u: config.url + '&' + config.method, f: c }); }); return Promise.resolve(config)}, error => { return Promise.reject(error)})// http响应拦截器axios.interceptors.response.use(data => { removePending(data.config); //在一个axios响应后再执行一下取消操作,把已经完成的请求从pending中移除 return Promise.resolve(data) }, error => { //加载失败 return {'data':{}} // return Promise.reject(error)})经过多次测试发现不同请求也给我取消了,原因是没有校验请求参数,也就是说get请求可以用,修改以下代码 ...

June 19, 2019 · 1 min · jiezi

Emberjs-通过-axios-下载文件

Emberjs 通过 axios 下载文件摘要: 目前项目中需要与后端合作,通过发送 GET 请求,后端返回文件流,前端进行文件的下载。使用到的技术有: Emberjsaxios思路接到这个需求的话,想着使用创建 a 链接,然后模拟点击 a 链接来完成下载,但是情况不是这样的。后端有多于一个的下载接口,首先是生成下载文件的接口, 这个接口主要是返回 需要下载的文件的name 以及相应的接口地址。而下载的文件可能不止一个,同时,对文件接口地址发送 GET 请求,会返回文件流,但是我们需要的是 CSV 格式的文件,所以想到通过 axios 来实现这个需求。 具体做法既然方向确定了,那就是去做了。 在项目中安装插件/导入 axios现在 Emberjs 封装好的 axios 插件 - ember-axios ,使用 ember install axios。这个插件没有文档,所以只能看源码,还好源码比较简单,就是简单的将 axios 的一些方法封装成一个 service 内的方法。 在项目文件中引入 axios安装后在 Emberjs 项目中将此 service 引入近来 import { inject as service } from '@ember/service';export default Controller.extend({ // ... axios: service() // ...});这样即可使用这个插件中封装的一些 axios 的方法。 使用之前也说过当前项目需要先发送一个请求,请求文件的接口地址。返回的值的格式为: { "fileNames":[ "filename=downloadFile1.csv", "filename=downloadFile2.csv" ], "status":"ok"}可以看到,如我们所想的那样,返回的并不一定是单个文件的地址,所以我们在接收到这个数据后: ...

June 19, 2019 · 1 min · jiezi

axios跨域请求默认不携带cookie

最近开发一款前后端分离的应用,后端接口全部完成,正在对接的时候发现死活登录不上。前端是本地server,跑在localhost上,后端接口部署在测试服务器上。后端已经允许了跨域,接口也能跑通,但是就是登录不上。而且接口的表现十分奇怪,request headers里显示一个感叹号+Provisional headers are shown。如下图:![图片描述][1]由于登录不上,怀疑是否是cookie未携带,但是无论如何操作,chrome面板总是只显示这4个header。尝试用QQ浏览器打开查看header,感叹号+Provisional headers are shown没有了,显示了实际的request headers。如下图:![图片描述][2]发现确实没有携带cookie。查阅axios文档,配置项有一个withCredentials,表示跨域请求时是否需要使用凭证,默认值为false。即axios 在发起跨域时默认不携带cookie,将withCredentials设置为true即可正常携带cookie。

June 18, 2019 · 1 min · jiezi

vuex-开发-测试-生产环境-配置axios

1、vue2使用 vue-cli安装的项目 config目录下面都有 dev.env.js/test.env.js/prod.env.js文件,做相应的修改,添加API_ROOT module.exports = merge(prodEnv, { NODE_ENV: '"development"', API_ROOT: '"http://www.eastgrain.cn"'})2、src下面添加api目录添加api.js文件 import axios from 'axios'// 创建配置const Axios = axios.create({ baseURL: process.env.API_ROOT, timeout: 20000, headers: { 'Content-Type': 'application/json' }})// request 拦截器 请求开始显示loading等等Axios.interceptors.request.use((config) => { console.log(config, 'config axios配置') // 显示loading... return config}, (error) => { return Promise.reject(error)})// response 拦截器Axios.interceptors.response.use((response) => { console.log(response, 'axios response配置') // 这里可以做处理,response.data.code 错误码不同显示不同错误信息 return response.data}, (error) => { return Promise.reject(error)})export default Axios3、在文件中调用 import Axios from '@/api/api'methods: { // 访问接口 getFormData () { Axios.post('customer/modifyUserInfo.json', {phone: 15001209233}).then((success) => { console.log(success)// 这里可以出发vuex中的mutations、actions来修改vuex state中的数据 }).then((err) => { console.log(err) }) },

June 18, 2019 · 1 min · jiezi

终于解决了如何-使用axios设置session过期的跳转

通常如果我们想要使用axios设置过期时的跳转,我们的思路是 拦截axios返回的response进行操作。如下官方文档 下面便是我再项目中的用法: 其中store和router是引入的vue-router和vuex的实例,用于在非.vue的文件中操作store和router。 然而,在过期后,不仅弹出了过期的提示,还弹出了组件中axios.post调用失败后catch中的提示。 这不是我要的,我就要简简单单弹出个过期就完了,不需要其他乱七八糟的提示。这是什么原因呢,因为上面interceptors.response中的 MessageBox.alert弹框之后,执行了return操作,把response结果返回给了组件中的axios.post。 所以接下来的解决方案就是,我弹框后,不return了 唉,事与愿违。还是不行。和上面一样的结果,都弹出了两个框。 看来直接return result不行,那么return一个promise呢,promise中resolved(result)呢? 漂亮,和预期一样( 长舒一口气) 点击确定,跳转到登录页面。 等等,什么鬼,为什么又跳出一次? 看来是因为组件中,不仅调用一次axios.post, 而是发了好几个请求。所以每进 一次instance.interceptors.response,都会判断一下。 那我们让他弹一次不就行了。 设置个定时器,这个定时器只进入一次,后面都不会进入。 点击超时的弹框后,直接跳转到登录页面,再也没有出现超时弹框,好,完美。 至此问题解决。

June 5, 2019 · 1 min · jiezi

vue-axios-post发送复杂对象的一点思考

一、项目情形现在vue项目中,一般使用axios发送请求去后台拉取数据。在某些业务场景中,前端需要在某个字段中发送一个复杂的嵌套对象给后台做保存并处理。虽然axios可配置发送方式(post/get等),但如果不做其他配置,post的数据其实也是拼在请求地址后面,而这种传输方式会有很多问题: 可能数据丢失;get传送的数据长度有limit,如果需要保存大段的中文,会报错;数据不直观,复杂对象的格式会出现问题。二、解决方案 怎么实现使用post方法时,能实现formData方式提交,而且整个请求数据格式能像queryString一样直观。 1、使用QS将数据序列化 //main.jsimport axios from 'axios';Vue.prototype.$axios = axios; // 配置axios的访问方式//demo.vueimport Qs from qs;this.$axios({ method: "post", url: "url", data: reqData, transformRequest: [ function(data){ return Qs.stringify(data) //使用Qs将请求参数序列化 }], headers: { 'Content-Type': 'application/x-www-form-urlencoded' //必须设置传输方式 }}).then((res)=>{ //逻辑代码}2、完成第一步后,可以实现post请求了,请求体为formData的格式,但如果reqData是一个对象嵌套数组的复杂对象,form的格式会变得非常不直观。 //例如obj为一个嵌套多层的复杂对象let reqData = { id: '123', status: '1', data: { innerData: { price: "higher", amount: "2000", }, outerData: { price: "lower", amount: "3000"! }, parts: ['123','234','345','456'] }}参考如上配置,最后请求体中parsed的数据格式会变成如下 对象跟数组的每一项都被拆拼成键值对,数据格式非常不直观,如果此时后台需要将对象整个储存起来,以便下次使用使用录入的数据还原前端页面,则会增加很多额外的转化工作。 3、可以怎样简单处理一下,让它变得像如下图一的get方法一样参数清晰呢? (图一)get方法地参数效果示意图 只需做一个简单的处理,将复杂对象对象变成字符串,再进行传输。 ...

June 4, 2019 · 1 min · jiezi

前端培训初级阶段场景实战20190606ContentType对照表及日常使用

前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每周四)。 axios 日常使用上,感觉不如 $.ajax 但是我之前使用的时候不是改入参就是改方法反正是都解决了。我也知道问题出在 content-type 上。就是记不住,这不前几天后台项目起了个新的服务。之前用的构建开发工具用的是 proxy 代理,不知道有老哥用过没,好几年前初次开发的时候就不更新了,还有 bug。索性换 axios 代理一下吧,然后报错了。好吧,我的锅,我认真总结,保证我不忘了。 今天讲什么?content-type 是什么MIME 对照表axios 为什么感觉不如 $.ajax带你领略 axios 正确打开方式content-type 是什么Content-Type 实体头部用于指示资源的 MIME类型 media type 。在响应中,用来描述服务端实际发送给客户端的数据的类型。在请求中,比如 POST请求,是指客户端给服务器实际发送的数据的类型。双方根据这个值,来选择适合的方式解析数据。 MIME 类型组成方式type/subtype,如application/json、text/html、text/plain对大小写不敏感,但是习惯写小写。 content-type 组成方式Content-Type:media-type; charset,如Content-Type: text/html; charset=utf-8 表单中的应用<form action="/" method="post" enctype="multipart/form-data"> 想上传文件的时候<form action="/" method="post" enctype="application/x-www-form-urlencoded"> 默认为什么想上传文件不能用第二个呢?带着你的问题往后看吧 MIME 对照表Media Types -全量的对照表 MIME 分类type关键词描述示例text文本。复制粘贴的里面常见。text/html html页面, text/css css文件,text/plain 通用文字(默认格式)image图片。input.files[0].type 返回的时候用于判断类型。input accept="image/*" 允许选择所有图片文件image/png png图片, image/jpeg jpg图片audio音频。同上audio/wav,audio/mpeg mp3文件video视频。同上video/mp4 MP4文件application二进制数据application/octet-stream 通用类型(默认格式),application/pdfmultipart复合类型multipart/form-data常见 MIMEkey描述application/octet-stream默认值,或者可以理解为未知的应用程序文件。浏览器会像对待设置了 HTTP 头 Content-Disposition 值为 attachment 的文件一样来对待这类文件。(微信下载文件)text/html可以理解为 html、xml 文件。text/plain默认值,也可以理解为未知格式的文本文件。文本文件嘛,没格式就只看字也不是啥大问题image/png常见图片类型,一般上传图片的时候判断image/jpeg常见图片类型,一般上传图片的时候判断image/gif常见图片类型,一般上传图片的时候判断multipart/byteranges用于把部分的响应报文发送回浏览器。常见于请求视频资源返回206状态码application/jsonJSON 格式multipart/form-data用于带文件上传的表单提交。作为多部分文档格式,由边界线(一个由'--'开始的字符串)划分出的不同部分组成。每一部分有自己的实体,以及自己的 HTTP 请求头,Content-Disposition 和 Content-Type。application/x-www-form-urlencoded普通的 get&post 请求。数据被编码为键/值对。(a=1&b=2)这是标准的编码格式。axios 为什么感觉不如 $.ajax(同样代码 jquery 好使,axios 不好使,axios 有 bug 吧)-这个应该是我听到最多的吐槽了。测试地址 ...

June 3, 2019 · 2 min · jiezi

项目中配置axios

先占个坑,毕设项目完成后,回来填坑~

May 30, 2019 · 1 min · jiezi

vue读取本地的excel文件并显示在网页上

我想实现读取一个本地的xlsx文件(task_list.xlsx)然后显示在网页上, 一开始选择的方法是建个express server, 通过发送axios请求来实现, 但是觉得只是读取一个本地文件还要搞个server太复杂了, 最终还是通过"xlsx"模块 + axios实现了读取本地文件, 无需后端, 步骤如下: 1.通过vue-cli新建项目: 2.编写分析excel workbook的脚本/src/scripts/read_xlsx.js const XLSX = require('xlsx')//将行,列转换function transformSheets(sheets) { var content = [] var content1 = [] var tmplist = [] for (let key in sheets){ //读出来的workbook数据很难读,转换为json格式,参考https://github.com/SheetJS/js-xlsx#utility-functions tmplist.push(XLSX.utils.sheet_to_json(sheets[key]).length) content1.push(XLSX.utils.sheet_to_json(sheets[key])) } var maxLength = Math.max.apply(Math, tmplist) //进行行列转换 for (let y in [...Array(maxLength)]){ content.push([]) for (let x in [...Array(tmplist.length)]) { try { for (let z in content1[x][y]){ content[y].push(content1[x][y][z]) } } catch (error) { content[y].push(' ') } } } content.unshift([]) for (let key in sheets){ content[0].push(key) } return content}export {transformSheets as default}3.新建一个组件/src/components/task_list.vue ...

May 28, 2019 · 1 min · jiezi

项目中JavaScript-中最大的安全整数

什么是最大安全整数?MAX_SAFE_INTEGER 是一个值为 9007199254740991的常量。因为Javascript的数字存储使用了IEEE 754中规定的双精度浮点数数据类型,而这一数据类型能够安全存储 -(253 - 1) 到 253 - 1 之间的数值(包含边界值)。--- MDN WEB DOCS在项目会导致什么错误?在代码中输出比MAX_SAFE_INTEGER大的Number值 console.log(9007199254740999) // 9007199254741000console.log(9007199254740993) // 9007199254740992在代码中比较超出安全存储的数值,可能会存在下列情况 9007199254740993 === 9007199254740992 // true实际项目中碰到的问题在进行vue 项目开发的时候,通过axios进行前后端数据交互 后端在定义某些数据时将数据的ID 设置为比MAX_SAFE_INTEGER大的int类型 而我取到后也没有注意到这一情况,在修改某一条数据时,是通过传回数据ID进行数据定位的。 然后问题就出现了。。。。 数据死活修改不了,后端返回无这条数据,调试了半天, 然后通过对比preview 和 response 中的数据发现了两者数据不一致 如何解决?第一个想法是在axios的拦截器中做处理,将数字类型转换为字符串 9007199254740993 => '9007199254740993'但经过尝试后发现axios拦截器中的数据本身就是错误了。 然后就用了原生的fetch 做处理 export function getData(data) { const promise = new Promise(function (resolve, reject) { const headers = new Headers() headers.append('Content-Type', 'application/json') const config = { method: 'POST', headers, body: JSON.stringify(data) } fetch('api/url', config).then(res => res.text()).then(text => { function numberToString (match) { return `:"${match.substring(1, match.length - 1)}",` } const responseJson = JSON.parse(text.replace(/:\d{15,100},/g, numberToString)) resolve(responseJson) }) }) return promise}但问题是这个只解决了一个api 的问题,然后每个都这样写,太烦了。而且fetch 并没有axios中的拦截器,不能统一处理异常 ...

May 27, 2019 · 1 min · jiezi

分享一个vue项目脚手架项目

搭建缘由源于公司每次新启动一个由多人协同开发的项目都由负责人初始化项目之后,每个人再去从私服pull一下项目才开始开发。但是每次初始化工程都是一步步的造轮子,一个个依赖去安装,新建一个个不同功能的文件夹,而每个负责人所初始化的项目目录、以及模块引入方式参差不齐,以至于开发中后期因每个人开发风格的不同导致git提交时总会产生各种各样的“冲突”,也会产生后期代码维护成本增加,所以就有必要考虑一下做一个统一的类似“脚手架”的功能了,用来给团队开发带来便捷的、统一的、易扩展的项目基础。 预实现的功能公共样式统一管理,全局sass的友好引入公共js统一管理解决vue脚手架初始化的部分问题路由形式、接口统一管理store模块化管理定义vue前端项目必用的方法修改好统一的config配置全局混入/指令的封装必要的依赖项node-sass sass sass-resources sass-loader sass-recources-loadervuex vuex-persistedstateaxiosbabel-polyfill项目目录如下 配置公共sass目录assets>scss文件形式 mixin.scss内容详见 mixin公共sass函数 common.scss内容如下 @import './mixin.scss'; // 公共函数@import './icomoon.css'; //字体图标@import './wvue-cli.scss'; //项目公共样式修改utils.js引入commom.css,就不用在main.js 或其他项目中的页面引入了 //57行开始function resolveResouce(name) { return path.resolve(__dirname, '../src/assets/scss/' + name); } function generateSassResourceLoader() { var loaders = [ cssLoader, // 'postcss-loader', 'sass-loader', { loader: 'sass-resources-loader', options: { // it need a absolute path resources: [resolveResouce('common.scss')] } } ]; if (options.extract) { return ExtractTextPlugin.extract({ use: loaders, fallback: 'vue-style-loader' }) } else { return ['vue-style-loader'].concat(loaders) } } // 注意这里 return { css: generateLoaders(), postcss: generateLoaders(), less: generateLoaders('less'), sass: generateSassResourceLoader(), scss: generateSassResourceLoader(), stylus: generateLoaders('stylus'), styl: generateLoaders('stylus') }接口统一管理js目录下的urlConfig.js ...

May 26, 2019 · 3 min · jiezi

vuecli3-vant-rem-移动端框架方案

描述基于vue-cli3.0+webpack 4+vant ui + sass+ rem适配方案+axios封装,构建手机端模板脚手架 vuecli3.0多环境开发axios封装rem适配方案多环境开发之前写过一个多环境的方案,是基于vue-cli2.0的vue多环境配置方案-传送门最近新的项目采用了vuecli3.0开始了一番折腾 这里参考了 vue-admin-template基本思路不变在src的文件里新建config 根据不同的环境去引用不同的配置文件,不同的是在根目录下有三个设置环境变量的文件这里可以参考vue-admin-template 这里有个问题,既然这里有了根据不同环境设置变量的文件,为什么还要去config下新建三个对应的文件呢?个人比较喜欢这种引入的方式而,比如我需要在文件引入api.common_api import { api } from '@/config'// apiconst { common_api } = api rem适配方案还是那句话,用vw还是用rem,这是个问题? 选用rem的原因是因为vant直接给到了这个适配方案,个人也比较喜欢这个方案 总结因为项目刚刚构建起来,后面还会持续更新,实际使用过程中一定还有很多问题,如果文章中有错误希望能够被指正,一起成长 项目github地址 关于我您可以扫描添加下方的微信并备注 Soul 加交流群,给我提意见,交流学习。 如果对你有帮助送我一颗小星星(づ ̄3 ̄)づ╭❤~ 转载请联系作者!

May 23, 2019 · 1 min · jiezi

axioskoa-开发小记

Access to XMLHttpRequest at 'http://localhost:8888/' from origin 'http://localhost:8080' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.axios如果携带着data参数发送请求,会添加一个自定义请求头:Access-Control-Request-Headers: content-type,在发送正式请求前会发送OPTIONS预检请求,如果后端没有对应的设置响应头,将无法通过而报出以上错误。 解决方法: server.use(async (ctx, next) => { console.log(`visited PATH: ${chalk.blue(ctx.path)}`) ctx.set({ 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'Content-Type' }) await next()})后端放行这个请求头

May 14, 2019 · 1 min · jiezi

vue项目中遇到的一点小问题记录

1、鼠标悬浮显示不同的背景图片,代码如下:效果如图,页面初始效果:鼠标悬浮后效果: 2、for 循环发送axios遇到的问题问题背景:在声动语商项目中,需求更改后,出现一个:教师发布课程的时候要求一个课程同时发送给多个班级。现在的接口:每次只能发送一个班级的id,也就是:classesId字段只能传一个班级的id,因此为了满足这个新需求就想着:将select修改为多选,使用for循环循环用户选中的班级数组,使用axios发送创建课程请求。更改后的界面如下图所示: 问题复现:思路:使用for循环,发送axios,发现请求发送的data中classesId总是最后一个,立马想到了闭包,以为是闭包问题,于是使用 这种方法想着解决下闭包,重新发送axios请求发现classesId数据还是不对。然后自我怀疑,以为自己写的闭包是不是有啥问题.... 于是使用了第三方lodash的forEach方法一下,将axios请求写到了foreach里面,重新运行还是发现不对。。。。 以为this指向有问题,有将this重新赋值,结果:还是一样。。。。。。。 于是又调整了一下代码:将axios请求重新封装出去,重新在for循环里面调用,结果:还是不对 打断点发现for循环出来的classesId数据是对的,但是加上axios请求,每次请求发送的classesId还只是最后一个的 又想着是不是axios的异步请求影响的,于是将axios改为了同步请求,结果:还是一样,这个时候,整个人就有点不好了。。。。 眼看着快要下班了,而这个问题已经看了一下午还没有解决,就很着急啊啊啊啊 努力回想自己曾经这样请求过啊,当时并没有发生任何不对。于是想着将请求的数据简化一下,就将发送的data数据简化到了只有classesId,想着只有一个数据了,就没有再定义任何的变量,直接将数据写到了axios请求内部。运行发现:classesId竟然是对的。。。。于是立马将其他数据都写到了axios请求内容,发现结果对了,天啊,终于看到了希望。。。。 问题原因:将这两种数据的定义及发送方式对比,分析问题可能是因为 js赋值的深拷贝和浅拷贝造成的。。。 其他解决过程中还试了watch监听for循环classesId的变化,发现也只能监听获取到最后一个classesId.,并不能解决这个问题

May 14, 2019 · 1 min · jiezi

vuecli构建的小说阅读器

项目介绍主要页面1、首页home.vue分类展示书籍,幻灯片展示热门推荐2、搜索search.vue,上拉加载更多3、书籍详情book.vue加入书架、立即阅读,展示评论,同类书籍推荐4、书籍内容read.vue,获取目录,存储翻阅的章节位置,5、书架bookrack.vue,获取加入书架的书单 技术栈vue、vue-cli、axios、vue-router、vuex、localStorege 入口页面app.vue分成底部导航 跟 主视图容器 router-view首页tabbar/Home包含: components/sub/item 和 components/sub/search 、components/sub/header结构: banner切换 与 搜索 和 小说分类楼层 小说楼层单独定义了组件 components/sub/item , home循环楼层分类名称,并将楼层分类id传给item组件 :booklistId='{id:item._id}' , item组件用props: ["booklistId"] 接收分类id, 并根据分类id获取对应的数据item.vue mouted: this.getlist(this.booklistId.id);methods: getlist(id) { //每个分类id下对应的数据 子组件接收父组件传过来的id 获取对应的数据 bootd(id).then(res => { var arrdata = res.data.data; arrdata.map(item => { this.booklist.push(item.book); }); }); }小说详情页components/book/Book.vue包含: components/sub/yuedu 、mulu、pinglun、结构: 小说概况与简介,是否加入书架或者继续阅读 ,目录、评论、同类书籍推荐加入书架/立即阅读(yuedu.vue)组件 加入书架,获取书籍信息,并把相关书籍信息存放在书架中、存localbook.vue computed: { ...mapState(['calbook','shuajiabook']) //书籍信息 书架数据[] }, methods:{ addbook(){ this.flag=!this.flag var book= this.calbook; // calbook 是store里存储的书籍信息【 SHEFLBOOK 】 var carbook = JSON.parse(window.localStorage.getItem('book') || '{}') if(!this.flag){ //加入书架 carbook[book._id] = { cover: book.cover, flag:!this.flag, title: book.title, lastChapter:book.lastChapter, id: book._id, author:book.author, chapterIndexCache: 0, bookSource: 0, pageIndexCache: 0, } this.setbook(false) window.localStorage.setItem('book', JSON.stringify(carbook)) }else{ delete carbook[book._id] this.setbook(true) //设置的布尔值 window.localStorage.setItem('book', JSON.stringify(carbook)) } } }立即阅读时进入小说章节 `this.$router.push({name:'read',params:{id:this.booklinks}})`目录组件components/sub/mulu.vue ...

May 13, 2019 · 2 min · jiezi

记录-关于axios封装

废话不多说,直接上代码,本人也是菜鸡 如果有什么不对请指教~ps: message为iview组件的插件 按需引入。 // 引入axiosimport axios from 'axios';import { Message } from 'iview'import store from './../store'import router from './../router'if (process.env.NODE_ENV == 'development') { axios.defaults.baseURL = '/api';} else if (process.env.NODE_ENV == 'debug') { axios.defaults.baseURL = '';} else if (process.env.NODE_ENV == 'production') { axios.defaults.baseURL = './';}axios.defaults.timeout = 60000; //设置请求时间// 响应拦截器axios.interceptors.response.use( response => { // 如果返回的状态码为0000,说明请求数据成功(注:0000是我和公司后台约定的状态码,具体的随机应变) // 否则的话抛出错误{ if(response.data.retCode != '0000'){ store.commit('common/defaultEntity', { retCode: response.data.retCode, retMsg: response.data.retMsg }) router.push({ path: '/error'}); } return Promise.resolve(response); }, error => { store.commit('common/defaultEntity', { retCode: error.response.status, retMsg: '请求不存在' }) router.push({ path: '/error'}); return Promise.reject(error.response); } );/** * 封装get方法 * @param url * @param data * @returns {Promise}*/export function fetch(url,params={}){ return new Promise((resolve,reject) => { axios.get(url,{ params:params }) .then(response => { resolve(response.data); }) .catch(err => { reject(err) }) }) }/** * 封装post请求 * @param url * @param data * @returns {Promise} */ export function post(url,data = {}){ return new Promise((resolve,reject) => { axios.post(url,data).then(response => { resolve(response.data); },err => { reject(err) }) }) }

April 25, 2019 · 1 min · jiezi

axios使用和源码阅读

axios.interceptorsaxios.interceptors拦截器主要用来作什么?和路由拦截有什么区别一个是接口的request, response数据处理一个是对业务处理,比如页面权限控制axios拦截import axios from ‘axios’import env from ‘@/env’import Utils from ‘@/components/Utils’import { Message} from ’element-ui’// 获取系统IDconst systemId = Utils.getQueryString(‘systemId’)if (systemId) { window.systemId = systemId} else { // 没有系统ID location.href = env.dataCloud}const auth = (response) => { // 未登录 if (response && ((response.status === 401) || (response.status === 412))) { location.href = env.dataCloud }}const instance = axios.create({ baseURL: ${env.api}${env.prefix.develop}, params: { systemId }, withCredentials: true})instance.nterceptors.response.use((response) => { auth(response) if (response && response.data && response.data.statusCode !== ‘0’) { Message.error((response.data && response.data.msg) || response.data.errmsg || ‘抱歉’) return Promise.reject(response).catch(() => { }) } return Promise.resolve(response.data)}, (error) => { let msg = ‘网络错误,请稍后再试’ if (error && error.response && error.response.status === 401) { msg = ‘请登录’ } const notice = document.getElementsByClassName(‘ivu-message-error’) if (notice.length === 0) { Message.error(msg) } auth(error && error.response) return Promise.reject(error).catch(() => { })})export default instance路由拦截login.jsmain.jsaxios/lib/core/Axios.jsaxios/lib/core/InterceptorManager.js拦截器上有request,response。分别用于拦截发送,接收。经典场景比如这样一个场景:在进行敏感操作(常见敏感操作如购买, 获取列表等)之前,每个请求需要携带token,但是token 有有效期,token 失效后需要换取新的token并继续请求。需求分析:每个请求都需要携带 token ,所以我们可以使用 axios request 拦截器,在这里,我们给每个请求都加 token,这样就可以节省每个请求再一次次的复制粘贴代码。token 失效问题,当我们token 失效,我们服务端会返回一个特定的错误表示,比如 token invalid,但是我们不能在每个请求之后去做刷新 token 的操作呀,所以这里我们就用 axios response 拦截器,我们统一处理所有请求成功之后响应过来的数据,然后对特殊数据进行处理,其他的正常分发。功能实现在 main.js 注册 axiosjsVue.use(Vuex)Vue.use(VueAxios, axios)Vue.use(qs)注:qs,使用axios,必须得安装 qs,所有的Post 请求,我们都需要 qs,对参数进行序列化。在 request 拦截器实现axios.interceptors.request.use( config => { config.baseURL = ‘/api/’ config.withCredentials = true // 允许携带token ,这个是解决跨域产生的相关问题 config.timeout = 6000 let token = sessionStorage.getItem(‘access_token’) let csrf = store.getters.csrf if (token) { config.headers = { ‘access-token’: token, ‘Content-Type’: ‘application/x-www-form-urlencoded’ } } if (config.url === ‘refresh’) { config.headers = { ‘refresh-token’: sessionStorage.getItem(‘refresh_token’), ‘Content-Type’: ‘application/x-www-form-urlencoded’ } } return config }, error => { return Promise.reject(error) })//在 response 拦截器实现axios.interceptors.response.use( response => { // 定时刷新access-token if (!response.data.value && response.data.data.message === ’token invalid’) { // 刷新token store.dispatch(‘refresh’).then(response => { sessionStorage.setItem(‘access_token’, response.data) }).catch(error => { throw new Error(’token刷新’ + error) }) } return response }, error => { return Promise.reject(error) })参考vue-axios interceptors(拦截器)实际应用一个项目学会前端实现登录拦截 ...

April 19, 2019 · 2 min · jiezi

Vue 使用 formData 方式向后台发送数据

基本使用方式template <input class=“file” name=“file” type=“file” accept=“image/png,image/gif,image/jpeg” @change=“update”/>JavaScriptupdate (e) { let file = e.target.files[0] // console.log(file) let param = new FormData() // 创建form对象 param.append(‘file’, file, file.name) // 通过append向form对象添加数据 param.append(‘id’, this.$store.state.userId) // 添加form表单中其他数据 // withCredentials: true 使得后台可以接收表单数据 跨域请求 const instance = axios.create({ withCredentials: true }) // url为后台接口 instance.post(‘url’, param) .then(this.succ) // 成功返回信息 调用函数 函数需自己定义,此处后面省略 .catch(this.serverError) // 服务器错误 调用对应函数 函数需自己定义,此处后面省略}2. 美化 input file 按钮 (拓展)思路:简单粗暴地隐藏:opacity: 0;在 <input class=“file”> 元素节点的位置上创建一个好看的元素节点,比如img将 <input class=“file”> 元素的z轴变高,使得其覆盖<img/> :z-index: 5;因为 <input class=“file”> 是透明的,那么我们就只看见它同xy上的好看的<img />点击这个好看的<img /> 其实是点击了它上层的表单以上思路可以实现点击用户头像,通过表单上传更换头像

April 13, 2019 · 1 min · jiezi

Vue技术分类

vue-cli1、vue-cli 工程常用的 npm 命令有哪些?$ npm install vue-cli //1$ vue init webpack vue-project //2$ cd vue-project //3$ npm install //4$ npm run dev 2、请说出vue-cli工程中每个文件夹和文件的用处3、config文件夹 下 index.js 的对于工程 开发环境 和 生产环境 的配置module.exports => dev => proxyTable 开发时请求代理module.exports => port 开发时使用端口module.exports => build => 规定打包后文件的结构以及名称4、详细介绍一些 package.json 里面的配置name: 项目名称,version: 版本号,description: 项目说明,author: 作者信息,dependencies: 开发环境和生产环境都需要的依赖包devDependencies: 生产环境的依赖包vue知识点1、对于Vue是一套渐进式框架的理解 Vue核心功能是一个视图模板引擎,但不是说Vue就不能成为一个框架。可以通过添加组件系统、客户端路由、大规模状态管理来构建一个完整的框架。这些功能相互独立,可以在核心功能的基础上任意选用其他的部件,不一定要全部整合在一起。这就是“渐进式”,就是Vue的使用方式。2、vue.js的两个核心是什么?数据驱动、组件系统。3、请问 v-if 和 v-show 有什么区别? v-if判断条件是否渲染,是惰性的,初始渲染时条件为假时什么也不做;v-show是 display: block/none;元素始终都会渲染;在项目中如果需要频繁的切换则使用v-show较好,运行条件很少改变,则使用v-if。4、vue常用的修饰符.prevent 提交事件不再重载页面;.stop 阻止单击事件冒泡;.self 当事件发生在该元素本身而不是子元素时触发;.capture 添加事件监听器时使用事件捕获模式;.once 只会触发一次 按键修饰符 :keyup.enter :keyup.tab5、v-on可以监听多个方法吗? 可以。6、vue中 key 值的作用v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,主要是为了高效的更新虚拟DOM。7、vue-cli工程升级vue版本手动修改 package.json 里面vue的版本,同时修改 vue-template-compiler 为相同的版本;后者在devDependencies里面,然后npm install。8、vue事件中如何使用event对象? @click=“EventName($event)“9、$nextTick的使用在修改数据之后立即使用这个方法,获取更新后的 DOM。10、Vue 组件中 data 为什么必须是函数每用一次组件,就会有一个新实例被创建。每个实例可以维护一份被返回对象的独立的拷贝,每个对象都是独立互不影响的。11、v-for 与 v-if 的优先级v-for 具有比 v-if 更高的优先级。v-if 将分别重复运行于每个 v-for 循环中。vue风格指南提示永远不要把 v-if 和 v-for 同时用在同一个元素上。12、vue中子组件调用父组件的方法第一种:this.$parent.xxx;第二种:通过props传递父组件函数名,子组件接受,接受类型为Function;第三种:创建eventBus。13、vue中 keep-alive 组件的作用keep-alive是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。include(包含的组件缓存) 与 exclude(排除的组件不缓存,优先级大于include) 。include - 字符串或正则表达式,只有名称匹配的组件会被缓存;exclude反之亦然。 include=“a,b” :include="/a|b/” :include=”[‘a’, ‘b’]“14、vue中如何编写可复用的组件?1.规范化命名:组件的命名应该跟业务无关,而是依据组件的功能命名。2.数据扁平化:定义组件接口时,尽量不要将整个对象作为一个 prop 传进来。每个 prop 应该是一个简单类型的数据。这样做有下列几点好处: (1) 组件接口清晰。加粗文字 (2) props 校验方便。 (3) 当服务端返回的对象中的 key 名称与组件接口不一样时,不需要重新构造一个对象。 扁平化的 props 能让我们更直观地理解组件的接口。3.可复用组件只实现 UI 相关的功能,即展示、交互、动画,如何获取数据跟它无关,因此不要在组件内部去获取数据。4.可复用组件应尽量减少对外部条件的依赖。5.组件在功能独立的前提下应该尽量简单,越简单的组件可复用性越强。6.组件应具有一定的容错性。15、什么是vue生命周期和生命周期钩子函数?Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程,称之为 Vue 的生命周期。总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后。让我们在控制整个Vue实例的过程时更容易形成好的逻辑。16、vue生命周期钩子函数有哪些?beforeCreate(创建前) 在数据观测和初始化事件还未开始created(创建后) 完成数据观测,属性和方法的运算,初始化事件,$el属性还没有显示出来; beforeMount(载入前) 在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上;mounted(载入后) 在el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互;beforeUpdate(更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程;updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用;beforeDestroy(销毁前) 在实例销毁之前调用。实例仍然完全可用;destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。17、vue如何监听键盘事件中的按键?监听keyup事件并添加按键修饰符,对一些常用按键vue提供了别名,或者使用keyCode,vue也支持复合按键。18、vue更新数组时触发视图更新的方法Vue.set(arr, key, value) Vue.set(object, key, value)19、vue中对象更改检测的注意事项Vue 不能检测对象属性的添加或删除;不能动态添加根级别的响应式属性。使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性。20、解决非工程化项目初始化页面闪动问题vue页面在加载的时候闪烁花括号{}},v-cloak指令和css规则如[v-cloak]{display:none}一起用时,这个指令可以隐藏未编译的Mustache标签直到实例准备完毕。/css样式/[v-clock] { display: none;}21、v-for产生的列表,实现active的切换<ul class=“ul” > <li v-on:click=“currentIndex = index” class=“item” v-bind:class="{clicked: index === currentIndex}” v-for="(items, index) in arr"> <a>{{items}}</a> </li></ul>data() { return{ currentIndex: 0 }}22、v-model语法糖的组件中的使用1:用于表单上数据的双向绑定;2:修饰符: .lazy- 取代input监听change事件 .number- 输入字符串转为数字 .trim- 输入首尾空格过滤 23、十个常用的自定义过滤器// 全局方法 Vue.filter() 注册一个自定义过滤器Vue.filter(“sum”, function(value) { return value + 4;});// 局部new Vue({ el: “.test”, data: { message:12 }, filters: { sum: function (value) { return value + 4; } }})24、vue等单页面应用及其优缺点优点——数据驱动、组件化、轻量简洁高效,通过尽可能简单的API实现响应的数据绑定和组合的视图组件;缺点:不支持低版本的浏览器,不利于SEO优化,可以使用服务器端渲染,首次加载耗时长。25、什么是vue的计算属性?在模板中放入太多的逻辑会让模板过重且难以维护,在需要对数据进行复杂处理,且可能多次使用的情况下,尽量采取计算属性的方式。计算属性基于它们的依赖进行缓存的;只在相关依赖发生改变时它们才会重新求值。31、计算属性的缓存和方法调用的区别两种方式的最终结果确实是完全相同的。不同的是计算属性是基于它们的依赖进行缓存的,只在相关依赖发生改变时它们才会重新求值。只要相关依赖还没有发生改变,多次访问计算属性会立即返回之前的计算结果,而不必再次执行函数如果不希望有缓存,请用方法来替代。 26、vue-cli提供的几种脚手架模板vue-cli的脚手架项目模板有webpack-simple 和 webpack;区别在于webpack-simple 没有包括Eslint 检查等功能。27、vue父组件如何向子组件中传递数据? 通过父组件v-bind传递数据子组件props接收数据28、vue-cli开发环境使用全局常量①少量Vue.prototype.baseUrl = function () { return ‘https://segmentfault.com/';};Vue.prototype.getTitle = { title:’’, isBack: true, isAdd: false,};②配置文件形式在项目的src 目录里面 新建一个 lib目录,lib目录里创建一个 config.js文件。export default { install(Vue,options) { Vue.prototype.baseUrl = function () { return ‘111’; }; Vue.prototype.getTitle = { title:’’, isBack: true, isAdd: false, }; Vue.prototype.showFootTab = { isShow:false, active:0, }}最后导入 import config from ‘./lib/config.js’; Vue.use(config);使用 <template> <div> {{getTitle.title}} </div> </template> this.getTitle29、vue-cli生产环境使用全局常量30、vue弹窗后如何禁止滚动条滚动? /滑动限制/ stop(){ var mo=function(e){e.preventDefault();}; document.body.style.overflow=‘hidden’; document.addEventListener(“touchmove”,mo,false);//禁止页面滑动 }, /取消滑动限制/ move(){ var mo=function(e){e.preventDefault();}; document.body.style.overflow=’’;//出现滚动条 document.removeEventListener(“touchmove”,mo,false); } // 如果不是Vue,可以直接给html设置overflow:hidden32、vue-cli中自定义指令的使用directives: { focus: { // 指令的定义 inserted: function (el) { el.focus() }![图片描述][1] }}Vue.directive(‘color-swatch’, function (el, binding) { el.style.backgroundColor = binding.value}) vue-router1、vue-router如何响应 路由参数 的变化?当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。同时意味着组件的生命周期钩子不会再被调用。复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化) $route 对象:watch: { ‘$route’ (to, from) { // 对路由变化作出响应… }}2、完整的 vue-router 导航解析流程导航被触发。在失活的组件里调用离开守卫。调用全局的 beforeEach 守卫。在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。在路由配置里调用 beforeEnter。解析异步路由组件。在被激活的组件里调用 beforeRouteEnter。调用全局的 beforeResolve 守卫 (2.5+)。导航被确认。调用全局的 afterEach 钩子。触发 DOM 更新。用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。3、vue-router有哪几种导航钩子( 导航守卫 )?全局的, 单个路由独享的, 组件级的。全局守卫:router.beforeEach router.beforeResolve(2.5+) router.afterEachconst router = new VueRouter({ … })router.beforeEach((to, from, next) => { // …})router.afterEach((to, from) => { // 这些钩子不会接受 next 函数也不会改变导航本身: …})路由独享的守卫: beforeEnter 这些守卫与全局前置守卫的方法参数是一样的。const router = new VueRouter({ routes: [ { path: ‘/foo’, component: Foo, beforeEnter: (to, from, next) => { // … } } ]})组件内的守卫beforeRouteEnterbeforeRouteUpdate (2.2 新增)beforeRouteLeaveconst Foo = { template: ..., beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 this // 因为当守卫执行前,组件实例还没被创建 next(vm => { // 通过 vm 访问组件实例 }) }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 this }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 this }}每个守卫方法接收三个参数:to: Route: 即将要进入的目标 路由对象from: Route: 当前导航正要离开的路由next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。4、vue-router的几种实例方法以及参数传递编程式导航 this.$router.push({ name: ’news’, params: { userId: 123 }}); // this.$route.params.userId this.$router.push({ path: ‘/news’, query: { userId: 123 }}); // this.$route.query.userId this.$router.replace();声明式导航 <router-link :to="{ name: ’news’, params: { userId: 1111}}">click to news page</router-link> <router-link :to="{ path: ‘/news’, query: { userId: 1111}}">click to news page</router-link>5、vue-router的动态路由匹配以及使用需要把某种模式匹配到的所有路由,全都映射到同个组件const User = { template: ‘<div>User{{ $route.params.id }}</div>’}const router = new VueRouter({ routes: [ // 动态路径参数 以冒号开头 { path: ‘/user/:id’, component: User } ]})复用组件时,想对路由参数的变化作出响应的话,使用watch (监测变化) $route 对象 watch: { ‘$route’ (to, from) { // 对路由变化作出响应… } }想匹配任意路径,我们可以使用通配符 (){ // 会匹配所有路径 path: ‘’}, { // 会匹配以 /user- 开头的任意路径 path: ‘/user-*’}6、vue-router如何定义嵌套路由?在router.js使用children数组来定义子路由,并在模板中使用<router-view>定义嵌套路由。如果没有匹配到合适的子路由,可以提供一个 空的 子路由 routes: [ { path: ‘/user/:id’, component: User, children: [ // 当 /user/:id 匹配成功, // UserHome 会被渲染在 User 的 <router-view> 中 { path: ‘’, component: UserHome }, // …其他子路由 ] } ]7、<router-link></router-link>组件及其属性<router-link> 组件支持用户在具有路由功能的应用中 (点击) 导航。 通过 to 属性指定目标地址,默认渲染成带有正确链接的 <a> 标签,可以通过配置 tag 属性生成别的标签。to: <!– 字符串 –> <router-link to=“home”>Home</router-link> <!– 渲染结果 –> <a href=“home”>Home</a> <!– 使用 v-bind 的 JS 表达式 –> <router-link v-bind:to="‘home’">Home</router-link> <!– 不写 v-bind 也可以,就像绑定别的属性一样 –> <router-link :to="‘home’">Home</router-link> <!– 同上 –> <router-link :to="{ path: ‘home’ }">Home</router-link> <!– 命名的路由 –> <router-link :to="{ name: ‘user’, params: { userId: 123 }}">User</router-link> <!– 带查询参数,下面的结果为 /register?plan=private –> <router-link :to="{ path: ‘register’, query: { plan: ‘private’ }}">Register</router-link>replace: 会调用 router.replace() 而不是 router.push(),于是导航后不会留下 history 记录。<router-link :to="{ path: ‘/abc’}" replace></router-link>append: 在当前 (相对) 路径前添加基路径tag: 渲染成某种标签active-class: 设置 链接激活时使用的 CSS 类名。默认值可以通过路由的构造选项 linkActiveClass 来全局配置。8、vue-router实现路由懒加载( 动态加载路由 )component: () => import(‘comp/AlbumlibMore’)9、vue-router路由的两种模式vue-router 默认 hash 模式 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。HTML5 History 模式 充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。 要玩好,还需要后台配置支持; 因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://oursite.com/user/id 就会返回 40410、history路由模式与后台的配合在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面;然后在给出一个 404 页面。vuex1、什么是vuex?专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。读取的状态集中放在store中; 改变状态的方式是提交mutations,这是个同步的事物; 异步逻辑应该封装在action中。在main.js引入store,注入。新建了一个目录store,export 。场景有:单页应用中,组件之间的状态、音乐播放、登录状态、加入购物车2、使用vuex的核心概念state => 基本数据 getters => 从基本数据派生的数据 mutations => 提交更改数据的方法,同步! actions => 像一个装饰器,包裹mutations,使之可以异步。 modules => 模块化Vuex(2019.03.26)3、vuex在vue-cli中的应用4、组件中使用 vuex 的值和修改值的地方?5、在vuex中使用异步修改6、pc端页面刷新时实现vuex缓存http请求1、Promise对象是什么?2、axios、fetch与ajax有什么区别?3、什么是JS的同源策略和跨域问题?4、如何解决跨域问题?5、vue-cli中如何使用JSON数据模拟?6、vue-cli中http请求的统一管理。7、axios有什么特点?UI样式1、.vue组件的scoped属性的作用2、如何让CSS只在当前组件中起作用?3、vue-cli中常用的UI组件库4、如何适配移动端?【 经典 】5、移动端常用媒体查询的使用6、垂直居中对齐7、vue-cli中如何使用背景图片?8、使用表单禁用时移动端样式问题9、多种类型文本超出隐藏问题常用功能1、vue中如何实现tab切换功能?2、vue中如何利用 keep-alive 标签实现某个组件缓存功能?3、vue中实现切换页面时为左滑出效果4、vue中父子组件如何相互调用方法?5、vue中央事件总线的使用混合开发1、vue如何调用 原生app 提供的方法?2、原生app 调用 vue 提供的方法,并将值传递到 .vue 组件中生产环境1、vue打包命令是什么?2、vue打包后会生成哪些文件?3、如何配置 vue 打包生成文件的路径?4、vue如何优化首屏加载速度?MVVM设计模式1、MVC、MVP与MVVM模式2、MVC、MVP与MVVM的区别3、常见的实现MVVM几种方式4、Object.defineProperty()方法5、实现一个自己的MVVM(原理剖析)6、 ES6中类和定义7、JS中的文档碎片8、解构赋值9、Array.from与Array.reduce10、递归的使用11、Obj.keys()与Obj.defineProperty12、发布-订阅模式13、实现MVVM的思路分析源码剖析1、vue内部与运行机制:Vue.js 全局运行机制响应式系统的基本原理什么是 Virtual DOM?如何编译template 模板?diff算法批量异步更新策略及 nextTick 原理?proxy代理?2、vuex工作原理详解Vue.mixinVue.use深入拓展1、vue开发命令 npm run dev 输入后的执行过程2、vue的服务器端渲染3、从零写一个npm安装包4、vue-cli中常用到的加载器5、webpack的特点 ...

March 26, 2019 · 4 min · jiezi

Vue项目部署(阿里云+Nginx代理+PM2)

最近部署一个Vue项目到阿里云ECS上,因为项目涉及一些跨域请求,所以采用了Nginx代理请求本地的node服务(利用pm2做进程管理)。node服务借助axios设置headers的referer、host转发请求,解决跨域请求问题。先交代下在阿里云ECS里安装的部署环境:phpstudy(php调试运行大礼包,里面包含nginx、mysql等,还能监控端口占用情况)、pm2(node服务进程管理工具)、node、git等等。部署过程拉去GitHub项目代码至root目录下(找到安装phpstudy的WWW目录),构建项目修改nginx-conf的代理配置、root项配置(指向项目项目的dist目录下)启动pm2(项目中,事先已写好服务端逻辑prod.server.js)启动phpstudy访问项目构建项目构建项目前,要修改项目confing目录下的index.js,主要是build部分的端口、目录,具体如下:build: { port: 9001, // 因为我是用PHPStudy做web服务器的,此时php.cgi会占9000端口,所以改用9001 // Template for index.html index: path.resolve(__dirname, ‘../dist/index.html’), // Paths assetsRoot: path.resolve(__dirname, ‘../dist’), assetsSubDirectory: ‘static’, assetsPublicPath: ‘’, …….}主要有两部分修改端口,跟代理端口一致port: 9001修改assetsPublicPathassetsPublicPath: ‘’nginx-conf配置利用phpstudy,可以很方便的进行nginx相关设置、host修改、端口监控等等。先来说说nginx-conf的配置。先找到nginx-conf配置入口修改ngin-confupstream my_project { server 127.0.0.1:9001; keepalive 64;}server { listen 80; server_name my_project; #charset koi8-r; #access_log logs/host.access.log main; root “C:/phpStudy/PHPTutorial/WWW/project/dist”; location / { index index.php index.html index.htm; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection “upgrade”; proxy_max_temp_file_size 0; proxy_pass http://my_project/; proxy_redirect off; proxy_read_timeout 240s; }}注意事项root配置,指向构建后目录 root “C:/phpStudy/PHPTutorial/WWW/project/dist”;设置代理端口时,避免端口占用!!upstream my_project { server 127.0.0.1:9001; keepalive 64;}开始部署时,使用的是9000端口,一直运行不起来,后面发现phpstudy启动是php-cgi.exe默认就使用了9000端口。关于端口使用情况,phpstudy也提供了工具。启动pm2关于pm2的介绍、常规使用自行了解。在项目目录下事先已经写好了转发请求的逻辑。pro.server.jsvar axios = require(‘axios’)const bodyParser = require(‘body-parser’)var config = require(’./config/index’)var express = require(’express’)var app = express()var apiRoutes = express.Router()apiRoutes.get(’/api/getdata’, function(req, res) { var url = ‘https://a.com’ axios.get(url, { headers: { referer: ‘https://b.com’, host: ‘b.com’ }, params: req.query }).then((response) => { …. }).catch((e) => { console.log(e) })})app.use(’/’, apiRoutes)app.use(express.static(’./dist’))var port = process.env.PORT || config.build.portmodule.exports = app.listen(port, function (err) { if (err) { console.log(err) return } console.log(‘Listening at http://localhost:’ + port + ‘\n’)})这里只是简单的借助axios可以设置referer和host,实现代理转发的功能。运行prod.server.jsprod.server.js是在根目录下,所以运行命令如下:pm2 start prod.server.js进程列表:pm2 start list查看进程详情pm2 show 0总结整个部署过程涉及比较多的知识点,nginx代理,node开发部署,端口管理等等。在端口占用这个点上卡了一段时间。不过目前只是实现构建部署、访问。但维护成本还是比较高,先得从GitHub拉取代码,本地构建。项目完成以后,研究下持续性集成流程。 ...

March 26, 2019 · 1 min · jiezi

vue-music QQ音乐获取Vkey方法

方法一###(有点问题)利用axios伪造,抓取的网页版qq音乐的接口,但这个接口有瑕疵…能获取到Vkey,但不是每一首歌曲都能正常播放…后来发现网页版音乐中每个歌曲的播放地址的域名不是都一样的,不能播放的歌曲有可能是这个接口不对…还没找到解决办法http://isure.stream.qqmusic.q…song.jsexport function createSong(musicData, songVkey) { return new Song({ id: musicData.songid, mid: musicData.songmid, singer: filterSinger(musicData.singer), name: musicData.songname, album: musicData.albumname, duration: musicData.interval, image: https://y.gtimg.cn/music/photo_new/T002R300x300M000${musicData.albummid}.jpg?max_age=2592000, url: http://isure.stream.qqmusic.qq.com/C400${musicData.songmid}.m4a?guid=9244517832&amp;vkey=${songVkey}&amp;uin=0&amp;fromtag=66 })}singer.jsexport function getSongVkey(songmid) { const url = ‘/api/getSongVkey’ const data = Object.assign({}, commonParams, { songmid: songmid, notice: 0, platform: ‘yqq.json’, needNewCode: 0, format: ‘json’, data: {“req_0”:{“module”:“vkey.GetVkeyServer”,“method”:“CgiGetVkey”,“param”:{“guid”:“9244517832”,“songmid”:[“001Qu4I30eVFYb”],“songtype”:[0],“uin”:“0”,“loginflag”:1,“platform”:“20”}},“comm”:{“uin”:0,“format”:“json”,“ct”:24,“cv”:0}} }) return axios.get(url, { params: data }).then((res) => { return Promise.resolve(res.data) })}webpack.dev.configapp.get(’/api/getSongVkey’, function (req, res) { var url = ‘https://u.y.qq.com/cgi-bin/musicu.fcg' axios.get(url, { headers: { referer: ‘https://u.y.qq.com/', host: ‘u.y.qq.com’ }, params: req.query }).then((response) => { res.json(response.data) }).catch((e) => { console.log(e) }) })singer-detail_normallizeSongs(list, callback) { let ret = [] let index = 1 list.forEach((item) => { let {musicData} = item // 得到music对象 if (musicData.songid && musicData.albummid) { getSongVkey(musicData.songmid).then((res) => { if (res.code === ERR_OK) { const sVkey = res.req_0.data.midurlinfo[0] const songVkey = sVkey.vkey const newSong = createSong(musicData, songVkey) console.log(newSong) ret.push(newSong) if (index === list.length) { callback && callback(ret) } index ++ } }) } }) } 方法二###(实测没有问题)这个是抓取的是h5版qq音乐的jsonp接口singer.jsexport function getSongVkey(songmid) { const url = ‘https://c.y.qq.com/base/fcgi-bin/fcg_music_express_mobile3.fcg' const data = Object.assign({}, { callback: ‘musicJsonCallback’, loginUin: 3051522991, format: ‘jsonp’, platform: ‘yqq’, needNewCode: 0, cid: 205361747, uin: 3051522991, guid: 5931742855, songmid: songmid, filename: C400${songmid}.m4a })song.jsexport function createSong(musicData, songVkey) { return new Song({ id: musicData.songid, mid: musicData.songmid, singer: filterSinger(musicData.singer), name: musicData.songname, album: musicData.albumname, duration: musicData.interval, image: https://y.gtimg.cn/music/photo_new/T002R300x300M000${musicData.albummid}.jpg?max_age=2592000, url: http://dl.stream.qqmusic.qq.com/C400${musicData.songmid}.m4a?fromtag=38&amp;guid=5931742855&amp;vkey=${songVkey} })}singer-detail_normallizeSongs(list) { let ret = [] list.forEach((item) => { let {musicData} = item // 得到music对象 getSongVkey(musicData.songmid).then((res) => { const songVkey = res.data.items[0].vkey if (musicData.songid && musicData.albummid) { ret.push(createSong(musicData, songVkey)) } }) }) console.log(ret) return ret } ...

March 25, 2019 · 2 min · jiezi

Vue技术点②

1:Vue实现数据双向绑定的原理?答:Object.defineProperty(),采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。<body> <div id=“app”> <input type=“text” id=“txt”> <p id=“show”></p></div></body><script type=“text/javascript”> var obj = {} Object.defineProperty(obj, ’txt’, { get: function () { return obj }, set: function (newValue) { document.getElementById(’txt’).value = newValue document.getElementById(‘show’).innerHTML = newValue } }) document.addEventListener(‘keyup’, function (e) { obj.txt = e.target.value })</script>2:Vue的路由实现:hash模式 和 history模式答:hash模式:在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取;特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.xxx.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。history模式:history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.xxx.com/items/id。后端如果缺少对 /items/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”3:vuex是什么?怎么使用?哪种功能场景使用它?答:专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。读取的状态集中放在store中; 改变状态的方式是提交mutations,这是个同步的事物; 异步逻辑应该封装在action中。在main.js引入store,注入。新建了一个目录store,….. export 。场景有:单页应用中,组件之间的状态、音乐播放、登录状态、加入购物车4:vue-router如何响应 路由参数 的变化?答:当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。同时意味着组件的生命周期钩子不会再被调用。复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化) $route 对象: watch: { ‘$route’ (to, from) { // 对路由变化作出响应… } }5:vue-router有哪几种导航钩子答:全局的, 单个路由独享的, 或者组件级的。全局守卫:router.beforeEach router.beforeResolve(2.5+) router.afterEachconst router = new VueRouter({ … })router.beforeEach((to, from, next) => { // …})router.afterEach((to, from) => { // 这些钩子不会接受 next 函数也不会改变导航本身: …})路由独享的守卫: beforeEnter 这些守卫与全局前置守卫的方法参数是一样的。const router = new VueRouter({ routes: [ { path: ‘/foo’, component: Foo, beforeEnter: (to, from, next) => { // … } } ]})组件内的守卫beforeRouteEnterbeforeRouteUpdate (2.2 新增)beforeRouteLeaveconst Foo = { template: ..., beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 this // 因为当守卫执行前,组件实例还没被创建 next(vm => { // 通过 vm 访问组件实例 }) }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 this }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 this }}每个守卫方法接收三个参数:to: Route: 即将要进入的目标 路由对象from: Route: 当前导航正要离开的路由next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。6:完整的 vue-router 导航解析流程答:导航被触发。在失活的组件里调用离开守卫。调用全局的 beforeEach 守卫。在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。在路由配置里调用 beforeEnter。解析异步路由组件。在被激活的组件里调用 beforeRouteEnter。调用全局的 beforeResolve 守卫 (2.5+)。导航被确认。调用全局的 afterEach 钩子。触发 DOM 更新。用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。 ...

March 25, 2019 · 2 min · jiezi

IE浏览器会缓存GET请求

起因 IE浏览器会缓存网页中的GET和XHR的内容,请求方式是get方式时,IE浏览器会进行识别。如果该get请求的url是第一次请求的话,会请求服务器,从数据库中获取数据;如果该get请求的url不是第一次请求的话,那么该url就不会请求服务器,IE浏览器会直接从缓存中拿到上次该url获取的数据。无论是什么插件的get方式请求,IE浏览器都会这样进行处理的,从而导致数据不同步。解决方案1. 在get请求的url中增加随机标识(推荐)在请求后拼接随机数或者时间戳,使两次请求的url不一致,浏览器就不会从缓存中读取数据2. 在axios中设置header,ajax可以用setRequestHeader方法(推荐)const api = axios.create({ // … headers: { ‘Cache-Control’: ’no-cache’ } // …})3. 修改浏览器配置 (只能暂时解决问题)Internet选项 >> 浏览历史记录 >> 设置 >> Internet 临时文件的选项改为‘每次访问网页时’4. 在服务端设置 header(“Cache-Control: no-cache, must-revalidate”)(看情况)5. 改为post接口(不推荐)

March 19, 2019 · 1 min · jiezi

七牛云上传及上传方法封装

分片及七牛云上传封装项目里面用到七牛云,有分片和简单上传在此做下简单的记录,分享下面是分片上传封装process.env.MAX_FILESIZE 是我写在config里面分片的大小 如1024102410 10MB分片项目是vue框架,请求是axios。上传的进度在onUploadProgress中获取/** * 封装upload方法 * @param url 上传路径 * @param json 包含file对象 * @returns {Promise} /export function upload(url,json) { return new Promise((resolve,reject) => { let size = parseInt(Number(json.file.size)/Number(process.env.MAX_FILESIZE) +1); let y = 0; let fun = function(){ let formData = new FormData(); let file = json.file.slice(yprocess.env.MAX_FILESIZE,(y+1)process.env.MAX_FILESIZE); formData.append(‘chunk’, y); formData.append(‘file_name’, json.file.name); formData.append(‘count’, size); formData.append(’type’, json.type); formData.append(‘file’, file); axios.post(url,formData,{ headers: { ‘Content-Type’: ‘multipart/form-data’ },timeout:10000000, onUploadProgress: progressEvent => { //progressEvent.loaded 为上传进度 }, }).then(response => { if(response.data.code === 200){ if(y+1<size){ y++; fun() }else{ y=0; resolve(response.data.data); } }else{ Vue.prototype.$message.error(response.data.msg) } }) .catch(err => { reject(err); let message = ‘请求失败!请检查网络’; if(err.response)message=err.response.data.message; Vue.prototype.$$msgbox({ title:‘错误!’, message:message, type:’error’, }) }) }; fun() } })} 下面是七牛云上传的封装/* * 封装upload方法 * @param json json中包含fail * @returns {Promise} */export function uploadQiniu(json) { return new Promise((resolve,reject) => {axios.get(‘获取七牛权限的后台接口地址,主要获取七牛token’,{ params:{ file_name:json.file.name } }).then(resData =>{ let putExtra = { fname: json.file.name, mimeType:json.mimeType || null }; let congif = {}; let observable = qiniu.upload(json.file,resData .data.data.new_name,resData .data.data.token,putExtra,congif); let observer = { next(res){ let progress = Number(res.total.percent.toFixed(0)); // 此处得到上传进度百分比 可加后续操作 }, error(err){ reject(err); let message = ‘请求失败!请检查网络’; if(err.response)message=err.response.data.message; Vue.prototype.$alert({ title:‘错误!’, message:message, type:’error’, }) }, complete(res){ res.url = res.key; res.name = json.file.name; resolve(res); } }; let subscription = observable.subscribe(observer) } ); })} ...

March 8, 2019 · 1 min · jiezi

VUE全家桶+ElementUi 项目踩坑总结

项目简介vue + axios + vue-router + vuex + ElementUI架构vuevue数据更新,视图不更新只有当实例被创建时 data 中存在的属性才是响应式的,Vue 不能检测对象属性的添加或删除; 可以使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性Vue.set(vm.userProfile, ‘age’, 27)this.$set(this.transportAddData.serviceOrderList[a].serviceOrderItems[i], ‘deletePoundIds’, [])vue 数据与方法 vue 对象更改检测注意事项Vue 不能检测以下变动的数组:当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue当你修改数组的长度时,例如:vm.items.length = newLengthvue 数组更新检测持续触发事件的优化持续触发某个事件可以用函数的节流和防抖来做性能优化//防抖function(){ … clearTimeout(timeoutId); timeoutId = setTimeout(function () { console.log(‘content’, content); player(content.msgTypeId, comId) }, 500); … }// 节流var canRun = true;document.getElementById(“throttle”).onscroll = function(){ if(!canRun){ // 判断是否已空闲,如果在执行中,则直接return return; } canRun = false; setTimeout(function(){ console.log(“函数节流”); canRun = true; }, 300);};javaScript的Throttling(节流)和Debouncing(防抖)nextTick在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。get() { this.$http.get(’/api/article’).then(function (res) { this.list = res.data.data.list // ref list 引用了ul元素,我想把第一个li颜色变为红色 document.querySelectorAll(’li’)[0].style.color = ‘red’ //这里会报错-,因为还没有 li this.$nextTick( ()=> { document.querySelectorAll(’li’)[0].style.color = ‘red’ }) })},Vue.nextTick 的原理和用途音频文件自动播放报错谷歌浏览器(Chrome 66)音频自动播放报错DOMException: play() failed because the user didn’t interact with the document first.解决方案:AudioContext// Chromerequest.get(’/baseConfig/messageAudio/play’, { params: { “comId”: Cookies.get(‘comId’), “msgTypeId”: id }, responseType: ‘arraybuffer’ // 这里需要设置xhr response的格式为arraybuffer }) .then(req => { … let context = new (window.AudioContext || window.webkitAudioContext)(); context.decodeAudioData(req.data, decode => play(context, decode)); function play (context, decodeBuffer) { sourceadio = context.createBufferSource(); sourceadio.buffer = decodeBuffer; sourceadio.connect(context.destination); // 从0s开始播放 sourceadio.start(0); } … })Chrome 66禁止声音自动播放之后 [AudioContext](https://developer.mozilla.org… [AudioContext.decodeAudioData()](https://developer.mozilla.org...vuex使用vuex修改state的方法和区别可以直接使用 this.$store.state.变量 = xxx;this.$store.dispatch(actionType, payload) 或者 this.$store.commit(commitType, payload)相同点:能够修改state里的变量,并且是响应式的(能触发视图更新) 不同点: 若将vue创建 store 的时候传入 strict: true, 开启严格模式,那么任何修改state的操作,只要不经过 mutation的函数,vue就会报如下错throw error : [vuex] Do not mutate vuex store state outside mutation handlers。使用commit提交到mutation修改state的优点:vuex能够记录每一次state的变化记录,保存状态快照,实现时间漫游/回滚之类的操作。dispatch 和 commit的区别在于: 使用dispatch是异步操作, commit是同步操作, 所以 一般情况下,推荐直接使用commit,即 this.$store.commit(commitType, payload),以防异步操作会带来的延迟问题。vuex strict vuex Mutation vuex actionsvuex到底是什么const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit(‘increment’) } }})==vuex中的state本质上是没有template的隐藏的vue组件。==vuex工作原理详解axios兼容问题Edge 41.16299.15.0 post请求会自动转为getmicrosoft-edge/platform/issues vue 使用axios 在EDGE浏览器上面post请求变成了get请求取消请求场景:每次请求在拦截器中添加token,后台判断token是否过期;当进入一个页面时触发多次请求,且正好token已经过期。这个时候需要第一次请求完成之后知道token已经过期则弹出提示、页面跳转到登录、停止之后的请求;否则会因为多次请求和axios响应拦截而多次弹框提示。解决方案 axios自带cancelToken 取消方法,然后在路由跳转后停止之前的请求// 请求拦截中 添加 cancelTokenaxios.interceptors.request.use(config => { config.cancelToken = store.source.token return config}, err => { return Promise.reject(err)}) // 路由跳转中进行判断router.beforeEach((to, from, next) => { const CancelToken = axios.CancelToken store.source.cancel && store.source.cancel() store.source = CancelToken.source() next()})//sort文件/state: { source: { token: null, cancel: null } }axios api 路由变化时使用axios取消所有请求 vue项目中 axios请求拦截器与取消pending请求功能存在问题: 如果 token过期提示弹框为二次确认弹框,再次确认之后才会进行页面跳转,那么在点击确认之前,页面中之前的请求还是会继续进行; 解决方案:给弹窗添加全局状态,根据状态判断是否需要弹出弹框预检请求CORS跨域 CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,==IE浏览器不能低于IE10。== 浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。简单请求请求方法是以下三种方法之一: HEAD GET POSTHTTP的头信息不超出以下几种字段:Accept Accept-Language Content-Language Last-Event-ID Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain简单请求不会触发 CORS 预检请求。非简单请求当请求满足下述任一条件时,即为非简单请求:使用了下面任一 HTTP 方法: PUT DELETE CONNECT OPTIONS TRACE PATCH人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。该集合为:AcceptAccept-LanguageContent-LanguageContent-Type (but note the additional requirements below)DPRDownlinkSave-DataViewport-WidthWidthContent-Type 的值不属于下列之一: application/x-www-form-urlencoded multipart/form-data text/plain请求中的XMLHttpRequestUpload 对象注册了任意多个事件监听器。请求中使用了ReadableStream对象。HTTP访问控制(CORS)预检请求非简单请求,会在正式通信之前,增加一次HTTP OPTIONS方法发起的查询请求,称为"预检"请求(preflight)。以获知服务器是否允许该实际请求。“预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。 ==该方法不会对服务器资源产生影响==优化方案Access-Control-Max-Age: <delta-seconds> //单位是秒。表示 preflight request (预检请求)的返回结果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息) 可以被缓存多久Vue Routerpush、replace的区别push会向history添加新的记录,replace只是替换掉原来的记录,不会添加新的记录;这就导致了用replace方法跳转的页面是无法回到之前的页面的;(类似window.history)vue Router 编程式的导航路由懒加载为了提升页面加载速度,实现按需加载,也就是当路由访问时才加载对应组件,我们可以结合vue的异步组件和webpack的代码分割功能来实现路由的懒加载。{ path: ‘/iov/login’, name: ‘登录’, component: resolve => require([’@/views/login/login’], resolve),},{ path:’/iov/organization’, name:‘组织管理’, component:() => import(’@/views/enterprise/organization’)}vue Router 路由懒加载 vue 异步组件 vue + vue-router 懒加载 import / resolve+requireelementUI表单弹窗中 elementform 清除验证残留提示给表单添加不同的 ref (REFNAME),如果有相同的ref 会导致残留验证提示清除失败 this.dialogTranspor = true //弹窗打开后 dom 没有生成,所有要用 this.$nextTick this.$nextTick(function () { this.$refs.REFNAME.resetFields(); })页码数无法正常显示场景:列表页在跳到详情或其他页面后再返回列表页,无法正常显示对应页数(页码数放在state中),但请求的数据时正常的; 解决方案:页码数、总页数必须要在同一个对象中,否则当前页码数不能正常显示data() { return { //完成查询条件 searchComplate: { “comId”: Cookies.get(‘comId’), “transportOrderCode”: null, “orderCode”: null, “customerId”: null, “abnormal”: 2, “startTime”: null, “endTime”: null, “pageNum”: 1, “pageSize”: 20, total: 0, currentRow: ‘’, dataArea: [’’, ‘’], activeName: ‘’, expands: [] }, }}动态多级表单验证<li v-for="(item,index) in transportAddData.serviceOrderList”> <template v-for="(subItem,subIndex) in item.serviceOrderItems"> <tr > <td> <el-form-item :prop="‘serviceOrderList.’+index+’.serviceOrderItems.’ + subIndex + ‘.addressName’" :rules="{required: true, message: ‘卸货地不能为空’, trigger: ‘blur’}"> <el-input v-model=“subItem.addressName” placeholder=“地址”></el-input> </el-form-item> </td> <td> <el-form-item :prop="‘serviceOrderList.’+index+’.serviceOrderItems.’ + subIndex + ‘.planTonnage’" :rules="[{required: true, message: ‘必填项’, trigger: ‘blur’},{pattern: /^((([1-9]+(\d+)?)(.\d+)?)|(0.\d+))$/, message: ‘必须为正数且不为0’}]"> <el-input v-model=“subItem.planTonnage” placeholder=“预卸吨数”></el-input> </el-form-item> </td> … </tr> </template></li> ...

March 7, 2019 · 3 min · jiezi

axios不会对url中的功能性字符进行编码

在请求中如果url包括特殊字符的话,可能会导致接口接收参数失败,所以前端一般会对特殊字符进行encode,方法有两种encodeURI()对整个url进行编码,会避开url中的功能性字符,例如,& ? [ ]编码前:http://10.10.67.67:8080/api/chain/basic/users?params=+[编码后:http://10.10.67.67:8080/api/chain/basic/users?params=%2b[encodeURIComponent()对某个参数进行编码,会编码所有特殊字符编码前:http://10.10.67.67:8080/api/chain/basic/users?params=+[编码后:http://10.10.67.67:8080/api/chain/basic/users?params=%2b%5B在axios中就会对get请求的整个url进行encodeURI,导致有些get方法不能传[],所以在请求拦截器中可以对get方法单独处理,避开axios的encodeURImyAxios.interceptors.request.use( config => { let url = config.url // get参数编码 if (config.method === ‘get’ && config.params) { url += ‘?’ let keys = Object.keys(config.params) for (let key of keys) { url += ${key}=${encodeURIComponent(config.params[key])}&amp; } url = url.substring(0, url.length - 1) config.params = {} } config.url = url return config },

March 4, 2019 · 1 min · jiezi

Ajax Fetch 和 Axios(持续更新中...)

Ajax Fetch 和 Axios(持续更新中…)知识点梳理AJAX 不是 JavaScript 的规范,它只是一个哥们“发明”的缩写:Asynchronous JavaScript and XML,意思就是用 JavaScript 执行异步网络请求。JavaScript 代码都是单线程执行的,由于这个“缺陷”,导致 JavaScript 的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现,回调函数不好看,不利于代码复用,而链式写法好处 逻辑统一、利于复用,所以出现 Primose Promise 有各种开源实现,在 ES6 中被统一规范,由浏览器直接支持。async await 是 Promise 语法糖,使异步的逻辑书写标准的同步函数Generator原生 XHRAjaxAJAX 不是 JavaScript 的规范,它只是一个哥们“发明”的缩写:Asynchronous JavaScript and XML,意思就是用 JavaScript 执行异步网络请求。属性描述onreadystatechange每当 readyState 属性改变时,就会调用该函数。readyState存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。0: 请求未初始化 1: 服务器连接已建立,open()方法已调用,但是 send()方法未调用 2: 请求已连接 send()方法已调用,HTTP 请求已发送到 Web 服务器。未接收到相应3: 请求处理中 4: 请求已完成,且响应已就绪status200: “OK"404: 未找到页面;(function() { var xmlhttp if (window.XMLHttpRequest) { // IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码 xmlhttp = new XMLHttpRequest() } else { // IE6, IE5 浏览器执行代码 xmlhttp = new ActiveXObject(‘Microsoft.XMLHTTP’) } xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { console.log(xmlhttp.responseText) } } xmlhttp.open(‘GET’, ‘http://www.runoob.com/try/ajax/ajax_info.txt', true) xmlhttp.send()})()Ajax 安全限制浏览器的同源策略导致的。默认情况下,JavaScript 在发送 AJAX 请求时,URL 的域名必须和当前页面完全一致跨域请求通过 Flash 插件发送 HTTP 请求,这种方式可以绕过浏览器的安全限制,但必须安装 Flash,并且跟 Flash 交互。不过 Flash 用起来麻烦,而且现在用得也越来越少了。通过在同源域名下架设一个代理服务器来转发,JavaScript 负责把请求发送到代理服务器JSONP 它有个限制,只能用 GET 请求,并且要求返回 JavaScript。这种方式跨域实际上是利用了浏览器允许跨域引用 JavaScript 资源CORS CORS 全称 Cross-Origin Resource Sharing,是 HTML5 规范定义的如何跨域访问资源。面这种跨域请求,称之为“简单请求”。简单请求包括 GET、HEAD 和 POST(POST 的 Content-Type 类型仅限 application/x-www-form-urlencoded、multipart/form-data 和 text/plain),并且不能出现任何自定义头(例如,X-Custom: 12345),通常能满足 90%的需求Promise在 JavaScript 的世界中,所有代码都是单线程执行的。由于这个“缺陷”,导致 JavaScript 的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现function callback() { console.log(‘Done’)}console.log(‘before setTimeout()’)setTimeout(callback, 1000) // 1秒钟后调用callback函数console.log(‘after setTimeout()’)链式写法的好处在于,先统一执行 AJAX 逻辑,不关心如何处理结果,然后,根据结果是成功还是失败,在将来的某个时候调用 success 函数或 fail 函数。古人云:“君子一诺千金”,这种“承诺将来会执行”的对象在 JavaScript 中称为 Promise 对象。使用 Promise 封装 ajax 简化异步处理// ajax函数将返回Promise对象:function ajax(method, url, data) { var request = new XMLHttpRequest() return new Promise(function(resolve, reject) { request.onreadystatechange = function() { if (request.readyState === 4) { if (request.status === 200) { resolve(request.responseText) } else { reject(request.status) } } } request.open(method, url) request.send(data) })}var p = ajax(‘GET’, ‘/api/categories’)p.then(function(text) { // 如果AJAX成功,获得响应内容}).catch(function(status) { // 如果AJAX失败,获得响应代码})Promise 使用方法;(function() { console.time(‘doIt’) const time1 = 300 step1(time1) .then(time2 => step2(time2)) .then(time3 => step3(time3)) .then(result => { console.log(result is ${result}) console.timeEnd(‘doIt’) })})()function takeLongTime(n) { return new Promise(resolve => { setTimeout(() => resolve(n + 200), n) })}function step1(n) { console.log(step1 with ${n}) return takeLongTime(n)}function step2(n) { console.log(step2 with ${n}) return takeLongTime(n)}function step3(n) { console.log(step3 with ${n}) return takeLongTime(n)}Promise.all()两个任务是可以并行执行的,用 Promise.all()实现var p1 = new Promise(function(resolve, reject) { setTimeout(resolve, 500, ‘P1’)})var p2 = new Promise(function(resolve, reject) { setTimeout(resolve, 6000, ‘P2’)})// 同时执行p1和p2,并在它们都完成后执行then:Promise.all([p1, p2]).then(function(results) { console.log(results) // 获得一个Array: [‘P1’, ‘P2’]})Promise.race()有些时候,多个异步任务是为了容错,只需要获得先返回的结果即可var p1 = new Promise(function(resolve, reject) { setTimeout(resolve, 3000, ‘P1’)})var p2 = new Promise(function(resolve, reject) { setTimeout(resolve, 6000, ‘P2’)})// 同时执行p1和p2,其中一个完成后执行then:Promise.race([p1, p2]).then(function(results) { console.log(results) // // ‘P1’})async awaitawaitawait 操作符用于等待一个 Promise 对象。它只能在异步函数 async function 中使用await 表达式会暂停当前 async function 的执行,等待 Promise 处理完成。若 Promise 正常处理(fulfilled),其回调的 resolve 函数参数作为 await 表达式的值,继续执行 async function。若 Promise 处理异常(rejected),await 表达式会把 Promise 的异常原因抛出。另外,如果 await 操作符后的表达式的值不是一个 Promise,则返回该值本身。// 如果一个 Promise 被传递给一个 await 操作符,await 将等待 Promise 正常处理完成并返回其处理结果。function resolveAfter2Seconds(x) { return new Promise(resolve => { setTimeout(() => { resolve(x) }, 2000) })}async function f1() { var x = await resolveAfter2Seconds(10) console.log(x) // 10}f1()// 如果 Promise 处理异常,则异常值被抛出。async function f3() { try { var z = await Promise.reject(30) } catch (e) { console.log(e) // 30 }}f3()asyncasync function 声明用于定义一个返回 AsyncFunction 对象的异步函数。异步函数是指通过事件循环异步执行的函数,它会通过一个隐式的 Promise 返回其结果。一个返回的 Promise 对象会以 async function 的返回值进行解析(resolved),或者以该函数抛出的异常进行回绝(rejected)。async 函数中可能会有 await 表达式,这会使 async 函数暂停执行,等待 Promise 的结果出来,然后恢复 async 函数的执行并返回解析值(resolved)。function resolveAfter2Seconds() { return new Promise(resolve => { setTimeout(() => { resolve(‘resolved’) }, 2000) })}async function asyncCall() { console.log(‘calling’) var result = await resolveAfter2Seconds() console.log(result) // expected output: ‘resolved’}asyncCall()GeneratorFetchFetch 是一个现代的概念, 等同于 XMLHttpRequest。它提供了许多与 XMLHttpRequest 相同的功能,但被设计成更具可扩展性和高效性。Fetch 是挂在在 window 下的Fetch 的核心在于对 HTTP 接口的抽象,包括 Request,Response,Headers,Body,以及用于初始化异步请求的 global fetch。Fetch 还利用到了请求的异步特性——它是基于 Promise 的。fetch(‘http://example.com/movies.json') .then(function(response) { return response.json() }) .then(function(myJson) { console.log(myJson) })postData(‘http://example.com/answer', { answer: 42 }) .then(data => console.log(data)) // JSON from response.json() call .catch(error => console.error(error))function postData(url, data) { // Default options are marked with * return fetch(url, { body: JSON.stringify(data), // must match ‘Content-Type’ header cache: ’no-cache’, // *default, no-cache, reload, force-cache, only-if-cached credentials: ‘same-origin’, // include, same-origin, *omit headers: { ‘user-agent’: ‘Mozilla/4.0 MDN Example’, ‘content-type’: ‘application/json’ }, method: ‘POST’, // *GET, POST, PUT, DELETE, etc. mode: ‘cors’, // no-cors, cors, *same-origin redirect: ‘follow’, // manual, *follow, error referrer: ’no-referrer’ // *client, no-referrer }).then(response => response.json()) // parses response to JSON}参考AJAXPromiseasync await 语法描述Fetch 语法描述 ...

February 21, 2019 · 3 min · jiezi

【收藏干货】axios配置大全

一、安装1、 利用npm安装npm install axios –save 2、 利用bower安装bower install axios –save 3、 直接利用cdn引入<script src=“https://unpkg.com/axios/dist/...;></script>二、例子1、 发送一个GET请求axios.get(’/user?ID=12345’)//通过给定的ID来发送请求 .then(function(response){ console.log(response); }) .catch(function(err){ console.log(err); });//以上请求也可以通过这种方式来发送axios.get(’/user’,{ params:{ ID:12345 }}).then(function(response){ console.log(response);}).catch(function(err){ console.log(err);});2、 发送一个POST请求axios.post(’/user’,{ firstName:‘Fred’, lastName:‘Flintstone’}).then(function(res){ console.log(res);}).catch(function(err){ console.log(err);});3、 一次性并发多个请求function getUserAccount(){ return axios.get(’/user/12345’);}function getUserPermissions(){ return axios.get(’/user/12345/permissions’);}axios.all([getUserAccount(),getUserPermissions()]) .then(axios.spread(function(acct,perms){ //当这两个请求都完成的时候会触发这个函数,两个参数分别代表返回的结果 }))三、axios的APIaxios可以通过配置(config)来发送请求1、 axios(config)//发送一个POST请求axios({ method:“POST”, url:’/user/12345’, data:{ firstName:“Fred”, lastName:“Flintstone” }});2、 axios(url[,config])发送一个GET请求(默认的请求方式) axios(’/user/12345’);(二)、 请求方式的别名,这里对所有已经支持的请求方式都提供了方便的别名axios.request(config);axios.get(url[,config]);axios.delete(url[,config]);axios.head(url[,config]);axios.post(url[,data[,config]]);axios.put(url[,data[,config]])axios.patch(url[,data[,config]])注意:当我们在使用别名方法的时候,url,method,data这几个参数不需要在配置中声明(三)、 并发请求(concurrency),即是帮助处理并发请求的辅助函数//iterable是一个可以迭代的参数如数组等axios.all(iterable)//callback要等到所有请求都完成才会执行axios.spread(callback)(四)、创建一个axios实例,并且可以自定义其配置1、 axios.create([config])var instance = axios.create({ baseURL:“https://some-domain.com/api/", timeout:1000, headers: {‘X-Custom-Header’:‘foobar’}});2、 实例的方法一下是实例方法,注意已经定义的配置将和利用create创建的实例的配置合并axios#request(config)axios#get(url[,config])axios#delete(url[,config])axios#head(url[,config])axios#post(url[,data[,config]])axios#put(url[,data[,config]])axios#patch(url[,data[,config]])四、请求的配置(request config)以下就是请求的配置选项,只有url选项是必须的,如果method选项未定义,那么它默认是以GET的方式发出请求{ //url是请求的服务器地址 url:’/user’, //method是请求资源的方式 method:‘get’//default //如果url不是绝对地址,那么baseURL将会加到url的前面 //当url是相对地址的时候,设置baseURL会非常的方便 baseURL:‘https://some-domain.com/api/', //transformRequest选项允许我们在请求发送到服务器之前对请求的数据做出一些改动 //该选项只适用于以下请求方式:put/post/patch //数组里面的最后一个函数必须返回一个字符串、-一个ArrayBuffer或者Stream transformRequest:[function(data){ //在这里根据自己的需求改变数据 return data; }], //transformResponse选项允许我们在数据传送到then/catch方法之前对数据进行改动 transformResponse:[function(data){ //在这里根据自己的需求改变数据 return data; }], //headers选项是需要被发送的自定义请求头信息 headers: {‘X-Requested-With’:‘XMLHttpRequest’}, //params选项是要随请求一起发送的请求参数—-一般链接在URL后面 //他的类型必须是一个纯对象或者是URLSearchParams对象 params: { ID:12345 }, //paramsSerializer是一个可选的函数,起作用是让参数(params)序列化 //例如(https://www.npmjs.com/package/qs,http://api.jquery.com/jquery.param) paramsSerializer: function(params){ return Qs.stringify(params,{arrayFormat:‘brackets’}) }, //data选项是作为一个请求体而需要被发送的数据 //该选项只适用于方法:put/post/patch //当没有设置transformRequest选项时dada必须是以下几种类型之一 //string/plain/object/ArrayBuffer/ArrayBufferView/URLSearchParams //仅仅浏览器:FormData/File/Bold //仅node:Stream data { firstName:“Fred” }, //timeout选项定义了请求发出的延迟毫秒数 //如果请求花费的时间超过延迟的时间,那么请求会被终止 timeout:1000, //withCredentails选项表明了是否是跨域请求 withCredentials:false,//default //adapter适配器选项允许自定义处理请求,这会使得测试变得方便 //返回一个promise,并提供验证返回 adapter: function(config){ /………./ }, //auth表明HTTP基础的认证应该被使用,并提供证书 //这会设置一个authorization头(header),并覆盖你在header设置的Authorization头信息 auth: { username:“zhangsan”, password: “s00sdkf” }, //返回数据的格式 //其可选项是arraybuffer,blob,document,json,text,stream responseType:‘json’,//default // xsrfCookieName: ‘XSRF-TOKEN’,//default xsrfHeaderName:‘X-XSRF-TOKEN’,//default //onUploadProgress上传进度事件 onUploadProgress:function(progressEvent){ //下载进度的事件onDownloadProgress:function(progressEvent){} }, //相应内容的最大值 maxContentLength:2000, //validateStatus定义了是否根据http相应状态码,来resolve或者reject promise //如果validateStatus返回true(或者设置为null或者undefined),那么promise的状态将会是resolved,否则其状态就是rejected validateStatus:function(status){ return status >= 200 && status <300;//default }, //maxRedirects定义了在nodejs中重定向的最大数量 maxRedirects: 5,//default //httpAgent/httpsAgent定义了当发送http/https请求要用到的自定义代理 //keeyAlive在选项中没有被默认激活 httpAgent: new http.Agent({keeyAlive:true}), httpsAgent: new https.Agent({keeyAlive:true}), //proxy定义了主机名字和端口号, //auth表明http基本认证应该与proxy代理链接,并提供证书 //这将会设置一个Proxy-Authorization header,并且会覆盖掉已经存在的Proxy-Authorization header proxy: { host:‘127.0.0.1’, port: 9000, auth: { username:‘skda’, password:‘radsd’ } }, //cancelToken定义了一个用于取消请求的cancel token //详见cancelation部分 cancelToken: new cancelToken(function(cancel){ })}五、请求返回的内容{ data:{}, status:200, //从服务器返回的http状态文本 statusText:‘OK’, //响应头信息 headers: {}, //config是在请求的时候的一些配置信息 config: {}}你可以这样来获取响应信息axios.get(’/user/12345’) .then(function(res){ console.log(res.data); console.log(res.status); console.log(res.statusText); console.log(res.headers); console.log(res.config); })六、默认配置你可以设置默认配置,对所有请求都有效1、 全局默认配置axios.defaults.baseURL = ‘http://api.exmple.com’;axios.defaults.headers.common[‘Authorization’] = AUTH_TOKEN;axios.defaults.headers.post[‘content-Type’] = ‘appliction/x-www-form-urlencoded’;2、 自定义的实例默认设置//当创建实例的时候配置默认配置var instance = axios.create({ baseURL: ‘https://api.example.com’});//当实例创建时候修改配置instance.defaults.headers.common[“Authorization”] = AUTH_TOKEN;3、 配置中的有优先级config配置将会以优先级别来合并,顺序是lib/defauts.js中的默认配置,然后是实例中的默认配置,最后是请求中的config参数的配置,越往后等级越高,后面的会覆盖前面的例子。//创建一个实例的时候会使用libray目录中的默认配置//在这里timeout配置的值为0,来自于libray的默认值var instance = axios.create();//回覆盖掉library的默认值//现在所有的请求都要等2.5S之后才会发出instance.defaults.timeout = 2500;//这里的timeout回覆盖之前的2.5S变成5sinstance.get(’/longRequest’,{ timeout: 5000});七、拦截器你可以在请求、响应在到达then/catch之前拦截他们//添加一个请求拦截器axios.interceptors.request.use(function(config){ //在请求发出之前进行一些操作 return config;},function(err){ //Do something with request error return Promise.reject(error);});//添加一个响应拦截器axios.interceptors.response.use(function(res){ //在这里对返回的数据进行处理 return res;},function(err){ //Do something with response error return Promise.reject(error);})2、取消拦截器var myInterceptor = axios.interceptor.request.use(function(){/…./});axios.interceptors.request.eject(myInterceptor);3、 给自定义的axios实例添加拦截器var instance = axios.create();instance.interceptors.request.use(function(){})八、错误处理axios.get(’/user/12345’) .catch(function(error){ if(error.response){ //请求已经发出,但是服务器响应返回的状态吗不在2xx的范围内 console.log(error.response.data); console.log(error.response.status); console.log(error.response.header); }else { //一些错误是在设置请求的时候触发 console.log(‘Error’,error.message); } console.log(error.config); });九、取消你可以通过一个cancel token来取消一个请求 你可以通过CancelToken.source工厂函数来创建一个canceltokenvar CancelToken = axios.CancelToken;var source = CancelToken.source();axios.get(’/user/12345’,{ cancelToken: source.token}).catch(function(thrown){ if(axios.isCancel(thrown)){ console.log(‘Request canceled’,thrown.message); }else { //handle error }});//取消请求(信息的参数可以设置的)source.cance(“操作被用户取消”);你可以给cancelToken构造函数传递一个executor function来创建一个cancel token:var cancelToken = axios.CancelToken;var cance;axios.get(’/user/12345’,{ cancelToken: new CancelToken(function(c){ //这个executor函数接受一个cancel function作为参数 cancel = c; })})//取消请求cancel(); ...

February 19, 2019 · 2 min · jiezi

webpack4+react+antd+axios+router4+redux 学习以及脚手架搭建_014

webpack4 学习脚手架搭建安装和初始化首先附上官方的文档github地址https://github.com/xiaopingzh…会不定时更新,如果觉得有帮助到你,给个Star当做鼓励可好。.├── README.md├── build│ ├── webpack.dev.conf.js│ ├── webpack.dll.conf.js│ └── webpack.prod.conf.js├── dist├── dll├── manifest.json├── package-lock.json├── package.json├── public│ ├── favicon.ico│ └── index.html├── src│ ├── components│ │ ├── Bread│ │ │ └── Bread.js│ │ └── SiderBar│ │ └── SiderBar.js│ ├── index.js│ ├── layouts│ │ └── BasicLayout.js│ ├── pages│ │ ├── Counter│ │ │ └── Counter.js│ │ └── Home│ │ └── Home.js│ ├── redux│ │ ├── actions│ │ │ └── counter.js│ │ ├── reducer.js│ │ ├── reducers│ │ │ └── counter.js│ │ └── store.js│ ├── request│ │ └── request.js│ ├── router│ │ └── Router.js│ └── util│ └── loadable.js└── yarn.lock新创建一个目录并初始化npm,在本地安装webpack,再安装webpack-cli>npm initThis utility will walk you through creating a package.json file.It only covers the most common items, and tries to guess sensible defaults.See npm help json for definitive documentation on these fieldsand exactly what they do.Use npm install &lt;pkg&gt; afterwards to install a package andsave it as a dependency in the package.json file.Press ^C at any time to quit.package name: (webpack4)version: (1.0.0)description:entry point: (index.js)test command:git repository:keywords:author:license: (ISC)About to write to /Users/xiaopingzhang/UCloud/webpack4/package.json:{ “name”: “webpack4”, “version”: “1.0.0”, “description”: “”, “main”: “index.js”, “scripts”: { “test”: “echo "Error: no test specified" && exit 1” }, “author”: “”, “license”: “ISC”}Is this OK? (yes) yes初始化之后按照提示一步步往下就可以了,可以输入该项目的描述等等信息。一开始也没有关系,后面也还可以更改。下一步 本地安装webpack,再安装webpack-clinpm install webpack webpack-cli –save-dev==–save-dev 是你开发时候依赖的东西,–save 是你发布之后还依赖的东西。==>npm install webpack webpack-cli –save-dev> fsevents@1.2.7 install /Users/xiaopingzhang/UCloud/webpack4/node_modules/fsevents> node installnode-pre-gyp WARN Using needle for node-pre-gyp https download[fsevents] Success: “/Users/xiaopingzhang/UCloud/webpack4/node_modules/fsevents/lib/binding/Release/node-v57-darwin-x64/fse.node” is installed via remote> webpack-cli@3.2.1 postinstall /Users/xiaopingzhang/UCloud/webpack4/node_modules/webpack-cli> lightercollective *** Thank you for using webpack-cli! ***Please consider donating to our open collective to help us maintain this package. https://opencollective.com/webpack/donate ***npm WARN webpack4@1.0.0 No descriptionnpm WARN webpack4@1.0.0 No repository field.+ webpack-cli@3.2.1+ webpack@4.29.0added 458 packages from 239 contributors and audited 5208 packages in 18.624sfound 0 vulnerabilities安装好之后,也会显示安装的哪个版本,一般安装没有啥问题。实在安装不成功,试一下全局安装。2.新建src文件夹,入口的js文件和html文件。.├── index.html├── package.json└── src └── index.jsindex.js文件const component = () => { let element = document.createElement(“div”); element.innerHTML = “webpackworks”; return element;};document.body.appendChild(component());index.html<!DOCTYPE html><html> <head> <title>Start</title> </head> <body> <script src="./dist/main.js"></script> </body></html>3.学会使用webpack编译文件输入 npx webpack>npx webpackHash: 9ad2a368debc9967c1f4Version: webpack 4.29.0Time: 269msBuilt at: 2019-01-27 21:15:22 Asset Size Chunks Chunk Namesmain.js 1.01 KiB 0 [emitted] mainEntrypoint main = main.js[0] ./src/index.js 218 bytes {0} [built]WARNING in configurationThe ‘mode’ option has not been set, webpack will fallback to ‘production’ for this value. Set ‘mode’ option to ‘development’ or ‘production’ to enable defaults for each environment.You can also set it to ’none’ to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/再用浏览器打开index.html,查看网页是否正常的显示了。webpack 把入口文件 index.js 经过处理之后,生成 main.js配置文件经过第一部分的尝试,已经初步了解webpack的作用,这一部分通过配置文件进行相应的一些设置。babelBabel 把用最新标准编写的 JavaScript 代码向下编译成可以在今天随处可用的版本。 这一过程叫做“源码到源码”编译, 也被称为转换编译。npm install –save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0新建babel配置文件.babelrc{ “presets”: [ “es2015”, “react”, “stage-0” ], “plugins”: []}//babel-core 调用Babel的API进行转码//babel-loader//babel-preset-es2015 用于解析 ES6//babel-preset-react 用于解析 JSX//babel-preset-stage-0 用于解析 ES7 提案新建配置文件webpack.base.conf.jswebpack.dev.conf.jswebpack.prod.conf.js分别是公共配置,开发配置,生产配置。目前目录结构为.├── build│ ├── webpack.base.conf.js│ ├── webpack.dev.conf.js│ └── webpack.prod.conf.js├── dist│ └── main.js├── index.html├── package.json└── src └── index.js加载js/jsx文件npm install –save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-0在 src 目录下新建.babelrc{ “presets”: [ [ “env”, { “targets”: { “browsers”: [">1%", “last 3 versions”] } } ], “stage-2”, “latest”, “react” ], “plugins”: [ “syntax-dynamic-import”, “transform-class-properties”, <!–[–> <!– “import”,–> <!– {–> <!– “libraryName”: “antd”,–> <!– “libraryDirectory”: “es”,–> <!– “style”: true–> // “style”: “css” //主题设置 <!– }–> <!–]–> 不用antd 可以去掉 ]}文件新增 { test: /.(js|jsx)$/, exclude: /(node_modules|bower_components)/, //排除 include: [ path.resolve(__dirname, ‘../src’) ], //包括 use: { loader: ‘babel-loader’ } },加载CSS文件npm install –save-dev style-loader css-loader在配置文件里添加 { test: /.css$/, use: [“style-loader”, “css-loader”] }加载图片npm install –save-dev url-loader file-loader在配置文件里添加 { test: /.(png|jpg|gif)$/, use: [ { loader: “url-loader”, options: { limit: 8192 } } ] }options limit:8192意思是,小于等于8K的图片会被转成base64编码,直接插入HTML中,减少HTTP请求。加载less在这个踩了一个坑,记得安装 lessnpm install –save-dev less-loader less更改antd 默认主题设置需要,不用的话应该把相应的设置忽略即可。 { test: /.less$/, use: [ { loader: ‘style-loader’ }, { loader: ‘css-loader’ // translates CSS into CommonJS }, { loader: ’less-loader’, // compiles Less to CSS options: { modifyVars: { ‘font-size-base’: ‘12px’, ‘primary-color’: ‘#0EA679’ }, javascriptEnabled: true } } ] }加载字体那么,像字体这样的其他资源如何处理呢?file-loader 和 url-loader 可以接收并加载任何文件,然后将其输出到构建目录。这就是说,我们可以将它们用于任何类型的文件,包括字体。更新 webpack.config.js 来处理字体文件: { test: /.(woff|woff2|eot|ttf|otf)$/, use: [“file-loader”] }增加HtmlWebpackPluginHtmlWebpackPlugin作用是生成一个HTML模板。HtmlWebpackPlugin简化了HTML文件的创建,以便为你的webpack包提供服务。这对于在文件名中包含每次会随着编译而发生变化哈希的 webpack bundle 尤其有用。你可以让插件为你生成一个HTML文件,使用lodash模板提供你自己的模板,或使用你自己的loader首先需要安装插件:npm install –save-dev html-webpack-plugin在生产配置文件里添加 plugins: [ new HtmlWebpackPlugin({ template: ‘public/index.html’, title: ’title’, // 更改HTML的title的内容 favicon: ‘public/favicon.ico’, minify: { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true, }, }),清理 /dist 文件夹在每次构建前清理 /dist 文件夹.npm install clean-webpack-plugin –save-devnew CleanWebpackPlugin([’../dist’])模块热替换https://webpack.docschina.org…模块热替换(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新各种模块,而无需进行完全刷新。有两种方式一更改package.json"dev": “webpack –config build/webpack.dev.config.js –color –progress –hot"更改index.jsimport React from ‘react’;import ReactDom from ‘react-dom’;if (module.hot) { module.hot.accept();}//增加二更改配置文件const webpack = require(‘webpack’);devServer: { hot: true}plugins:[ new webpack.HotModuleReplacementPlugin()]reduxhttps://www.redux.org.cn/官方文档先给上,一开始学的时候也以为这个比较难,开始写就不会了。网上看看例子,自己在coding一下就差不多了。这边用到了一个中间件 redux-thunknpm install –save redux-thunk附上写的代码store注释的部分为生产环境使用。为了方便debug代码,在控制台打印readux日志。// import { createStore, applyMiddleware } from ‘redux’;// import thunk from ‘redux-thunk’;// import rootReducer from ‘./reducer’;// const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);// const store = createStoreWithMiddleware(rootReducer);// export default store;// 打印操作日志,方便调试,生产环境可以去掉,用上面注释的配置。import thunk from “redux-thunk”; // redux 作者开发的异步处理方案 可以在action 里传入 dispatch getStateimport { createLogger } from “redux-logger”; // 利用redux-logger打印日志import { createStore, applyMiddleware } from “redux”; // 引入redux createStore、中间件及composeimport { composeWithDevTools } from “redux-devtools-extension”; // devToolsEnhancer,import reducer from “./reducer”; // 引入reducers集合// 调用日志打印方法 collapsed是让action折叠,看着舒服点const loggerMiddleware = createLogger({ collapsed: true });// 创建一个中间件集合const middleware = [thunk, loggerMiddleware];// 创建storeconst store = createStore( reducer, composeWithDevTools(applyMiddleware(…middleware)));export default store;actionexport const INCREMENT = ‘counter/INCREMENT’;export const DECREMENT = ‘counter/DECREMENT’;export const RESET = ‘counter/RESET’;export function increment() { return { type: INCREMENT };}export function decrement() { return { type: DECREMENT };}export function reset() { return { type: RESET };}reducer每个页面的reduce文件import { INCREMENT, DECREMENT, RESET } from ‘../actions/counter’;const initState = { count: 0,};export default function reducer(state = initState, action) { switch (action.type) { case INCREMENT: return { count: state.count + 1, }; case DECREMENT: return { count: state.count - 1, }; case RESET: return { count: 0 }; default: return state; }}redecers 整合所有文件的reducerimport { combineReducers } from “redux”;import counter from “./reducers/counter”;export default combineReducers({ counter});react-loadablehttps://github.com/jamiebuild…官方文档先附上// 加载页面import Loadable from ‘react-loadable’;import React, { Component } from ‘react’;import { Spin, Icon } from ‘antd’;const antIcon = <Icon type=“loading” style={{ fontSize: 24 }} spin />;const antLong = ( <Icon type=“loading” style={{ fontSize: 24, color: ‘red’ }} spin />);const antError = ( <Icon type=“loading” style={{ fontSize: 24, color: ‘red’ }} spin />);export const Loading = props => { if (props.error) { return ( <Spin size=“large” tip=“加载错误 。。。” indicator={antError} style={{ position: ‘absolute’, color: ‘red’, top: ‘40%’, left: ‘50%’ }} /> ); } else if (props.timedOut) { return ( <Spin size=“large” tip=“加载超时 。。。” indicator={antLong} style={{ position: ‘absolute’, color: ‘red’, top: ‘40%’, left: ‘50%’ }} /> ); } else if (props.pastDelay) { return ( <Spin size=“large” tip=“Loading 。。。” indicator={antError} style={{ position: ‘absolute’, color: ‘red’, top: ‘40%’, left: ‘50%’ }} /> ); } else { return null; }};export const importPath = ({ loader }) => { return Loadable({ loader, loading: Loading, delay: 200, timeout: 10000 });};axios 统一拦截所有的请求和返回数据在需要用到的地方引入这个文件就ok了。只是简单的写了一个例子,后续再完善吧。axios使用起来很简洁。import axios from “axios”;import { message } from “antd”;import NProgress from “nprogress”;import “nprogress/nprogress.css”;// 拦截所有有请求与回复// Add a request interceptoraxios.interceptors.request.use( config => { NProgress.start(); return config; }, error => { message.error(“请求错误,请重试”); return Promise.reject(error); });// Add a response interceptoraxios.interceptors.response.use( response => { // NProgress.done(); // if (response.data.RetCode === 101) { // message.error(response.data.Message); // return response; // } // if (response.data.RetCode === 100) { // message.error(response.data.Message); // return response; // } return response; }, error => { message.error(“请求错误,请重试”); NProgress.done(); return Promise.reject(error); });export default request;公共路径(public path)插件配置 plugins: [ // 处理html new HtmlWebpackPlugin({ template: ‘public/index.html’, path: ‘../public/index.html’, inject: ‘body’, title: ‘管理平台’, favicon: ‘public/favicon.ico’, filename: ‘index.html’, hash: true, minify: { html5: true, removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true } }), new CleanWebpackPlugin([’../dist’], { allowExternal: true }), new BundleAnalyzerPlugin(), new MiniCssExtractPlugin({ chunkFilename: ‘[chunkhash].css’ }), new webpack.HashedModuleIdsPlugin(), new webpack.DllReferencePlugin({ context: __dirname, manifest: require(’../dll/manifest.json’) }), new CopyWebpackPlugin([ { from: ‘dll/Dll.js’, to: DIST_PATH } ]) ]html-webpack-pluginconst HtmlWebpackPlugin = require(‘html-webpack-plugin’);new HtmlWebpackPlugin({ template: ‘public/index.html’, path: ‘../public/index.html’, inject: ‘body’, title: ‘管理平台’, favicon: ‘public/favicon.ico’, filename: ‘index.html’, hash: true, minify: { html5: true, removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true } }),copy-webpack-pluginconst CopyWebpackPlugin = require(‘copy-webpack-plugin’);new CopyWebpackPlugin([ { from: ‘dll/Dll.js’, to: DIST_PATH } ])clean-webpack-pluginconst CleanWebpackPlugin = require(‘clean-webpack-plugin’);new CleanWebpackPlugin([’../dist’], { allowExternal: true })webpack-bundle-analyzerconst BundleAnalyzerPlugin = require(‘webpack-bundle-analyzer’) .BundleAnalyzerPlugin; new BundleAnalyzerPlugin(), mini-css-extract-pluginconst MiniCssExtractPlugin = require(‘mini-css-extract-plugin’); new MiniCssExtractPlugin({ chunkFilename: ‘[chunkhash].css’ }) 附上三个配置文件webpack.dev.conf.jsconst path = require(‘path’);const webpack = require(‘webpack’);const HtmlWebpackPlugin = require(‘html-webpack-plugin’);const CopyWebpackPlugin = require(‘copy-webpack-plugin’);const DIST_PATH = path.resolve(__dirname, ‘../dist’); //生产目录const APP_PATH = path.resolve(__dirname, ‘../src’); //源文件目录module.exports = { mode: ‘development’, entry: { index: ‘./src/index.js’ }, output: { path: DIST_PATH, //出口路径 filename: ‘index.js’, chunkFilename: ‘js/[name].[chunkhash].js’, //按需加载名称 // publicPath: “./” }, // 源错误检查 devtool: ‘inline-source-map’, //模块配置 module: { rules: [ { test: /.(js|jsx)$/, exclude: /(node_modules|bower_components)/, //排除 include: [ path.resolve(__dirname, ‘../src’), path.resolve(__dirname, ‘../node_modules/antd/’) ], //包括 use: { loader: ‘babel-loader’ } }, { test: /.css$/, use: [‘style-loader’, ‘css-loader’] }, { test: /.(png|jpg|gif)$/, use: [ { loader: ‘url-loader’, options: { limit: 8192 } } ] }, { test: /.(woff|woff2|eot|ttf|otf)$/, use: [‘file-loader’] }, //更改antd主题设置 { test: /.less$/, use: [ { loader: ‘style-loader’ }, { loader: ‘css-loader’ // translates CSS into CommonJS }, { loader: ’less-loader’, // compiles Less to CSS options: { modifyVars: { ‘font-size-base’: ‘12px’, ‘primary-color’: ‘#0EA679’ }, javascriptEnabled: true } } ] } ] }, //插件 plugins: [ new HtmlWebpackPlugin({ template: ‘public/index.html’, path: ‘../public/index.html’, inject: ‘body’, favicon: ‘public/favicon.ico’, title: ‘管理平台’, overlay: true, minify: { html5: false }, hash: true }), // 热更新 new webpack.HotModuleReplacementPlugin(), new webpack.HashedModuleIdsPlugin(), new webpack.DllReferencePlugin({ context: __dirname, manifest: require(’../dll/manifest.json’) }), new CopyWebpackPlugin([ { from: ‘dll/Dll.js’, to: DIST_PATH } ]) ], // 热更新 devServer: { port: ‘3300’, contentBase: DIST_PATH, historyApiFallback: true, hot: true, // 开启 https: false, compress: false, noInfo: true, open: true, proxy: { // ‘/’: { // target: ‘’, // changeOrigin: true, // secure: false, // }, } }};webpack.dll.conf.jsconst path = require(‘path’);const webpack = require(‘webpack’);const CleanWebpackPlugin = require(‘clean-webpack-plugin’);const vendors = [ ‘antd’, ‘axios’, ’nprogress’, ‘react’, ‘react-dom’, ‘react-loadable’, ‘react-redux’, ‘react-router’, ‘react-router-dom’, ‘redux’];module.exports = { entry: { vendor: vendors }, output: { path: path.resolve(__dirname, ‘../dll’), filename: ‘Dll.js’, library: ‘[name][hash]’ }, plugins: [ new webpack.DllPlugin({ path: path.resolve(__dirname, ‘../dll’, ‘manifest.json’), name: ‘[name][hash]’, context: __dirname }), new CleanWebpackPlugin([’../dll’], { allowExternal: true }) ]};webpack.prod.conf.jsconst path = require(‘path’);const webpack = require(‘webpack’);const CopyWebpackPlugin = require(‘copy-webpack-plugin’);const CleanWebpackPlugin = require(‘clean-webpack-plugin’);const HtmlWebpackPlugin = require(‘html-webpack-plugin’);const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’);const BundleAnalyzerPlugin = require(‘webpack-bundle-analyzer’) .BundleAnalyzerPlugin;const DIST_PATH = path.resolve(__dirname, ‘../dist’); //生产目录module.exports = { mode: ‘production’, entry: { index: ‘./src/index.js’ }, output: { path: DIST_PATH, //出口路径 filename: ‘index.js’, chunkFilename: ‘[name]_[hash].js’, //按需加载名称 // publicPath: ‘./’ }, // 源错误检查 devtool: ‘source-map’, //模块配置 module: { rules: [ { test: /.(js|jsx)$/, exclude: /(node_modules|bower_components)/, //排除 include: [ path.resolve(__dirname, ‘../src’), path.resolve(__dirname, ‘../node_modules/antd/’) ], //包括 use: { loader: ‘babel-loader’ } }, { test: /.css$/, use: [‘style-loader’, ‘css-loader’] }, { test: /.(png|jpg|gif)$/, use: [ { loader: ‘url-loader’, options: { limit: 8192 } } ] }, //更改antd主题设置 { test: /.less$/, use: [ { loader: ‘style-loader’ }, { loader: ‘css-loader’ // translates CSS into CommonJS }, { loader: ’less-loader’, // compiles Less to CSS options: { minimize: true, modifyVars: { ‘font-size-base’: ‘12px’, ‘primary-color’: ‘#0EA679’ }, javascriptEnabled: true } } ] }, { test: /.(woff|woff2|eot|ttf|otf)$/, use: [‘file-loader’] } ] }, //插件 plugins: [ // 处理html new HtmlWebpackPlugin({ template: ‘public/index.html’, path: ‘../public/index.html’, inject: ‘body’, title: ‘管理平台’, favicon: ‘public/favicon.ico’, filename: ‘index.html’, hash: true, minify: { html5: true, removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true } }), new CleanWebpackPlugin([’../dist’], { allowExternal: true }), new BundleAnalyzerPlugin(), new MiniCssExtractPlugin({ chunkFilename: ‘[chunkhash].css’ }), new webpack.HashedModuleIdsPlugin(), new webpack.DllReferencePlugin({ context: __dirname, manifest: require(’../dll/manifest.json’) }), new CopyWebpackPlugin([ { from: ‘dll/Dll.js’, to: DIST_PATH } ]) ] // 热更新};学习过程中的踩坑生产环境打包报错ERROR in Path must be a string. Received undefinedChild html-webpack-plugin for “index.html”: 1 asset Entrypoint undefined = index.html 这个错误不影响打包结果,应该是版本问题导致。https://github.com/jantimon/h…写完才发现有些忘记记录了,会保持更新。学习的过程中也学习参考了其他优秀的博客和github,以及文档。https://github.com/brickspert…https://github.com/NewPrototy…https://github.com/axios/axioshttps://github.com/jamiebuild…https://www.webpackjs.com/con… ...

January 31, 2019 · 9 min · jiezi

从0到1使用VUE-CLI3开发实战(五):模块化VUEX及使用vuetify

小肆前几天发了一篇2019年Vue精品开源项目库的汇总,今天小肆要使用的是在UI组件中排行第三的Vuetify。vuetify介绍Vuetify是一个渐进式的框架,完全根据Material Design规范开发,一共拥有80多个组件,对移动端支持非常好。支持SSR(服务端渲染),SPA(单页应用程序),PWA(渐进式Web应用程序)和标准HTML页面。vuetify官方文档给出了它具备的几点优势:安装安装算是比较简单了,在项目目录输入以下命令就OK:vue add vuetify但这时有一个问题,如果我们使用默认的icon,index.html里面引入的是google的链接 <link href=‘https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons’ rel=“stylesheet”>我们需要替换成国内的https://fonts.cat.net/底部导航组件今天我们先用vuetify的语法写一个底部导航的组件,先放代码:<template> <v-card flat> <v-bottom-nav :value=“true” fixed color=“transparent”> <v-btn color=“teal” :to="{path:’/’}" flat> <span>首页</span> <v-icon>home</v-icon> </v-btn> <v-btn color=“teal” :to="{path:’/lottery’}" flat> <span>足彩</span> <v-icon>favorite</v-icon> </v-btn> <v-btn color=“teal” :to="{path:’/competition’}" flat> <span>赛事</span> <v-icon>place</v-icon> </v-btn> <v-btn color=“teal” :to="{path:’/course’}" flat> <span>课程</span> <v-icon>music_video</v-icon> </v-btn> </v-bottom-nav> </v-card></template>这里主要用到的是v-bottom-nav这个API,下面这张图显示了它可用的全部属性:上述代码的实际显示效果:模块化vuex为了使用方便,我们改造一下vuex,新建store目录,目录结构如下:更改store.jsimport Vue from ‘vue’import Vuex from ‘vuex’import app from ‘./store/modules/app’import user from ‘./store/modules/user’import getters from ‘./store/getters’Vue.use(Vuex)const store = new Vuex.Store({ modules: { app, user }, getters})export default store全局loading昨天我们配置了axios,今天我们来配置一下全局loading。先写一个组件RequestLoading.vue<template> <transition name=“fade-transform” mode=“out-in”> <div class=“request-loading-component” v-if=“requestLoading”> <v-progress-circular :size=“50” color=“primary” indeterminate></v-progress-circular> </div> </transition></template><script>import { mapGetters } from ‘vuex’export default { name: ‘RequestLoading’, computed: { …mapGetters([‘requestLoading’]) }}</script><style lang=“stylus” scoped>.request-loading-component { position: fixed; left: 0; right: 0; top: 0; bottom: 0; background-color: rgba(48, 65, 86, 0.5); font-size: 150px; display: flex; flex-direction: row; justify-content: center; align-items: center; z-index: 999999;}</style>这里我们用到了,vuetify中的v-progress-circular接下来我们配置一下vuexapp.jsconst app = { state: { requestLoading: 0 }, mutations: { SET_LOADING: (state, status) => { // error 的时候直接重置 if (status === 0) { state.requestLoading = 0 return } if (status) { ++state.requestLoading } else { –state.requestLoading } } }, actions: { SetLoading({ commit }, status) { commit(‘SET_LOADING’, status) } }}export default appgetter.jsconst getters = { requestLoading: (state) => state.app.requestLoading, token: (state) => state.user.token, avatar: (state) => state.user.avatar, name: (state) => state.user.name}export default getters最后我们修改一下axios.js// 添加请求拦截器service.interceptors.request.use( (config) => { if (config.method === ‘post’ || config.method === ‘put’) { // post、put 提交时,将对象转换为string, 为处理Java后台解析问题 config.data = JSON.stringify(config.data) } // loading + 1 store.dispatch(‘SetLoading’, true) // 请求发送前进行处理 return config }, (error) => { // 请求错误处理 // loading 清 0 setTimeout(function() { store.dispatch(‘SetLoading’, 0) }, 300) return Promise.reject(error) })// 添加响应拦截器service.interceptors.response.use( (response) => { let { data, headers } = response if (headers[‘x-auth-token’]) { data.token = headers[‘x-auth-token’] } // loading - 1 store.dispatch(‘SetLoading’, false) return data }, (error) => { let info = {}, { status, statusText, data } = error.response if (!error.response) { info = { code: 5000, msg: ‘Network Error’ } } else { // 此处整理错误信息格式 info = { code: status, data: data, msg: statusText } } // loading - 1 store.dispatch(‘SetLoading’, false) return Promise.reject(info) })这样我们在等待接口返回数据是就会看到下面这样子:小结好啦 ,今天就到这里吧,如果有什么疑问,可以下面留言,小肆会及时回复的。记得点好看呦!前置阅读:用vue-cli3从0到1做一个完整功能手机站(一)从0到1开发实战手机站(二):Git提交规范配置从0到1使用VUE-CLI3开发实战(三): ES6知识储备从0到1使用VUE-CLI3开发实战(四):Axios封装 ...

January 26, 2019 · 2 min · jiezi

axios默认请求参数后台获取不到解决方法

*axios post方法默认使用application/json格式编码数据,那么解决方案就有两种,一是后台改变接收参数的方法,另一种则是将axios post方法的编码格式修改为application/x-www-form-urlencoded,这样就不需要后台做什么修改了。只提供前端解决方案:var qs = require(‘qs’);let defaults = {headers : {‘Content-Type’:‘application/x-www-form-urlencoded;charset=utf-8’,‘X-Requested-With’:‘XMLHttpRequest’},}return axios.post(url, qs.stringify(data), { …options,…defaults })

January 25, 2019 · 1 min · jiezi

从0到1使用VUE-CLI3开发实战(四): Axios封装

从0到1使用VUE-CLI3开发实战(四): Axios封装有很多同学看了本系列的前几篇之后建议我暂时先不用TS,于是小肆之后将把TS换成JS继续下面的文章。今天给大家带来项目中非常重要的一环,配置Axios,一起来看看吧。axios 简介首先要明白的是axios是什么:axios是基于promise(诺言)用于浏览器和node.js是http客户端。axios的作用是什么呢:axios主要是用于向后台发起请求的,还有在请求中做更多是可控功能。从浏览器中创建 XMLHttpRequest从 node.js 发出 http 请求支持 Promise API拦截请求和响应转换请求和响应数据取消请求自动转换JSON数据客户端支持防止 CSRF/XSRF项目配置首先当然还是要安装啦:npm install axios之后我们新建一个api文件夹用来放接口和axios的配置。先给大家看看我配置好之后的文件夹目录结构:可以说这次配置是我划分的比较详细的配置方法了,具体每个文件都分别做什么用,我们现在来看看吧。axios.js这个文件主要创建axios实例并对拦截器进行配置,不理解拦截器的同学可以看看下图:import axios from ‘axios’// 创建 axios 实例let service = axios.create({ // headers: {‘Content-Type’: ‘application/json’}, timeout: 60000})// 设置 post、put 默认 Content-Typeservice.defaults.headers.post[‘Content-Type’] = ‘application/json’service.defaults.headers.put[‘Content-Type’] = ‘application/json’// 添加请求拦截器service.interceptors.request.use( (config) => { if (config.method === ‘post’ || config.method === ‘put’) { // post、put 提交时,将对象转换为string, 为处理Java后台解析问题 config.data = JSON.stringify(config.data) } // 请求发送前进行处理 return config }, (error) => { // 请求错误处理 return Promise.reject(error) })// 添加响应拦截器service.interceptors.response.use( (response) => { let { data } = response return data }, (error) => { let info = {}, { status, statusText, data } = error.response if (!error.response) { info = { code: 5000, msg: ‘Network Error’ } } else { // 此处整理错误信息格式 info = { code: status, data: data, msg: statusText } } })/** * 创建统一封装过的 axios 实例 * @return {AxiosInstance} */export default function() { return service}index.jsindex.js文件主要封装我们几个常用的方法,get、post、put、deleteimport axios from ‘./axios’let instance = axios()export default { get(url, params, headers) { let options = {} if (params) { options.params = params } if (headers) { options.headers = headers } return instance.get(url, options) }, post(url, params, headers, data) { let options = {} if (params) { options.params = params } if (headers) { options.headers = headers } return instance.post(url, data, options) }, put(url, params, headers) { let options = {} if (headers) { options.headers = headers } return instance.put(url, params, options) }, delete(url, params, headers) { let options = {} if (params) { options.params = params } if (headers) { options.headers = headers } return instance.delete(url, options) }}install.jsinstall.js文件可以把我们所有的api接口安装到全局,之后我们在main.js文件中导入就可以了。import apiList from ‘./apiList’const install = function(Vue) { if (install.installed) { return install.installed = true Object.defineProperties(Vue.prototype, { $api: { get() { return apiList } } })}export default { install}main.js中添加:import api from ‘./api/install’Vue.use(api)apiList.js把我们所有的api文件夹导入到这一个文件中来。import matches from ‘./matches’import user from ‘./user’export default { matches, user}baseUrl.js根据不同的环境设定不同的baseUrl,在配置这个文件前,我们先需要做如下几件事:1.根目录新建.env.dev文件并在文件内写入NODE_ENV = ‘dev'2.在package.json文件内添加: “build:dev”: “vue-cli-service build –mode dev”, “build:pre”: “vue-cli-service build –mode pre”,以下是baseUrl.js的代码:let baseUrl = ‘/api’ // 本地代理switch (process.env.NODE_ENV) { case ‘dev’: baseUrl = ‘http://testserver.feleti.cn/' // 测试环境url break case ‘pre’: baseUrl = ‘https://pre-server.feleti.cn’ // 预上线环境url break case ‘production’: baseUrl = ‘https://api.feleti.cn’ // 生产环境url break}export default baseUrlmatches、user这两个文件夹都是根据api类型进行区分的,在项目以后也建议大家根据api类型划分出不同的文件存放,在小项目中这样做可能显得很麻烦,但如果项目比较大,这样做的优势就体现出来了。我们就只看看matches文件夹下的内容:urls.js把一个类型下的所有url接口放入这一个文件,我只放了一个暂时,可以继续添加。import baseUrl from ‘../baseUrl’export default { matches: baseUrl + ‘/matches’}index.js有些接口需要在header中添加token或是其他,可以按如下配置。import api from ‘../index’import urls from ‘./urls’const header = {}export default { matches(params) { // return出去了一个promise return api.get(urls.matches, params, header) }}配置完上述全部文件就算是大功告成了,下面我们看看如何使用吧。组件中调用created() { this.matches() }, methods: { async matches() { // 这里用try catch包裹,请求失败的时候就执行catch里的 try { //定义参数对象 let params = { type: ‘zc’ } let res = await this.$api.matches.matches(params) console.log(‘getMatches -> res’, res) } catch (e) { console.log(‘catch -> e’, e) } } }之后我们就可以在控制台看到我们调用成功的输出日志啦:小结在实际工作中,我们尽量要把项目做的细致一些,尤其是项目开始之前的配置,今天所涉及到的很多文件在之后的配置中还会有进步的更改,比如配置用户相关的接口、配置全局loading等,大家只要能把今天的内容完全理解,之后再配置这里就很容易啦。前置阅读:用vue-cli3从0到1做一个完整功能手机站(一)从0到1开发实战手机站(二):Git提交规范配置从0到1使用VUE-CLI3开发实战(三): ES6知识储备 ...

January 25, 2019 · 2 min · jiezi

axios-extra 支持并发及自动重试功能的 axios

axios 基于 promise 用于 浏览器 和 node.js 的 http 客户端;而 axios-extra 扩展了 axios 让它拥有有并发控制以及重试的能力;如果你是一正在使用 axios 只要修改一行代码立即拥有安装npm i axios-extra使用默认最大 10 并发, 0 重试;//const axios = require(‘axios’); const axios = require(‘axios-extra’); //修改一行代码 无感使用 axios-extra设置并发数,及重试次数方式一: 用 axios.defaults 修改默认配制const axios = require(‘axios-extra’);axios.defaults.maxConcurrent = 1; //修改并发为1axios.defaults.queueOptions.retry = 2; //修改默认重试次数为2方式二: 用 axios.create(config) 创建新的 axiosconst axios = require(‘axios-extra’);let axios1 = axios.create({ maxConcurrent: 1, //并发为1 queueOptions: { retry: 3, //请求失败时,最多会重试3次 retryIsJump: true //是否立即重试, 否则将在请求队列尾部插入重试请求 }});方式三: 为某一次特殊请求单独设置重试设置config参数的queueOptions属性即可;const axios = require(‘axios-extra’);//本次get请求若不成功,将重试3次axios.get(‘http://xxx’,{ queueOptions: {retry: 3}})axios 的发送请求方法均可使用:axios(config)axios.request(config)axios.get(url[, config])axios.delete(url[, config])axios.head(url[, config])axios.options(url[, config])axios.post(url[, data[, config]])axios.put(url[, data[, config]])axios.patch(url[, data[, config]])补充并发与重试都是基于队列实现的, 默人重试是在队列的最后重新插入请求. retryIsJump 设置为true最会在队列头部插入请求, 实现立即重试更多 queueOptions 配制可参看这里 ...

January 23, 2019 · 1 min · jiezi

javascript异步之Promise.all()、Promise.race()、Promise.finally()

同期异步系列文章推荐谈一谈javascript异步javascript异步中的回调javascript异步与promisejavascript异步之Promise.resolve()、Promise.reject()javascript异步之Promise then和catchjavascript异步之async(一)javascript异步之async(二)javascript异步实战javascript异步总结归档今天我们继续讨论promise网络上关于PromiseAPI使用的文章多如牛毛,为了保持javascript异步系列文章的完整性,现在对promise的API进行简单全面的介绍准备工作我在easy-mock添加了三个接口,备用依然使用axios进行ajax请求Promise.all()Promise.all()有点像“并行”我们看一个栗子<!DOCTYPE html><html lang=“en”><head> <meta charset=“UTF-8”> <meta name=“viewport” content=“width=device-width, initial-scale=1.0”> <meta http-equiv=“X-UA-Compatible” content=“ie=edge”> <title>promise</title> <script src=“https://unpkg.com/axios/dist/axios.min.js"></script></head><body> <script> { const p1 = axios.get(‘https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/promise1') .then(({ data }) => { console.log(‘p1成功啦’); return data.data }) const p2 = axios.get(‘https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/promise2') .then(({ data }) => { console.log(‘p2成功啦’); return data.data }) const p3 = axios.get(‘https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/mock') .then(({ data }) => { console.log(‘p3成功啦’); return data.data }) const p = Promise.all([p3, p1, p2]) .then(arr => { console.log(arr); console.log(‘Promise.all成功啦’); }) .catch(err=>{ console.log(err,‘Promise.all错啦’); }) } </script></body></html>我们知道axios返回的是一个promise对象,我们可以看下 console.log(p1);Promise.all就是用于将多个 Promise 实例,包装成一个新的 Promise 实例Promise.all,接收一个数组作为参数,数组的每一项都返回Promise实例我们重点看这段代码 const p = Promise.all([p3, p1, p2]) .then(arr => { console.log(arr); console.log(‘Promise.all成功啦’); }) .catch(err=>{ console.log(err,‘Promise.all错啦’); })p1,p2,p3都是返回promise实例,Promise.all不关心他们的执行顺序,如果他们都返回成功的状态,Promise.all则返回成功的状态,输出一个数组,是这三个p1,p2,p3的返回值,数组的顺序和他们的执行顺序无关,和他们作为参数排列的顺序有关我们看下输出为了是拉长接口三的返回时间我对接口三的数据进行了修改,返回值是长度1000-2000之间的随机数组,所以p3的执行要晚于p1和p2,但我们输出的arr,p3依然在前面,这给我们带来一个便利,返回值数组的顺序和方法的执行顺序无关,可以进行人为进行控制我们将p1做一下改动,使p1报错 const p1 = axios.get(‘https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/promise1') .then(({ data }) => { console.log(‘p1成功啦’); return xxxx.data//将data.data修改为xxxx.data })如果有一个返回失败(reject),Promise.all则返回失败(reject)的状态,此时第一个被reject的实例的返回值,会传递给P的回调函数。三个promise实例参数之间是“与”的关系,全部成功,Promise.all就返回成功,有一个失败,Promise.all就返回失败换个角度说,一个promise的执行结果依赖于另外几个promise的执行结果,例如:几个ajax全部执行完了,才能渲染页面,几个ajax全部执行完了,才能做一些数据的计算操作,不关心执行顺序,只关心集体的执行结果Promise.race()Promise中的竞态,用法和Promise.all类似,对应参数的要求和Promise.all相同,传入一个数组作为参数,参数要返回一个Promise实例race就是竞争的意思,数组内的Promise实例,谁执行的快,就返回谁的执行结果,不管是成功还是失败const p = Promise.race([p3, p1, p2]) .then(res => { console.log(res); console.log(‘Promise.all成功啦’); }) .catch(err=>{ console.log(err,‘Promise.all错啦’); })通过输出我们发现p1是第一个完成的,所以p的返回结果就是p1的执行结果而且就算完成,但是 进程不会立即停止,还会继续执行下去。关于race的使用场景搜了一下,很多文章都说是用来解决网络超时的提示,类似于下面这样 const p3 = axios.get(‘https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/mock') .then(({ data }) => { console.log(‘p3成功啦’); return data.data }) const p4 = new Promise(function (resolve, reject) { setTimeout(() => reject(new Error(‘网络连接超时’)), 50) }) const p = Promise.race([p3, p4]) .then(res => console.log(res)) .catch(err => console.log(err));p3的ajax和50ms的定时器比较,看谁执行的快,如果超过了50ms,p3的ajax还没返回,就告知用户网络连接超时这里有个问题,就算提示超时了,p3还在继续执行,它并没有停下来,直到有状态返回个人观点:race可以用来为ajax请求的时长划定范围,如果ajax请求时长超过xxxms会执行某个方法,或者ajax请求时长不超过xxms会执行某个方法,总之,race的应用空间不是很大Promise.finally()finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。 const p = Promise.race([p3, p4]) .then(res => console.log(res)) .catch(err => console.log(err)) .finally(() => { console.log(“finally的执行与状态无关”) });当promise得到状态(不论成功或失败)后就会执行finally,原文链接参考链接Promise 对象Promise.prototype.finally ...

January 22, 2019 · 1 min · jiezi

javascript异步与promise

同期异步系列文章推荐谈一谈javascript异步javascript异步中的回调javascript异步之Promise.all()、Promise.race()、Promise.finally()javascript异步之Promise.resolve()、Promise.reject()javascript异步之Promise then和catchjavascript异步之async(一)javascript异步之async(二)javascript异步实战javascript异步总结归档我们说处理javascript异步最常用的方式就是通过回调函数,对于回调函数我们昨天对此做了介绍简单快速,我们一般使用嵌套回调或者链式回调,会产生以下问题当采用嵌套回调时,会导致层级太多,不利于维护所以我们又采用了链式回调,对嵌套回调进行拆分,拆分后的函数间耦合度很高,如果需要传递参数,函数之间的关联性会更高,而且要对参数进行校验以提高代码的健壮性如果将我们自己的回调函数传递给第三方插件或者库,就要考虑一些不可控因素调用回调过早调用回调过晚(或不被调用)调用回调次数过多或者过少promise的存在就是为了解决以上问题虽然我们日常写回调函数不会有这么严格的要求,但是如果不这样去写回调函数,就会存在隐患,当在团队协作的时候,显得编码规范显得尤为重要本文不重点介绍如何使用promise,重点介绍的是promise解决了哪些异步回调出现的问题。什么是promise我们来看一个场景,有助于我们了解promise设想一下这个场景,我去KFC,交给收银员10元,下单买一个汉堡,下单付款。到这里,我已经发出了一个请求(买汉堡),启动了一次交易。但是做汉堡需要时间,我不能马上得到这个汉堡,收银员给我一个收据来代替汉堡。到这里,收据就是一个承诺(promise),保证我最后能得到汉堡。所以我需要好好的保留的这个收据,对我来说,收据就是汉堡,虽然这张收据不能吃,我需要等待汉堡做好,等待收银员叫号通知我等待的过程中,我可以做些别的事情收银员终于叫到了我的号,我用收据换来了汉堡当然还有一种情况,当我去柜台取汉堡的时候,收银员告诉我汉堡卖光了,做汉堡的师傅受伤了等等原因,导致了我无法得到这个汉堡虽然我有收据(承诺),但是可能得到汉堡(成功),可能得不到汉堡(失败)我由等待汉堡变成了等到或者等不到,这个过程不可逆,上面很形象的介绍了promise,上面的等待汉堡和得到汉堡,汉堡卖光了,得不到汉堡,分别对应promise的三种状态三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)(一旦状态改变,就不会再变)回调函数调用过早调用过早就是将异步函数作为同步处理了,我们之前说过,javascript以单线程同步的方式执行主线程,遇到异步会将异步函数放入到任务队列中,当主线程执行完毕,会循环执行任务队列中的函数,也就是事件循环,直到任务队列为空。事件循环和任务队列事件循环就像是一个游乐场,玩过一个游戏后,你需要重新排到队尾才能再玩一次任务队列就是,在你玩过一个游戏后,可以插队接着玩我们看一个栗子 const promise = new Promise((resolve, reject) => { resolve(“成功啦”) }); promise.then(res => { console.log(res); console.log(“我是异步执行的”); }) console.log(‘我在主线程’);看下输出,重点看输出顺序//我在主线程//成功啦//我是异步执行的直接手动是promise的状态切为成功状态,console.log(“我是异步执行的”);这段代码也是异步执行的提供给then()的回调永远都是异步执行的,所以promise中不会出现回调函数过早执行的情况回调函数调用过晚或不被调用回调函数调用过晚回调函数调用过晚的处理原理和调用过早很类似,在promise的then()中存放着异步函数,所有的异步都存在于js的任务队列中,当js的主线程执行完毕后,会依次执行任务队列中的内容,不会出现执行过晚的情况回调函数不被调用我们用栗子说话 const promise = new Promise((resolve, reject) => resolve(‘成功啦’)) promise.then(s => console.log(s)); console.log(‘我在主线程’);成功状态的输出//我在主线程//成功啦成功状态下回调被调用继续看一下失败的回调 const promise = new Promise((resolve, reject) => reject(‘失败啦’)) promise.then(null, s => console.log(s)); console.log(‘我在主线程’);失败状态的输出//我在主线程//失败啦失败状态下回调被调用所以说,不管是失败还是成功,回调函数都会被调用回调函数调用次数过多或者过少调用次数过多我们之前说了promise有三种状态pending(进行中)、fulfilled(已成功)和rejected(已失败)状态一旦状态改变,就不会再变一个栗子 const promise = new Promise((resolve, reject) => { reject(‘失败啦’) resolve(‘成功啦’) }); promise.then(res => { console.log(我是异步执行的成功:${res}); },err=>{ console.log(我是异步执行的失败:${err}); }).catch(err => { console.log(err); }) console.log(‘我在主线程’);输出//我在主线程//我是异步执行的失败:失败啦当状态变为失败时,就不会再变为成功,成功的函数也不会执行,反之亦然调用次数过少回调函数正常是调用一次,过少=>0次=>回调函数不被调用,上面刚刚讨论过原文链接参考链接JavaScript Promise 迷你书Promise 对象ES6 系列之我们来聊聊 Promise ...

January 21, 2019 · 1 min · jiezi

javascript异步中的回调

同期异步系列文章推荐谈一谈javascript异步javascript异步与promisejavascript异步之Promise.all()、Promise.race()、Promise.finally()javascript异步之Promise.resolve()、Promise.reject()javascript异步之Promise then和catchjavascript异步之async(一)javascript异步之async(二)javascript异步实战javascript异步总结归档我们之前介绍了javascript异步的相关内容,我们知道javascript以同步,单线程的方式执行主线程代码,将异步内容放入事件队列中,当主线程内容执行完毕就会立即循环事件队列,直到事件队列为空,当用产生用户交互事件(鼠标点击,点击键盘,滚动屏幕等待),会将事件插入事件队列中,然后继续执行。处理异步逻辑最常用的方式是什么?没错这就是我们今天要说的—回调js回调函数如你所知,函数是对象,所以可以存储在变量中,所以函数还有以下身份:可以作为函数的参数可以在函数中创建可以在函数中返回当一个函数a以一个函数作为参数或者以一个函数作为返回值时,那么函数a就是高阶函数回调函数百度百科回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。维基百科在计算机程序设计中,回调函数,或简称回调(Callback 即call then back 被主函数调用运算后会返回主函数),是指通过函数参数传递到其它代码的,某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序。回调函数,几乎每天我们都在用 setTimeout(() => { console.log(“这是回调函数”); }, 1000); const hero=[‘郭靖’,‘黄蓉’] hero.forEach(item=>{ console.log(item); })回调函数解决了哪些问题举一个简单的: let girlName = “裘千尺” function hr() { girlName = “黄蓉” console.log(我是${girlName}); } function gj() { console.log(${girlName}你好,我是郭靖,认识一下吧); } hr() gj()输出,重点看输出顺序//=>我是黄蓉//=>黄蓉你好,我是郭靖,认识一下吧上面的代码输出是没什么悬念的,不存在异步,都单线程同步执行,最后郭靖和黄蓉相识如果这时候黄蓉很忙,出现了异步,会怎么样? let girlName = “裘千尺” function hr() { setTimeout(() => { girlName = “黄蓉” console.log(‘我是黄蓉’); }, 0); } function gj() { console.log(${girlName}你好,我是郭靖,认识一下吧); } hr() gj()输出,重点看输出顺序//=>裘千尺你好,我是郭靖,认识一下吧//=>我是黄蓉虽然定时器是0ms,但是也导致了郭靖和黄蓉的擦肩而过,这不是我们期望的结果,hr函数存在异步,只有等主线程的内容走完,才能走异步函数所以最简单的办法就是使用回调函数解决这种问题,gj函数依赖于hr函数的执行结果,所以我们把gj作为hr的一个回调函数 let girlName = “裘千尺” function hr(callBack) { setTimeout(() => { girlName = “黄蓉” console.log(‘我是黄蓉’); callBack() }, 0); } function gj() { console.log(${girlName}你好,我是郭靖,认识一下吧); } hr(gj)输出,重点看输出顺序//=>我是黄蓉//=>黄蓉你好,我是郭靖,认识一下吧⚠️:当回调函数作为参数时,不要带后面的括号!我们只是传递函数的名称,不是传递函数的执行结果上面小栗子貌似的很简单,我们继续嵌套回调和链式回调我们把昨天的demo做一下升级引入了lodash:处理按钮点击防抖axios,集成了promis,但promise不是我们今天讨论的内容,我们只使用axios的ajax请求接口功能easy-mock:接口数据,用来实现ajax请求(数据是假的,但是请求是真的)嵌套回调<!DOCTYPE html><html lang=“en”><head> <meta charset=“UTF-8”> <meta name=“viewport” content=“width=device-width, initial-scale=1.0”> <meta http-equiv=“X-UA-Compatible” content=“ie=edge”> <title>javascript回调</title> <script src=“https://unpkg.com/axios/dist/axios.min.js"></script> <script src=“https://cdn.bootcss.com/lodash.js/4.17.11/lodash.min.js"></script></head><body> <button>点击</button> <script> { const btn = document.querySelector(‘button’) btn.onclick = () => { _.debounce(() => { axios.get(‘https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/mock') .then(data => { console.log(“ajax返回成功”); myData = data.data console.log(myData); }) .catch(error => { console.log(“ajax返回失败”); }) }, 500)() } } </script></body></html>仔细看代码,不难发现,这是一个典型的嵌套回调,我们分析一下第一层异步,用户交互,来自按钮的点击事件第二层异步,按钮去抖,来自lodash下debounce的500ms延时第三次异步,ajax请求,处理后台接口数据拿到数据后我们没有继续做处理,在实际工作中可能还存在异步,还会继续嵌套,会形成一个三角形的缩进区域再继续嵌套,就会形成所说的“回调地狱”,就是回调的层级太多了,代码维护成本会高很多上面的栗子最多算是入门毁掉地狱,我们看一下这个 function funA(callBack) { console.log(“A”); setTimeout(() => { callBack() }, 10); } function funB() { console.log(“B”); } function funC(callBack) { console.log(“C”); setTimeout(() => { callBack() }, 100); } function funD() { console.log(“D”); } function funE() { console.log(“E”); } function funF() { console.log(“F”); }//从这里开始执行 funA(() => { funB() funC(() => { funD() }) funE() }) funF()(这段代码,带回调的都是异步逻辑)你能很快的看出这段代码的执行顺序吗?顺序如下:A、F、B、C、E、D一般正常人不会这么嵌套多层,层级一多,就会考虑拆分链式回调 const btn = document.querySelector(‘button’) //监听按钮点击事件 btn.onclick = () => { debounceFun() } //去抖动 const debounceFun = _.debounce(() => { ajax() }, 500) //ajax 请求 const ajax = function () { axios.get(‘https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/mock') .then(data => { console.log(“ajax返回成功”); myData = data.data console.log(myData); }) .catch(error => { console.log(“ajax返回失败”); }) }我相信很多人都会通过这种链式回调的方式处理异步回调,因为可读性比嵌套回调要搞,但是维护的成本可能要高很多上面的栗子,三个异步函数之间只有执行顺序上的关联,并没有数据上的关联,但是实际开发中的情况要比这个复杂,回调函数参数校验我们举一个简单的栗子 let girlName = “裘千尺” function hr(callBack) { setTimeout(() => { girlName = “黄蓉” console.log(‘我是黄蓉’); callBack(girlName) }, 0); } function gj(love) { console.log(${girlName}你好,我是郭靖,认识一下吧,我喜欢${love}); } hr(gj)gj作为hr的回调函数,并且hr将自己的一个变量传递给gj,gj在hr的回调中执行,仔细看这种写法并不严谨,如果gj并不只是一个function类型会怎么样?如果love的实参并不存在会怎么样?况且这只是一个简单的栗子所以回调函数中,参数的校验是很有必要的,回调函数链拉的越长,校验的条件就会越多,代码量就会越多,随之而来的问题就是可读性和可维护性就会降低。还是回调函数的校验但我们引用了第三方的插件或库的时候,有时候难免要出现异步回调的情况,一个栗子:xx支付,当用户发起支付后,我们将自己的一个回调函数,传递给xx支付,xx支付比较耗时,执行完之后,理论上它会去执行我们传递给他的回调函数,是的理论上是这样的,我们把回调的执行权交给了第三方,隐患随之而来第三方支付,多次调用我们的回调函数怎么办?第三方支付,不调用我们的回调函数怎么办?当我们把回调函数的执行权交给别人时,我们也要考虑各种场景可能会发生的问题总结一下:回调函数简单方便,但是坑也不少,用的时候需要多注意校验原文链接 ...

January 18, 2019 · 2 min · jiezi

初识vue之axios的封装

18年初开始接触vue,最开始是使用的vue-resource,不过听说axios挺牛逼的,准备跳坑试试,毕竟vue-resource官方已经放弃维护了其中就是baseURL是我们后台接口的请求路劲(request的最后url=baseURL+axios的请求url) withCredentials 这个字段是让我们的请求携带cookie的信息,如果没有设置的话,默认的false,就会出现session丢失的情况,一直无法取到session里面的信息request请求拦截器,在这里我们可以在做一些请求之前操作,对于某些请求,根据请求的携带过来的参数(例如下面这个请求,就没有loading的效果)有些项目需要请求好几个后台服务,在请求拦截器这里直接更改request的baseURL就成。。还有有些接口需要更改头部的信息,直接修改就成 ps:这这里不得不吐槽下vue-resource 在请求拦截器里面更改头部所碰到的坑,想更改头部的信息,必须得先将emulateJSON 这个字段设为false axios的请求默认的headers的Content-Type为’application/x-www-form-urlencoded;charset=UTF-8’post请求后端的 (后端框架ssm)Controller中@RequestParam取不到请求参数这个时候对请求参数做qs.stringify()处理就好了或者要求后端改成从@RequestBody获取参数也成当请求头部为application/json 无需对请求参数做任何处理response 响应拦截器主要是对请求超时的情况做处理。

January 16, 2019 · 1 min · jiezi

vue开发环境配置跨域,一步到位

本文要实现的是:使用vue-cli搭建的项目在开发时配置跨域,上线后不做任何任何修改,接口也可以访问阅读时间需要三分钟production:产品 生产环境development:开发 开发环境1.开发环境设置跨域使用工具:vue-cli自带的配置配置目录 /config/index.js//自行复制黏贴proxyTable: { ‘/apis’:{ target: ‘http://10.1.63.26:19080/’, // 后台api changeOrigin: true, //是否跨域 // secure: true, pathRewrite: { ‘^/apis’: ’’ //需要rewrite的, } }}注意:以上配置只有在生产环境下有效,你打包之后就不起作用了这样就存在一个问题,你的接口都是/apis开头的,打包之后部署到服务器要去除/apis,才能正常访问后台接口,如何解决呢?2.生产环境设置跨域使用工具 axios 中文文档地址思路解决的思路是这样的:首先,axios有一个baseURL的属性,配置了baseURL之后,你访问接口时就会自动带上假设你vue-cli起了一个开发环境,地址为http://localhost:8080//例1 当不设置baseURL时axios.get(’/user’) //访问/user相当于访问 http://localhost:8080/user//例2 axios.baseURL=’/apis’axios.get(’/user’) //访问/user就相当于访问 http://localhost:8080/apis/user//例3axios.baseURL=‘https://sbsb.com’axios.get(’/user’) //访问/user就相当于访问 https://sbsb.com/user//例4axios.baseURL=‘https://sbsb.com/apis'axios.get('/user') //访问/user就相当于访问 https://sbsb.com/apis/user然后我们要根据现在的环境是开发环境还是生产环境,配置不同的baseURL//判断是否是生产环境var isPro = process.env.NODE_ENV === ‘production’ //process.env.NODE_ENV用于区分是生产环境还是开发环境//配置不同的baseURLmodule.exports = { baseURL: isPro ? ‘http://sbsb.com:8888/' : ‘/apis’}process.env.NODE_ENV用于区分是生产环境还是开发环境,这个值是webpack设置的动手操作假设后台api的rul是http://sbsb.com:8888/首先在/config目录下新建一个文件,我这里叫api.config.js写入以下代码//判断是否是生产环境var isPro = process.env.NODE_ENV === ‘production’ //process.env.NODE_ENV用于区分是生产环境还是开发环境//根据环境不同导出不同的baseURLmodule.exports = { baseURL: isPro ? ‘http://sbsb.com:8888/' : ‘/apis’}然后,在main.js中引入axios和刚才那个文件//main.jsimport Vue from ‘vue’import axios from ‘axios’import apiConfig from ‘../config/api.config.js’axios.baseURL=apiConfig.baseURL//axios的其他配置…这样配置之后,打包部署到服务器上也不用再手工去除/apis如果配置过程中出现了问题,自己调试,看看访问的url正不正确 ...

January 16, 2019 · 1 min · jiezi

axios异步请求数据的简单使用

使用Mock模拟好后端数据之后(Mock模拟数据的使用参考:https://segmentfault.com/a/11…),就需要尝试请求加载数据了。数据请求选择了axios,现在都推荐使用axios。axios(https://github.com/axios/axios)是基于 promise 的 HTTP 库。如官网文档介绍,npm i 之后,在需要的组件中加载就可以了。个人认为,编码的魅力在于,解决问题的方法不止一种,有时候这个方法在你的开发环境下ok,在我的开发环境下却不ok,所以,问题是各式各样的,而解决问题的方法也是百花齐放的。axios的入门1、安装npm i axios -S2、引入在src目录下新建apis.js文件(项目逐渐完善的过程中会有很有个api接口,当然也可以命名为axios.js,命名是为了让别人看懂),并引入:import axios from ‘axios’;之后,编辑apis.js文件,考虑封装axios.get或post请求3、apis.js文件的编辑import axios from ‘axios’;const Domain = “http://localhost:8080”; // 定义根域名axios.defaults.headers.post[‘Content-Type’] = ‘application/x-www-form-urlencoded’; // 设置post默认的请求头// 封装 post 请求export function post(action, params){ return new Promise((resolve, reject) => { // url 判断是测试环境 就要拿 测试环境的域名, 正式环境的就要用 正式域名 let url = Domain + action; axios.post(url, params) .then(response => { resolve(response.data) }) .catch(error => { reject(error) }) });} // 封装 get 请求export function get(action, params){ return new Promise((resolve, reject) => { axios.get(Domain + action, params) .then(response => { resolve(response.data) }) .catch(error => { reject(error) }) });}export default { postData(action, params){ return post(action, params) }, getData(action, params){ return get(action, params) }}4、在需要的组件中进行引用 import api from ‘../../apis.js’; export default { name: “banner”, data() { return { bannerList: [] }; }, created(){ this.getBanner(); // 在页面渲染完成即加载 }, methods: { getBanner(){ this.$api.getData(’/getBanner’).then(val => { this.bannerList = val.imgs; }); } }}5、全局配置axios很多组件都需要请求数据,每用一次导入一次很麻烦,全局配置之后就不用在组件中导入了。在入口文件main.js中引入,之后挂在vue的原型链上:import api from ‘./apis.js’;Vue.prototype.$http = api;在组件中使用:getBanner(){ this.$http.getData(’/getBanner’).then(val => { this.bannerList = val.imgs; }); } 6、axios结合vuex(在项目中还没用到,如果有问题,欢迎指正)在vuex的仓库文件store.js中引用,使用action添加方法。action 可以包含异步操作,而且可以通过 action 来提交 mutations。action有一个固有参数context,但是 context 是 state 的父级,包含state、gettersimport Vue from ‘Vue’import Vuex from ‘vuex’import axios from ‘axios’Vue.use(Vuex)export default new Vuex.Store({ // 定义状态 state: { banners: { name: ‘pic’ } }, actions: { // 封装一个 ajax 方法 saveBanner (context) { axios({ method: ‘get’, url: ‘/getBanner’, data: context.state.banners }) } }})在组件中发送请求的时候,需要使用 this.$store.dispatch 来分发methods: { getBananer() { this.$store.dispatch(‘saveBanner’) // actions里的方法名 }} 异步加载的几种方法1、$.ajax( url[, settings])url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址。 type: 要求为String类型的参数,请求方式(post或get)默认为get。 data:规定要发送到服务器的数据。 async:布尔值,表示请求是否异步处理。默认是 true。 dataType: 要求为String类型的参数,预期服务器返回的数据类型。 contentType:要求为String类型的参数,当发送信息至服务器时,内容编码类型默认为"application/x-www-form-urlencoded"。 success:要求为Function类型的参数,请求成功后调用的回调函数。 error:Function类型的参数,请求失败后调用的回调函数。 jsonp:在一个 jsonp 中重写回调函数的字符串。$(function(){ $(’#send’).click(function(){ $.ajax({ type: “GET”, url: “test.json”, data: {username:$("#username").val(), content:$("#content").val()}, dataType: “json”, success: function(data){ // handle success } error: function(data){ // handle error } jsonp: "" }); }); }); 2、$.ajax 的跨域请求问题当Ajax请求的url不是本地或者同一个服务器的地址时,浏览器会报一个错误:No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin…………由于浏览器的安全机制,不能调用不同服务器下的url地址。基于此,jQuery.ajax给出了jsonp的解决方案: 把服务器返回的数据类型设置为jsonp。 $(function(){ $(’#send’).click(function(){ $.ajax({ type: “GET”, url: “test.json”, data: {username:$("#username").val(), content:$("#content").val()}, dataType: “jsonp”, // jsonp格式 success: function(data){ // handle success } error: function(data){ // handle error } jsonp: “callback” }); }); }); 但是,jsonp是一种非官方的方法,而且这种方法只支持get请求,不如post请求安全。此外,jsonp需要服务器配合,如果是访问的是第三方服务器,我们没有修改服务器的权限,那么这种方式是不可行的。3、vue框架中的vue-resourceue-resource是Vue.js的一款插件,它可以通过XMLHttpRequest或JSONP发起请求并处理响应。vue-resource体积小,支持主流浏览器。不过,vue2.0之后就不再更新了,尤大神推荐使用axios。{ // GET /someUrl this.$http.get(’/someUrl’).then(response => { // get body data this.someData = response.body; }, response => { // error callback });}4、vue-resource的跨域请求问题同样地,由于浏览器的安全机制,vue-resource也面临着跨域请求的问题。解决方案如下:在vue项目下的 config/index.js 文件里面配置代理proxyTable:dev: { // Paths assetsSubDirectory: ‘static’, assetsPublicPath: ‘/’, proxyTable: { // 新增,解决跨域请求问题 ‘/api’: { target: ‘http://192.168.1.103:8080/’, changeOrigin: true, pathRewrite: { ‘/api': '/' } }, secure: false }, target中写你想要请求数据的地址的域名 4、axios跨域请求的问题与vue-resource一样,在vue项目下的 config/index.js 文件里面配置代理proxyTable: dev: { // Paths assetsSubDirectory: 'static', assetsPublicPath: '/', proxyTable: { // 新增,解决跨域请求问题 '/api': { target: 'http://192.168.1.103:8080/', changeOrigin: true, pathRewrite: { '/api’: ‘/’ } }, secure: false }, 不过vue-resource和axios这两个方法,可能配置了代理proxyTable还是会报:No ‘Access-Control-Allow-Origin’ header is present on ……的问题,这需要后端服务器配合设置: header(“Access-Control-Allow-Origin”, “*”); header(“Access-Control-Allow-Methods”,“PUT,POST,GET,DELETE,OPTIONS”); emmmm,总感觉自己还是有点懵 233 ...

January 13, 2019 · 2 min · jiezi

谈一谈javascript异步

从今天开始研究一下javascript的异步相关内容,感兴趣的请关注同期异步系列文章推荐javascript异步中的回调javascript异步与promisejavascript异步之Promise.all()、Promise.race()、Promise.finally()javascript异步之Promise.resolve()、Promise.reject()javascript异步之Promise then和catchjavascript异步之async(一)javascript异步之async(二)javascript异步实战javascript异步总结归档什么是js异步?我们知道JavaScript的单线程的,这与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?所谓"单线程",就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段Javascript代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。ajax的同步请求就会导致浏览器产生假死,因为它会锁定浏览器的UI(按钮,菜单,滚动条等),并阻塞所有用户的交互,jquery中的ajax有这样一个同步请求的功能,一定要慎用,尤其是在请求的数据量很大的时候,要避免使用同步请求。举几个栗子????感受一下异步后台接口使用easy-mock,官方地址:https://easy-mock.com/ajax使用axios,基本代码如下<!DOCTYPE html><html lang=“en”><head> <meta charset=“UTF-8”> <meta name=“viewport” content=“width=device-width, initial-scale=1.0”> <meta http-equiv=“X-UA-Compatible” content=“ie=edge”> <title>javascript异步</title> <script src=“https://unpkg.com/axios/dist/axios.min.js"></script></head><body> <button>点击</button> <script> { let myData = null //ajax请求 function ajax() { axios.get(‘https://easy-mock.com/mock/5b0525349ae34e7a89352191/example/mock') .then(data => { console.log(“ajax返回成功”);// handle success myData = data.data console.log(myData); }) .catch(error => { // console.log(error); // handle error console.log(“ajax返回失败”); }) } } </script></body></html>我们通过添加一些js来看下效果,异步-定时器 console.log(myData); setTimeout(() => { console.log(‘定时器’); }, 2000); console.log(myData);输出,应该没什么悬念//null//null//定时器执行顺序:先执行第一个 console.log(myData);然后遇到了定时器,将定时器挂起(就是暂停了这个定时器)继续执行第二个 console.log(myData);没有可以执行的js代码,回头把挂起的任务继续执行下去继续看下一个栗子异步-ajax console.log(myData); ajax() console.log(myData);看下输出,依然没有悬念//null//null//ajax返回成功//{success: true, data: {…}}(这是接口返回的数据,我们不必关心返回的具体内容,只要知道返回了就好,陌上寒注)执行顺序和上面的定时器基本类似,不在此赘述。将两个栗子合并,我们看下 console.log(myData); ajax() setTimeout(() => { console.log(‘定时器’); }, 2000); console.log(myData);输出,//null//null//ajax返回成功//{success: true, data: {…}}//定时器发现问题了吗?两个异步函数相遇了,先执行谁?谁跑的快就先执行谁?也可以这么说,其实这引发了另外一个知识点,任务队列和事件循环两个 console.log(myData);是同步执行的,他们都在js的主线程上执行,在主线程之外还存在一个任务队列,任务队列中存放着需要异步执行的内容当主线程运行完毕之后,就会去执行任务队列中的任务(不断的重复扫描)直到任务队列清空观察这段代码 console.log(1); setTimeout(function () { console.log(2); }, 1000); console.log(3);输出:1,3,2,这没什么可解释的再看一段代码setTimeout(function(){console.log(1);}, 0);console.log(2);输出:2,1,为什么会这样?console.log(2);在主线程中,先执行,setTimeout(function(){console.log(1);}, 0);放在了任务队列中,只有在主线程执行完了才会去执行任务列队中的内容为什么主线程的任务执行完了后需要不断的扫描任务列队中的内容呢?看这段代码,有助于你的理解 console.log(myData); ajax() setTimeout(() => { console.log(‘定时器’); }, 2000); console.log(myData); const btn = document.querySelector(‘button’) btn.onclick = () => { console.log(“点击了”); }我们为button按钮添加了点击事件,在浏览器刷新的同时不停地对按钮进行点击操作(当然是手动点击)看下输出://null//null//(10次输出)点击了//ajax返回成功//{success: true, data: {…}}//定时器//点击了这样是不是可以理解为什么主线程要去循环扫描任务列队了?事件循环的每一轮称为一个tick(有没有联想到vue中的nextTick?)当产生用户交互(鼠标点击事件,页面滚动事件,窗口大小变化事件等等),ajax,定时器,计时器等,会向事件循环中的任务队列添加事件,然后等待执行,前端异步有哪些场景?定时任务:setTimeout,setInverval网络请求:ajax请求,img图片的动态加载事件绑定或者叫DOM事件,比如一个点击事件,我不知道它什么时候点,但是在它点击之前,我该干什么还是干什么。用addEventListener注册一个类型的事件的时候,浏览器会有一个单独的模块去接收这个东西,当事件被触发的时候,浏览器的某个模块,会把相应的函数扔到异步队列中,如果现在执行栈中是空的,就会直接执行这个函数。ES6中的Promise什么时候需要异步:在可能发生等待的情况等待过程中不能像alert一样阻塞程序的时候因此,所有的“等待的情况”都需要异步一句话总结就是需要等待但是又不能阻塞程序的时候需要使用异步异步和并行千万不要把异步和并行搞混了,异步是单线程的,并行是多线程的异步:主线程的任务以同步的方式执行完毕,才会去依次执行任务列队中的异步任务并行:两个或多个事件链随时间发展交替执行,以至于从更高的层次来看,就像是同时在运行(尽管在任意时刻只处理一个事件)原文链接参考链接关于js中的同步和异步异步和单线程——什么时候需要异步,前端使用异步的场景Javascript异步编程的4种方法 ...

January 10, 2019 · 1 min · jiezi

跨域携带cookies无效问题

开发环境:vue,axios 0.17.1,springboot 2.1.1,springsession在本地测试页面时,发现cookies都没有传上去,本地测试是跨域的,原先是正常的。开始以为是axios问题,结果试了XMLHttpRequest也是一样,都已设置withCredentials:true。跨域的请求都能接收和回应,但是请求时cookies都没有携带。看了下set-cookie的值:SESSION=YWFlZTBjY2QtOWE4NC00MmI4LWEwZWEtYjUxYzY2ZjMyN2Nh; Path=/server/; HttpOnly; SameSite=Lax,这里多了个HttpOnly和SameSite,而问题就出在这个SameSite上。(可能是更新到SpringSession2之后导致的)取消SameSite:// SpringSession配置类@EnableRedisHttpSession( maxInactiveIntervalInSeconds = 7200)public class SpringSessionConfig { public SpringSessionConfig() {} @Bean public CookieSerializer httpSessionIdResolver() { DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer(); // 取消samesite cookieSerializer.setSameSite(null); return cookieSerializer; }}ps:chrome的network中看不到跨域的set-cookie标记,也是坑。

January 9, 2019 · 1 min · jiezi

axios请求、和返回数据拦截,统一请求报错提示_012

axios请求、和返回数据拦截,统一请求报错提示官方文档https://github.com/axios/axios 英文文档https://www.kancloud.cn/yunye… 中文文档请求和返回拦截,添加统一的报错信息请求的配置可以通过阅读官方文档来进行配置。axios api也很简介,多看看再自己尝试一下就会了下面是我写的一个在react中的应用,UI用的阿里的Antd 框架,所以报错信息直接用全局弹窗来提示了。比较简陋。写好之后,在写发送请求的文件中引用request 就可以了。import axios from ‘axios’;import { message } from ‘antd’;import NProgress from ’nprogress’;import ’nprogress/nprogress.css’;// 拦截请求// Add a request interceptoraxios.interceptors.request.use( config => { NProgress.start(); return config; }, error => { message.error(‘请求错误,请重试’); return Promise.reject(error); },);//拦截返回数据// Add a response interceptoraxios.interceptors.response.use( response => { NProgress.done(); if (response.data.RetCode === 101) { message.error(response.data.Message); return response; } if (response.data.RetCode === 100) { message.error(response.data.Message); return response; } return response; }, error => { message.error(‘请求错误,请重试’); NProgress.done(); return Promise.reject(error); },);export default request;https://github.com/axios/axios ...

January 2, 2019 · 1 min · jiezi

深入解析Axios 常用的请求方法别名

下面小编就为大家分享一篇Axios 常用的请求方法别名,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。Axios是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。常用的请求方法别名一般有: Get/post/http协议请求执行Get请求function get(){ return axios.get(’/data.json’, { params:{ id:1234 } }).then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });//欢迎加入前端全栈开发交流圈一起学习交流:864305860 }使用get方法进行传参数的时候用的是 params方法执行Post请求function post(){return axios.post(’/data.json’, { id:1234 })//欢迎加入前端全栈开发交流圈一起学习交流:864305860 .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });//欢迎加入前端全栈开发交流圈一起学习交流:864305860 }使用post方法进行传参数的时候是直接进行数据的传递,这也是两种方法的区别。执行http协议请求unction http(){ return axios({ method: ‘post’, url: ‘/data.json’, data: { id: 1111, },params: { id:2222, }).then(res=>{ this.msg=res.data; });//欢迎加入前端全栈开发交流圈一起学习交流:864305860}注意这里的区别,当使用post请求的时候,进行数据的传参使用的是data方法,而使用get请求的时候,使用的是params方法。使用拦截器:在请求或响应被 then 或 catch 处理前拦截它们。// 添加请求拦截器mounted:function(){ axios.interceptors.request.use(function (config) { // 在发送请求之前做些什么 return config; }, function (error) { // 对请求错误做些什么 return Promise.reject(error); });// 添加响应拦截器 axios.interceptors.response.use(function (response) { // 对响应数据做点什么 return response; }, function (error) { // 对响应错误做点什么 return Promise.reject(error); });//欢迎加入前端全栈开发交流圈一起学习交流:864305860}结语感谢您的观看,如有不足之处,欢迎批评指正。 ...

December 19, 2018 · 1 min · jiezi

解析Node.js通过axios实现网络请求

本次给大家分享一篇node.js通过axios实现网络请求的方法,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。1、使用Npm 下载axios npm install –save axiosvar update_url = axios.create({ baseURL:‘debug url’});update_url.get(’/debug url’).then(function (response){ //response 就是请求url 返回的内容}//欢迎加入前端全栈开发交流圈一起学习交流:864305860上述的方法请求文件时候,body的默认格式不是form-data。因此我们需要请求的数据格式为form-data的时候,需要使用下面的库 requestnpm install –save request2、request 请求url,可以使用get,post的方式.request.post({url:‘http://192.168.1.159/backup/client/interface1s.php?func=getMusicPath’,formData:{musicname:task.name}},function optionalCallback(err,httpResponse,body){ //body为url反馈回来的数据,}//欢迎加入前端全栈开发交流圈一起学习交流:864305860结语感谢您的观看,如有不足之处,欢迎批评指正。

December 18, 2018 · 1 min · jiezi

VUE跨域问题

vue-cli项目中,解决跨域问题。在config > index.js 文件中的proxyTable里边添加’/api’配置proxyTable: { ‘/api’: { // 跨域域名 target: ‘http://www.xxxxx.cn’, // 是否跨域 changeOrigin: true, pathRewrite: { ‘^/api’: ’’ } }},在vue组件中使用methods: { // 加载数据 getUserInfo () { this.$axios.get(‘api/mall/servlet/json?funcNo=3040’) // this.$axios.get(‘http://www.xxxxx.cn/mall/servlet/json?funcNo=3040') .then(this.handleGetUserInfoSucc) .catch(error => console.log(error)) }} 需要重新运行项目,不然会报错重新运行项目后本地开发就不会出现跨域问题了。当项目打包,放到服务器上,会报错Failed to load resource: the server responded with a status of 404 (Not Found)开发的时候用的dev_server只针对开发用的,打包后dev_server这块配置的请求代理已经无效。这时直接将域名放到get中,打包放到服务器methods: { // 加载数据 getUserInfo () { // this.$axios.get(‘api/mall/servlet/json?funcNo=3040’) this.$axios.get(‘http://www.xxxxx.cn/mall/servlet/json?funcNo=3040') .then(this.handleGetUserInfoSucc) .catch(error => console.log(error)) }}

December 18, 2018 · 1 min · jiezi

PC端微信内置浏览器vue axios没发出去请求

PC端微信内置浏览器vue axios没发出去请求,仅做记录今天测试同学 测活动的时候 在windows下面的微信内邮件扫描二维码 竟然使用内置浏览器测了起来。还有这种骚操作??? 之前的测试从来没测过这个浏览器,据说是腾讯使用的比较老的chrome内核果然有问题。通过抓包得知请求都没发出去,于是我就在axios里面一步一步手动做console 通过变量写入到页面最后拦截器里面看到了includes,随便不抱希望的改了一下,没想到请求发出去了,这么说来应该是babel的版本没有转换includes导致的,也有可能是转换了微信浏览器还是不支持。最终自己重写了includes,得以解决

December 14, 2018 · 1 min · jiezi

记一次获取QQ音乐播放源链接地址

目标链接:https://y.qq.com/portal/playe…分析network 发现一个请求:双击打开发现就是歌曲播放源地址紫棋小姐姐唱歌真好听记住这个链接,并且多打开几个试一试,以便进行对比找出规律。链接比较找规律经过一波分析,对比几个数据,容易找出链接的构成。http://dl.stream.qqmusic.qq.com/C400${songmid}.m4a?guid=3878307950&vkey=${vkey}&uin=0&fromtag=66用了模板字符串的语法,可见<font color=“red”>songmid</font>、<font color=“red”>vkey</font>是可变参数,guid、uin、fromtag是固定参数。那我们的目标就指向抓取到含这两个数据的接口数据了。经过一番寻找,晃眼一撇:咦? 这不就是vkey嘛。赶紧结合代码一把梭。我就知道没那么轻松。不多截图,正确答案确实是在那个接口里,但是对于我们的目的来说,这里的数据有很多是很相似且冗余的。最终总算还是找到了可以组合的正确通用链接:红色的两个可以组合,黄色的单个也可以。往下所述是用的黄色框的,因为更方便,不用单独找vkey、songmid来拼接url了。请求正确链接数据正确的链接找到了,接下来就要在本地写代码请求数据了。我们来分析下那个链接的headers咋一看貌似可以利用jsonp。贴主要代码确实请求到数据了。只是…估计服务端做了某些限制…既然jsonp行不通,那就后端接口代理、用axios来搞。代码太繁琐,不好贴,就贴个代理吧,思路就是这样子。这是经过处理后的数据结构,抓取到的播放源链接就是如下蓝色框。迄今,经测试是正确的是链接地址。若有意见与建议,请多指教~

December 12, 2018 · 1 min · jiezi

使用API自动生成工具优化前端工作流

在工作中,我们的前端工作流一般开始于前后端协商好Api文档之后,再针对这个Api文档做mock模拟数据,然后用做好的mock进行开发,后端开发完毕之后再改一下API数据的BaseURL切换到正式API进行联调;如下本文介绍的一个工具(或者说方法),来将这个工作流优化一下,也是我平时工作正在用的方法,当做自己的笔记,也跟大家一起分享一下这个方法的主要思路就是开发人员在某个api工具中按要求填好文档,然后导出swagger.json配置文件,再把这个配置文件导入到easy-mock中,再用工具自动生成前端api的js文件以供调用。本文中所使用的工具:sosoApi、Easy-mock、Swagger、Easy-mock-api-template、axios1. 使用Api管理平台导出swagger.json文件一般我们前后端通过各种平台或者工具来管理Api,比如免费的可视化Api管理平台 sosoApi、Yapi等,一般来说这些工具都可以生成swagger.json的Api,我们可以用它来直接生成一个漂亮的可视化Api文档,也可以用它来作为配置文件导入其他工具中,比如Easy-mock;比如在sosoApi中就可以导出为swagger文档(swagger.json):我们先导出一个swagger.json备用;2. 使用swagger.json导入easy-mockMock平台我们可以使用Easy-mock,轻量又简洁,虽然没有Api的分组功能,但平时应付应付不太大的应用、个人应用等场景足够了;Easy-mock官网的服务被不少人直接拿到开发环境用,经常被挤爆,这个情况可以用本地部署来解决这个问题,参考 windows本地安装部署 Easy Mock 。我们将Api管理平台中导出的swagger.json文件在新建project的时候导入:这样刚刚Api平台中配置的Api就被同步到我们的Easy-mock配置中了,比如sosoApi的示例项目导出的结果就是:这时我们就可以用它来进行数据mock了,怎么样,是不是很轻松easy-mock项目面板上面会有个 Project ID,这个记下来后面要用;3. 使用easy-mock-cli生成js格式Api有了easy-mock之后一般情况下我们要写前端的api文件了,一般api工具用axios,这里提供一个封装:// utils/fetch.jsimport axios from ‘axios’ const service = axios.create({ baseURL: ‘https://easy-mock.com/project/5bf6a23c92b5d9334494e884', timeout: 5000}) // request拦截器service.interceptors.request.use( config => {…}, err => {…}) // respone拦截器service.interceptors.response.use( res => {…}, err => {…}) export default service我们可以用easy-mock-cli来生成api,模板文件如果不想用原来的模板的话,可以使用我fork之后改写的一个模板easy-mock-api-template,生成的Api文件是这样的:// api/index.jsimport fetch from ‘utils/fetch’; /* 活动查询 /const activityQuery = ({ activityDate }) => fetch({ method: ‘get’, url: ‘/activity/query’, params: { activityDate }}); /* 活动保存 /const activitySave = () => fetch({ method: ‘post’, url: ‘/activity/save’}); /* 活动提交 */const activitySubmit = ({ activityId, content }) => fetch({ method: ‘post’, url: ‘/activity/submit’, data: { activityId, content }}); export { activityQuery, // 活动查询 activitySave, // 活动保存 activitySubmit // 活动提交};然后在文件中就可以:import * as Api from ‘api/index.js’; // 调用Api.activitySubmit({ activityId: 2 }) .then(…)简单介绍一下配置文件,更复杂的配置要参考原来的文档;// .easy-mock.js 配置文件 { host: ‘http://localhost:8080/’, // easy-mock的源,没有本地部署的话不用写,本地部署则填本地服务地址 output: “../”, // 生成 API 的基础目录 template: “../”, // 指定模板,这里用本地写的模板 projects: [ // 可以有多个模板来源 { “id”: “你要创建的 Easy Mock 项目的 id”, // 刚刚记下来的 Project ID “name”: “api” // 生成的output目录下的文件名 } ]}然后npm run create-api就可以在根目录下生成一个api/index.js文件了网上的帖子大多深浅不一,甚至有些前后矛盾,在下的文章都是学习过程中的总结,如果发现错误,欢迎留言指出参考:用swagger.json自动生成axios api访问代码 - 简书Easy-mock-cli/README.md推介阅读:windows本地安装部署 Easy Mock - 掘金 ...

November 23, 2018 · 1 min · jiezi

vue axios拦截器介绍

axios的拦截器是一个作用非常大,非常好用的东西。分为请求拦截器和相应拦截器两种。我一般把拦截器写在main.js里。1. 请求拦截器请求拦截器的作用是在请求发送前进行一些操作,例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易。axios.interceptors.request.use(function (config) { // 在发送请求之前做些什么,例如加入token ……. return config; }, function (error) { // 对请求错误做些什么 return Promise.reject(error); });2. 响应拦截器响应拦截器的作用是在接收到响应后进行一些操作,例如在服务器返回登录状态失效,需要重新登录的时候,跳转到登录页。axios.interceptors.response.use(function (response) { // 在接收响应做些什么,例如跳转到登录页 …… return response; }, function (error) { // 对响应错误做点什么 return Promise.reject(error); });3. 移除拦截器var myInterceptor = axios.interceptors.request.use(function () {/…/});axios.interceptors.request.eject(myInterceptor);4. 为axios实例添加拦截器var instance = axios.create();instance.interceptors.request.use(function () {/…/});拦截器真的非常重要非常好用~

November 12, 2018 · 1 min · jiezi

vue axios请求频繁时取消上一次请求

一、前言在项目中经常有一些场景会连续发送多个请求,而异步会导致最后得到的结果不是我们想要的,并且对性能也有非常大的影响。例如一个搜索框,每输入一个字符都要发送一次请求,但输入过快的时候其实前面的请求并没有必要真的发送出去,这时候就需要在发送新请求的时候直接取消上一次请求。二、代码<script>import axios from ‘axios’import qs from ‘qs’export default { methods: { request(keyword) { var CancelToken = axios.CancelToken var source = CancelToken.source() // 取消上一次请求 this.cancelRequest(); axios.post(url, qs.stringify({kw:keyword}), { headers: { ‘Content-Type’: ‘application/x-www-form-urlencoded’, ‘Accept’: ‘application/json’ }, cancelToken: new axios.CancelToken(function executor(c) { that.source = c; }) }).then((res) => { // 在这里处理得到的数据 … }).catch((err) => { if (axios.isCancel(err)) { console.log(‘Rquest canceled’, err.message); //请求如果被取消,这里是返回取消的message } else { //handle error console.log(err); } }) }, cancelRequest(){ if(typeof this.source ===‘function’){ this.source(‘终止请求’) } }, }}</script>三、结语这样就可以成功取消上一次请求啦!真的非常好用~ ...

November 11, 2018 · 1 min · jiezi

Vue基于vuex、axios拦截器实现loading效果及axios的安装配置

准备利用vue-cli脚手架创建项目进入项目安装vuex、axios(npm install vuex,npm install axios)axios配置项目中安装axios模块(npm install axios)完成后,进行以下配置: main.js//引入axiosimport Axios from ‘axios’//修改原型链,全局使用axios,这样之后可在每个组件的methods中调用$axios命令完成数据请求Vue.prototype.$axios=Axios loading组件我这里就选择使用iview提供的loading组件,npm install iviewmain.jsimport iView from ‘iview’;import ‘iview/dist/styles/iview.css’;Vue.use(iView);安装引入后,将loading写成一个组件loading.vueVuex state状态设置控制loading的显隐store.js(Vuex)export const store = new Vuex.Store({ state:{ isShow:false }})在state中定义isShow属性,默认false隐藏v-if=“this.$store.state.isShow"为loading组件添加v-if绑定state中的isShow组件使用axios请求数据<button @click=“getData”>请求数据</button>methods:{ getData(){ this.$axios.get(‘https://www.apiopen.top/journalismApi') .then(res=>{ console.log(res)//返回请求的结果 }) .catch(err=>{ console.log(err) }) } }我这里使用一个按钮进行触发事件,利用get请求网上随便找的一个api接口,.then中返回请求的整个结果(不仅仅包括数据)Axios拦截器配置main.js//定义一个请求拦截器Axios.interceptors.request.use(function(config){ store.state.isShow=true; //在请求发出之前进行一些操作 return config})//定义一个响应拦截器Axios.interceptors.response.use(function(config){ store.state.isShow=false;//在这里对返回的数据进行处理 return config})分别定义一个请求拦截器(请求开始时执行某些操作)、响应拦截器(接受到数据后执行某些操作),之间分别设置拦截时执行的操作,改变state内isShow的布尔值从而控制loading组件在触发请求数据开始时显示loading,返回数据时隐藏loading特别注意:这里有一个语法坑(我可是来来回回踩了不少次)main.js中调取、操作vuex state中的数据不同于组件中的this.$store.state,而是直接store.state 同上面代码效果展示本文作者:茅野zhy博客链接:www.zhysama.xyz版权声明: 该文章由博主编辑 , 转发请注明出处谢谢!

September 5, 2018 · 1 min · jiezi