国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - vue.js - 如何在Vue項目中添加接口監聽遮罩

如何在Vue項目中添加接口監聽遮罩

2022-01-07 16:18RiverTT vue.js

這篇文章主要介紹了如何在Vue項目中添加接口監聽遮罩,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

一、業務背景

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

二、問題分析

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

三、組件設計

1、遮罩層出現和關閉的時機

該問題根據不同業務需求決定,但是筆者認為,大部分遮罩的出現和關閉主要取決于接口的請求和返回,一個接口在請求pending狀態下,顯示遮罩層,所有接口返回則關閉遮罩。本文主要解決的是接口請求遮罩問題,使用ts進行編寫,且并不會羅列所有細節。

2、Mask組件設計

Mask組件為一個class,將細節屏蔽在class內部。
(1)class內部最主要功能為添加和刪除遮罩層,傳輸的當前請求接口的url。

?
1
2
3
4
5
6
7
class Mask {
 // 顯示遮罩層
 appendMask(url: string): void{}
 
 // 刪除遮罩層
 removeMaskl(url: string): void{}
}

(2)添加遮罩層函數,請求時調用該函數,傳入當前接口url。函數內部維護一個監聽對象,用以監聽當前是否存在pending狀態的請求。該對象的value為該接口pending狀態的數量。通過假設遮罩視圖組件已經掛載到了Vue原型鏈上,如果沒有,則在組件上方引入即可。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 監聽對象數據類型定義
interface HTTPDictInterface {
 [index: string]: number;
}
 
appendMask(url: string): void{
 
 if(!this.monitorHTTPDict[url]){
 this.monitorHTTPDict[url] = 0;
 }
 this.monitorHTTPDict[url] += 1;
 
 // 如果存在監聽接口,則顯示遮罩層
 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)刪除遮罩層函數,每次請求結束之后都會調用該函數,當發現請求監聽對象為空時,刪除的遮罩層。如果沒有pending狀態的接口,刪除該對接的key。該對象為空且有遮罩層的情況下,刪除遮罩層。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
removeMask(url: string): void{
 
 // 成功返回后
 if (this.monitorHTTPDict[monitorUrl]) {
 this.monitorHTTPDict[monitorUrl] -= 1;
 if (this.monitorHTTPDict[monitorUrl] <= 0) {
 delete this.monitorHTTPDict[monitorUrl];
 }
 }
 
 // hasMask用以檢測頁面是否存在遮罩層標簽元素
 if (this.mask && this.hasMask() && !Object.keys(this.monitorHTTPDict).length) {
 document.body.removeChild(this.mask.$el);
 this.mask = null;
 }
 
 this.timer = null;
}

3、該組件如何優雅的引入到項目中,不產生耦合。

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

?
1
2
3
4
5
6
7
instance.interceptors.request.use((config) => {
 
 // 添加遮罩層
 mask.appendMask(config.url);
 
 return config;
});

(2)添加init函數,直接在原生XMLHttpRequest對象中注入回調。更改原生XMLHttpRequest函數,在事件'loadstart'和'loadend'中注入回調,需要注意的是,loadstart接收的傳參中,并沒有當前請求的url,所以還需要改寫open函數,把open接收傳參的url掛載到新的xhr對象上。慎用該方法。因為更改原生API的方式十分危險,在很多編碼規范中是禁止的,如果所有人都對原生API進行改寫,當同時引入這些框架會產生沖突,造成無法意料的后果。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// 通過傳參來決定是否使用該方法
 
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,編碼規范不允許修改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)注入使用方式,直接調用init。這樣改項目的所有請求都會經過Mask。

?
1
new Mask().init()

4、如何在已有的項目中,漸進式的更換原有的maskShow的方式,從而不造成大面積問題。

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

?
1
2
3
4
5
6
7
8
9
// key需要監聽的路由頁面,value為一個數組,數組中填寫的接口為黑名單,不需要監聽的接口
const PAGE_ONE = `/home`;
const PAGE_TWO = `/login`;
const HTTO_ONE = `xxx`
 
export const maskUrlList = {
 [PAGE_ONE]: [HTTO_ONE],
 [PAGE_TWO]: [],
};

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
appendMask(url: string): void{
 
 // 獲取當前頁面的path,獲取頁面路徑,根據hash和history模式進行區分
 const monitorPath: string = this.getMonitorPath();
 
 // maskUrlList為配置項,先檢查頁面路由,之后檢查是否存在黑名單
 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、細節問題

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
// 清理遮罩層
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模式下的‘#',

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 獲取請求接口的url
getMonitorUrl(url: string): string{
 const urlIndex: number = url.indexOf(`?`);
 let monitorUrl: string = url;
 if (urlIndex !== -1) {
 monitorUrl = url.substring(0, urlIndex);
 }
 return monitorUrl;
}
// 獲取當前路由path
getMonitorPath(): 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);
 }
 
 // 截圖路徑,刪除請求參數
 const hashIndex: number = monitorPath.indexOf(`?`);
 
 if (hashIndex !== -1) {
 monitorPath = monitorPath.substring(0, hashIndex);
 }
 
 return monitorPath;
}

(3)接口過濾baseUrl。細心的話,會發現在使用axios的接口時,自行決定是否帶入baseUrl,那是因為axios會在請求時進行區分過濾。如果項目前期并沒有很好的定義使用方式的話,會有兩種不同使用axios的方式。那么,就需要對baseUrl進行過濾。

?
1
2
3
4
5
6
7
// 去除baseUrl
cleanBaseUrl(fullUrl: string): string {
 
 const baseUrlLength: number = this.baseUrl.length;
 return fullUrl.substring(baseUrlLength);
 
}

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

?
1
2
3
4
5
6
7
new Mask({
 modeType, // hash或history
 autoMonitoring, // 是否更寫原生XMLHttpRequest對象
 maskUrlList, // 配置引入的頁面和接口
 baseUrl, // 當前項目的baseUrl
 ...
}).init()

四、總結

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

到此這篇關于如何在Vue項目中添加接口監聽遮罩的文章就介紹到這了,更多相關Vue 接口監聽遮罩內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://juejin.cn/post/6921014472811380743

延伸 · 閱讀

精彩推薦
  • vue.jsVue項目中實現帶參跳轉功能

    Vue項目中實現帶參跳轉功能

    最近做了一個手機端系統,其中遇到了父頁面需要攜帶參數跳轉至子頁面的問題,現已解決,下面分享一下實現過程,感興趣的朋友一起看看吧...

    YiluRen丶4302022-03-03
  • vue.jsVue2.x-使用防抖以及節流的示例

    Vue2.x-使用防抖以及節流的示例

    這篇文章主要介紹了Vue2.x-使用防抖以及節流的示例,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下...

    Kyara6372022-01-25
  • vue.jsVue2.x 項目性能優化之代碼優化的實現

    Vue2.x 項目性能優化之代碼優化的實現

    這篇文章主要介紹了Vue2.x 項目性能優化之代碼優化的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    優小U9632022-02-21
  • vue.js用vite搭建vue3應用的實現方法

    用vite搭建vue3應用的實現方法

    這篇文章主要介紹了用vite搭建vue3應用的實現方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下...

    Asiter7912022-01-22
  • vue.jsVue多選列表組件深入詳解

    Vue多選列表組件深入詳解

    這篇文章主要介紹了Vue多選列表組件深入詳解,這個是vue的基本組件,有需要的同學可以研究下...

    yukiwu6752022-01-25
  • vue.js詳解vue 表單綁定與組件

    詳解vue 表單綁定與組件

    這篇文章主要介紹了vue 表單綁定與組件的相關資料,幫助大家更好的理解和學習使用vue框架,感興趣的朋友可以了解下...

    Latteitcjz6432022-02-12
  • vue.jsVue中引入svg圖標的兩種方式

    Vue中引入svg圖標的兩種方式

    這篇文章主要給大家介紹了關于Vue中引入svg圖標的兩種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的...

    十里不故夢10222021-12-31
  • vue.js梳理一下vue中的生命周期

    梳理一下vue中的生命周期

    看過很多人講vue的生命周期,但總是被繞的云里霧里,尤其是自學的同學,可能js的基礎也不是太牢固,聽起來更是吃力,那我就已個人之淺見,以大白話...

    CRMEB技術團隊7992021-12-22
主站蜘蛛池模板: 91av精品 | 国产 欧美 日韩一区 | 午夜国产 | 久久精彩| 超黄网站在线观看 | 午夜精品久久 | 综合久久久久 | 国产噜噜噜噜噜久久久久久久久 | 色就是色网站 | 国产精品美女久久久久久久久久久 | h在线免费 | 正在播放国产精品 | 国产欧美精品区一区二区三区 | 久久久久久久久久久久一区二区 | 伊人青青草 | 久久中文字幕一区二区 | 欧美日韩国产一区二区三区 | 精品天堂 | 日韩1区| 久久久久久久久久久精 | 国产高清自拍视频 | 国产精品亚洲综合 | 久草社区 | 五月婷婷在线观看 | 欧美激情综合网 | 有码在线 | 日韩国产精品一区二区三区 | 韩国成人精品a∨在线观看 欧美精品综合 | 日本不卡一区二区三区在线观看 | 日韩精品免费视频 | 日韩精品视频在线观看一区二区 | 一级免费视频 | 国产色毛片 | 欧美一级免费 | 三区在线 | 国产精品一级毛片在线 | 黄网站色 | 亚洲视频一区在线 | 日韩欧美精品在线 | 国产精品国产精品国产专区不片 | 精品久久网 |