电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

如何在Vue項(xiàng)目中添加接口監(jiān)聽遮罩

瀏覽:12日期:2022-10-09 09:04:09
一、業(yè)務(wù)背景

使用遮罩層來屏蔽用戶的非正常操作,是前端經(jīng)常使用的方式。但是在一些項(xiàng)目中,并沒有對(duì)遮罩層進(jìn)行統(tǒng)一管理,這就會(huì)造成如下的問題:(1)所有的業(yè)務(wù)組件都要引入遮罩層組件,也就是每個(gè).vue業(yè)務(wù)組件,都在template中引入了Mask組件。組件在項(xiàng)目的各個(gè)角落都存在,不利于管理,代碼極度冗余。(2)Mask組件都分散到業(yè)務(wù)的各個(gè)角落,所以控制是否顯示遮罩層的變量也散在業(yè)務(wù)組件中。比如使用maskShow來控制是否展示遮罩層時(shí),一個(gè)較為復(fù)雜的項(xiàng)目中會(huì)產(chǎn)生200+的maskShow變量。(3)maskShow過多且融入在業(yè)務(wù)中,同時(shí)maskShow的變量往往寫在接口的回調(diào)函數(shù)中,經(jīng)常會(huì)出現(xiàn)忘記改變變量的情況,造成遮罩層該顯示和不該顯示的邏輯出錯(cuò)。(4)項(xiàng)目經(jīng)常是在本地調(diào)試,而真實(shí)運(yùn)行卻又在線上,(3)中的問題在本地經(jīng)常無(wú)法驗(yàn)證出。因?yàn)檫@些問題經(jīng)常是在線上網(wǎng)絡(luò)環(huán)境較差的情況出現(xiàn)。如一個(gè)按鈕按完之后,需要等接口返回才能再次點(diǎn)擊,但是本地因?yàn)榉祷厮俣容^快,如果忘記添加遮罩層也不會(huì)有什么問題。但如果是網(wǎng)絡(luò)有問題的線上環(huán)境,就很容易出現(xiàn),且該問題一旦出現(xiàn),很難定位,大大影響工作效率。

二、問題分析

根據(jù)上述的背景,在實(shí)際項(xiàng)目中添加一個(gè)公共的遮罩層組件進(jìn)行管理,就變的十分有意義。經(jīng)過分析,具體需要解決如下問題:(1)遮罩層出現(xiàn)和關(guān)閉的時(shí)機(jī)。(2)Mask組件設(shè)計(jì)。(3)該組件如何優(yōu)雅的引入到項(xiàng)目中,不產(chǎn)生耦合。(4)如何在已有的項(xiàng)目中,漸進(jìn)式的更換原有的maskShow的方式,從而不造成大面積問題。(5)細(xì)節(jié)問題

三、組件設(shè)計(jì)1、遮罩層出現(xiàn)和關(guān)閉的時(shí)機(jī)

該問題根據(jù)不同業(yè)務(wù)需求決定,但是筆者認(rèn)為,大部分遮罩的出現(xiàn)和關(guān)閉主要取決于接口的請(qǐng)求和返回,一個(gè)接口在請(qǐng)求pending狀態(tài)下,顯示遮罩層,所有接口返回則關(guān)閉遮罩。本文主要解決的是接口請(qǐng)求遮罩問題,使用ts進(jìn)行編寫,且并不會(huì)羅列所有細(xì)節(jié)。

2、Mask組件設(shè)計(jì)

Mask組件為一個(gè)class,將細(xì)節(jié)屏蔽在class內(nèi)部。(1)class內(nèi)部最主要功能為添加和刪除遮罩層,傳輸?shù)漠?dāng)前請(qǐng)求接口的url。

class Mask { // 顯示遮罩層 appendMask(url: string): void{} // 刪除遮罩層 removeMaskl(url: string): void{}}

(2)添加遮罩層函數(shù),請(qǐng)求時(shí)調(diào)用該函數(shù),傳入當(dāng)前接口url。函數(shù)內(nèi)部維護(hù)一個(gè)監(jiān)聽對(duì)象,用以監(jiān)聽當(dāng)前是否存在pending狀態(tài)的請(qǐng)求。該對(duì)象的value為該接口pending狀態(tài)的數(shù)量。通過假設(shè)遮罩視圖組件已經(jīng)掛載到了Vue原型鏈上,如果沒有,則在組件上方引入即可。

// 監(jiān)聽對(duì)象數(shù)據(jù)類型定義interface HTTPDictInterface { [index: string]: number;}appendMask(url: string): void{ if(!this.monitorHTTPDict[url]){ this.monitorHTTPDict[url] = 0; } this.monitorHTTPDict[url] += 1; // 如果存在監(jiān)聽接口,則顯示遮罩層 if(!this.mask && Object.keys(this.monitorHTTPDict).length){ // 在body上添加遮罩層樣式,$Mask為遮罩層樣式組件 const Constructor = Vue.extend(Vue.prototype.$Mask); this.mask = new Constructor().$mount(); document.body.appendChild(this.mask.$el); }}

(3)刪除遮罩層函數(shù),每次請(qǐng)求結(jié)束之后都會(huì)調(diào)用該函數(shù),當(dāng)發(fā)現(xiàn)請(qǐng)求監(jiān)聽對(duì)象為空時(shí),刪除的遮罩層。如果沒有pending狀態(tài)的接口,刪除該對(duì)接的key。該對(duì)象為空且有遮罩層的情況下,刪除遮罩層。

removeMask(url: string): void{ // 成功返回后 if (this.monitorHTTPDict[monitorUrl]) { this.monitorHTTPDict[monitorUrl] -= 1; if (this.monitorHTTPDict[monitorUrl] <= 0) { delete this.monitorHTTPDict[monitorUrl]; } } // hasMask用以檢測(cè)頁(yè)面是否存在遮罩層標(biāo)簽元素 if (this.mask && this.hasMask() && !Object.keys(this.monitorHTTPDict).length) { document.body.removeChild(this.mask.$el); this.mask = null; } this.timer = null;}3、該組件如何優(yōu)雅的引入到項(xiàng)目中,不產(chǎn)生耦合。

使用該組件,需要在所有的請(qǐng)求發(fā)起之前調(diào)用appendMask函數(shù),所有的請(qǐng)求結(jié)束之后調(diào)用removeMask函數(shù)。這就有如下兩種調(diào)用方式。(1)使用axios等組件的回調(diào),完成函數(shù)調(diào)用。但是這種做法并沒有將Mask組件的代碼獨(dú)立于項(xiàng)目,它依賴于具體接口框架的API。

instance.interceptors.request.use((config) => { // 添加遮罩層 mask.appendMask(config.url); return config;});

(2)添加init函數(shù),直接在原生XMLHttpRequest對(duì)象中注入回調(diào)。更改原生XMLHttpRequest函數(shù),在事件’loadstart’和’loadend’中注入回調(diào),需要注意的是,loadstart接收的傳參中,并沒有當(dāng)前請(qǐng)求的url,所以還需要改寫open函數(shù),把open接收傳參的url掛載到新的xhr對(duì)象上。慎用該方法。因?yàn)楦脑鶤PI的方式十分危險(xiǎn),在很多編碼規(guī)范中是禁止的,如果所有人都對(duì)原生API進(jìn)行改寫,當(dāng)同時(shí)引入這些框架會(huì)產(chǎn)生沖突,造成無(wú)法意料的后果。

// 通過傳參來決定是否使用該方法init(){ if (this.autoMonitoring){ this.initRequestMonitor(); }}// 新的xmlhttprequest類型interface NewXhrInterface extends XMLHttpRequest{ requestUrl?: string}// 原生注入initRequestMonitor(): void{ let OldXHR = window.XMLHttpRequest; let maskClass: Mask = this; // @ts-ignore,編碼規(guī)范不允許修改XMLHttpRequest window.XMLHttpRequest = function () { let realXHR: NewXhrInterface = new OldXHR(); let oldOpen: Function = realXHR.open; realXHR.open = (...args: (string | boolean | undefined | null)[]): void => { realXHR.requestUrl = (args[1] as string); oldOpen.apply(realXHR, args); }; realXHR.addEventListener(`loadstart`, () => { const requestUrl: string = (realXHR.requestUrl as string); const url: string = maskClass.cleanBaseUrl(requestUrl); // 開啟遮罩 maskClass.appendMask(url); }); realXHR.addEventListener(`loadend`, () => { const responseURL: string = (realXHR as XMLHttpRequest).responseURL; const url: string = maskClass.cleanBaseUrl(responseURL); // 刪除遮罩 maskClass.removeMask(url); }); return realXHR; };}

(3)注入使用方式,直接調(diào)用init。這樣改項(xiàng)目的所有請(qǐng)求都會(huì)經(jīng)過Mask。

new Mask().init()4、如何在已有的項(xiàng)目中,漸進(jìn)式的更換原有的maskShow的方式,從而不造成大面積問題。

如果直接在全項(xiàng)目中使用,牽扯的面積就會(huì)變得很廣,會(huì)大面積的產(chǎn)生問題,反而得不償失。所以應(yīng)該采取一種漸進(jìn)更換的方式,做到平滑過渡。主要思路是通過配置頁(yè)面和黑名單的方式,來決定哪些頁(yè)面引入該組件,從而讓每個(gè)組員自己修改,畢竟頁(yè)面的負(fù)責(zé)人才是最了解當(dāng)前頁(yè)面業(yè)務(wù)的人。至于如何黑名單還是白名單,則由項(xiàng)目的具體業(yè)務(wù)決定。

// key需要監(jiān)聽的路由頁(yè)面,value為一個(gè)數(shù)組,數(shù)組中填寫的接口為黑名單,不需要監(jiān)聽的接口const PAGE_ONE = `/home`;const PAGE_TWO = `/login`;const HTTO_ONE = `xxx`export const maskUrlList = { [PAGE_ONE]: [HTTO_ONE], [PAGE_TWO]: [],};

appendMask方法過濾黑名單和沒有配置的頁(yè)面。maskUrlList為控制的對(duì)象,先檢查頁(yè)面路由,之后檢查是否存在黑名單。

appendMask(url: string): void{ // 獲取當(dāng)前頁(yè)面的path,獲取頁(yè)面路徑,根據(jù)hash和history模式進(jìn)行區(qū)分 const monitorPath: string = this.getMonitorPath(); // maskUrlList為配置項(xiàng),先檢查頁(yè)面路由,之后檢查是否存在黑名單 if (this.maskUrlList[monitorPath] && !this.maskUrlList[monitorPath].includes(url)) { if (this.monitorHTTPDict[url] === undefined) { this.monitorHTTPDict[url] = 0; } this.monitorHTTPDict[monitorUrl] += 1; } // 添加遮罩層 if (!this.mask && this.hasMonitorUrl()) { const Constructor = Vue.extend(Vue.prototype.$Mask); this.mask = new Constructor().$mount(); document.body.appendChild(this.mask.$el); }}5、細(xì)節(jié)問題

(1)渲染之后才關(guān)閉遮罩層,將實(shí)際刪除遮罩層邏輯放到定時(shí)器中,Vue的異步渲染采用的promise,所以關(guān)閉在如果放在渲染之后,需要放入setTimeout中。這里涉及到事件循環(huán)的知識(shí)。當(dāng)接口返回,如果需要渲染頁(yè)面,則會(huì)異步執(zhí)行一個(gè)Promise,Promise為微任務(wù),setTimeout為宏任務(wù),當(dāng)主線程執(zhí)行完畢后,會(huì)先執(zhí)行微任務(wù),之后才會(huì)執(zhí)行異步的宏任務(wù)setTimeout。

// 清理遮罩層if (!this.timer) { this.timer = window.setTimeout(() => { if (this.mask && this.hasMask() && !this.hasMonitorUrl()) { document.body.removeChild(this.mask.$el); this.mask = null; } this.timer = null; }, 0);}

(2)過濾接口的‘?’,以及hash模式下的‘#’,

// 獲取請(qǐng)求接口的urlgetMonitorUrl(url: string): string{ const urlIndex: number = url.indexOf(`?`); let monitorUrl: string = url; if (urlIndex !== -1) { monitorUrl = url.substring(0, urlIndex); } return monitorUrl;}// 獲取當(dāng)前路由pathgetMonitorPath(): string{ const path: string = this.mode === HASH_TYPE ? window.location.hash : window.location.pathname; let monitorPath: string = path; if (this.mode === HASH_TYPE) { monitorPath = monitorPath.substring(path.indexOf(`#`) + 1); } // 截圖路徑,刪除請(qǐng)求參數(shù) const hashIndex: number = monitorPath.indexOf(`?`); if (hashIndex !== -1) { monitorPath = monitorPath.substring(0, hashIndex); } return monitorPath;}

(3)接口過濾baseUrl。細(xì)心的話,會(huì)發(fā)現(xiàn)在使用axios的接口時(shí),自行決定是否帶入baseUrl,那是因?yàn)閍xios會(huì)在請(qǐng)求時(shí)進(jìn)行區(qū)分過濾。如果項(xiàng)目前期并沒有很好的定義使用方式的話,會(huì)有兩種不同使用axios的方式。那么,就需要對(duì)baseUrl進(jìn)行過濾。

// 去除baseUrlcleanBaseUrl(fullUrl: string): string { const baseUrlLength: number = this.baseUrl.length; return fullUrl.substring(baseUrlLength); }

(4)組件初始化,通過傳入params的方式,將對(duì)象實(shí)例化出來。

new Mask({ modeType, // hash或history autoMonitoring, // 是否更寫原生XMLHttpRequest對(duì)象 maskUrlList, // 配置引入的頁(yè)面和接口 baseUrl, // 當(dāng)前項(xiàng)目的baseUrl ...}).init()四、總結(jié)

本文介紹了統(tǒng)一遮罩層的背景、問題及設(shè)計(jì)方案。但并沒有將所有細(xì)節(jié)進(jìn)行列舉,這需要根據(jù)實(shí)際業(yè)務(wù)進(jìn)行選擇。但大體方案已經(jīng)列出:(1)遮罩層應(yīng)該在一些接口pending裝的時(shí)候顯示,所有接口返回后自動(dòng)關(guān)閉。這里的接口是指需要監(jiān)聽的接口(2)組件最重要的兩個(gè)函數(shù)為appendMask添加遮罩層和removeMask刪除遮罩層。(3)如果想Mask完全獨(dú)立,并不想依賴于第三方庫(kù)(axios)的回調(diào),可以直接對(duì)XMLHttpRequest進(jìn)行改寫,但這樣做風(fēng)險(xiǎn)很大,并不建議。(4)組件更換統(tǒng)一組員自己配置路由及監(jiān)聽接口的方式。這里的邏輯可以自行決定,如果要監(jiān)聽的接口多,可以采用黑名單,反之則白名單。(5)對(duì)渲染的優(yōu)化、請(qǐng)求帶參數(shù)、路由的模式進(jìn)行了優(yōu)化。

到此這篇關(guān)于如何在Vue項(xiàng)目中添加接口監(jiān)聽遮罩的文章就介紹到這了,更多相關(guān)Vue 接口監(jiān)聽遮罩內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Vue
相關(guān)文章:
主站蜘蛛池模板: 水冷散热器_水冷电子散热器_大功率散热器_水冷板散热器厂家-河源市恒光辉散热器有限公司 | 球形钽粉_球形钨粉_纳米粉末_难熔金属粉末-广东银纳官网 | 恒温恒湿试验箱厂家-高低温试验箱维修价格_东莞环仪仪器_东莞环仪仪器 | 小型高低温循环试验箱-可程式高低温湿热交变试验箱-东莞市拓德环境测试设备有限公司 | 并离网逆变器_高频UPS电源定制_户用储能光伏逆变器厂家-深圳市索克新能源 | 中高频感应加热设备|高频淬火设备|超音频感应加热电源|不锈钢管光亮退火机|真空管烤消设备 - 郑州蓝硕工业炉设备有限公司 | 短信群发平台_群发短信软件_短信营销-讯鸽科技 | 防火板_饰面耐火板价格、厂家_品牌认准格林雅 | 陶瓷加热器,履带式加热器-吴江市兴达电热设备厂| 石英陶瓷,石英坩埚,二氧化硅陶瓷-淄博百特高新材料有限公司 | 盘煤仪,盘料仪,盘点仪,堆料测量仪,便携式激光盘煤仪-中科航宇(北京)自动化工程技术有限公司 | 自动气象站_农业气象站_超声波气象站_防爆气象站-山东万象环境科技有限公司 | 黄石东方妇产医院_黄石妇科医院哪家好_黄石无痛人流医院 | 汕头市盛大文化传播有限公司,www.11400.cc | 北京西风东韵品牌与包装设计公司,创造视觉销售力! | 磁力反应釜,高压釜,实验室反应釜,高温高压反应釜-威海自控反应釜有限公司 | 瓶盖扭矩仪(扭力值检测)-百科 | 全温恒温摇床-水浴气浴恒温摇床-光照恒温培养摇床-常州金坛精达仪器制造有限公司 | 不锈钢轴流风机,不锈钢电机-许昌光维防爆电机有限公司(原许昌光维特种电机技术有限公司) | 反渗透水处理设备|工业零排放|水厂设备|软化水设备|海南净水设备--海南水处理设备厂家 | 智成电子深圳tdk一级代理-提供TDK电容电感贴片蜂鸣器磁芯lambda电源代理经销,TDK代理商有哪些TDK一级代理商排名查询。-深圳tdk一级代理 | 实木家具_实木家具定制_全屋定制_美式家具_圣蒂斯堡官网 | 东亚液氮罐-液氮生物容器-乐山市东亚机电工贸有限公司 | 安平县鑫川金属丝网制品有限公司,防风抑尘网,单峰防风抑尘,不锈钢防风抑尘网,铝板防风抑尘网,镀铝锌防风抑尘网 | 新能源汽车电机定转子合装机 - 电机维修设备 - 睿望达 | 单螺旋速冻机-双螺旋-流态化-隧道式-食品速冻机厂家-广州冰泉制冷 | 扒渣机厂家_扒渣机价格_矿用扒渣机_铣挖机_撬毛台车_襄阳永力通扒渣机公司 | 衬氟止回阀_衬氟闸阀_衬氟三通球阀_衬四氟阀门_衬氟阀门厂-浙江利尔多阀门有限公司 | 智慧物联网行业一站式解决方案提供商-北京东成基业 | 减速机三参数组合探头|TSM803|壁挂式氧化锆分析仪探头-安徽鹏宸电气有限公司 | 电子书导航网_电子书之家_电子书大全_最新电子书分享发布平台 | 无锡不干胶标签,卷筒标签,无锡瑞彩包装材料有限公司 | 日本东丽膜_反渗透膜_RO膜价格_超滤膜_纳滤膜-北京东丽阳光官网 日本细胞免疫疗法_肿瘤免疫治疗_NK细胞疗法 - 免疫密码 | 【甲方装饰】合肥工装公司-合肥装修设计公司,专业从事安徽办公室、店面、售楼部、餐饮店、厂房装修设计服务 | 钢托盘,铁托盘,钢制托盘,镀锌托盘,饲料托盘,钢托盘制造商-南京飞天金属13260753852 | 慢回弹测试仪-落球回弹测试仪-北京冠测精电仪器设备有限公司 | 焊缝跟踪系统_激光位移传感器_激光焊缝跟踪传感器-创想智控 | 分子精馏/精馏设备生产厂家-分子蒸馏工艺实验-新诺舜尧(天津)化工设备有限公司 | 塑料撕碎机_编织袋撕碎机_废纸撕碎机_生活垃圾撕碎机_废铁破碎机_河南鑫世昌机械制造有限公司 | 骨密度检测仪_骨密度分析仪_骨密度仪_动脉硬化检测仪专业生产厂家【品源医疗】 | 潍坊青州古城旅游景点攻略_青州酒店美食推荐-青州旅游网 |