今天程序猿節,祝大家永無bug
昨天接了個功能,已知有一個input
類型爲password
,在修改內容的時候也是密文展示,但是用戶還是覺得不安全,因爲可以在f12
下找到dom並直接修改input
的type
從而直接使其明文展示
wtf? 真有這麼不當人的用戶咩??
後來想了個辦法,頁面上展示的是基於此變量的計算屬性比如computedStr
,然後頁面上的展示本質上就是這個計算屬性的值:
<el-input
v-model="passwordComputed"
type="password"
id="pswId"
style="border:1px solid red"
:clearable="dialogBtn !== 'preview'"
:readonly="dialogBtn == 'preview'"
/>
隨後在計算屬性裏寫上它的邏輯,由於它是v-model
因而要使用comp的get
&set
// computed
passwordComputed: {
get() {
const basePasswordLen = baseMsg; //這個是該計算屬性依賴的源數據 已脫敏
console.log("basePasswordLen :>> ", basePasswordLen);
let encryptedStr = ``;
for (let index = 0; index < basePasswordLen.length; index++) {
encryptedStr += `•`;
}
return encryptedStr; // 當僅展示時,返回一堆`*`號,這樣用戶修改type也不怕啦,因爲它本質上就是`*`
},
set(newVal) {
// 雙向綁定的是計算屬性,
// const basePasswordLen = baseMsg; //這個是該計算屬性依賴的源數據 已脫敏
// const prePsdLen = basePasswordLen.length; // 上一次的數據
// const psdEle = document.getElementById("pswId");
// console.log("psdEle :>> ", psdEle);
// if (!newVal) { //如果是新值是空字符,則將原值賦空
// baseMsg = ``;
// return;
// }
// // 如果小於原值,說明是刪除動作
// if (newVal.length < prePsdLen) {
// 刪減動作
// } else {
// const { resultVal, startIndex, filterText } = this.filterNewValue(
// newVal,
// basePasswordLen
// );
// baseMsg = resultVal; //將計算後的數據反賦給真正的變量
// 這時候光標會異常,因爲上一行是整體賦值操作而不是新增操作,因而必須要重新設置下光標
// this.$nextTick(() => {
// psdEle.focus(); // 重新獲取焦點
// console.log(" psdEle.selectionStart :>> ", psdEle.selectionStart);
// selectionStart與selectionEnd是同一值時,顯示光標所在所有,不同值時,中間的差值就是選中態
// psdEle.selectionStart = psdEle.selectionEnd =
// startIndex + filterText.length + 1; // 重新設置光標 這一點非常重要,因爲此input不允許明文查看,因而光標的位置就很關鍵。 模仿光標正常input下輸入態 這裏其實還要加`1`,舉個例子,假設輸入了四個字符,那麼光標其實應該在第四位索引上
// });
// }
}
}
在新增動作裏,添加對數據的計算
// methods
// 數據清洗-》獲取輸入的數據和數據的第一個的下標
filterNewValue(nv, ov) {
let filterText = "";
let startIndex = null;
for (let index = 0; index < nv.length; index++) {
if (nv[index] !== `•`) {
filterText += nv[index];
if (startIndex === null) {
startIndex = index;
}
}
}
const resultVal = this.insertStringAt(ov, filterText, startIndex);
return {
resultVal,
startIndex,
filterText
};
},
// 此處計算用戶本次輸入後的明文數據(包含所有)
insertStringAt(originalString, stringToInsert, insertionIndex) {
if (insertionIndex < 0) {
insertionIndex = 0;
}
if (insertionIndex > originalString.length) {
insertionIndex = originalString.length;
}
const part1 = originalString.slice(0, insertionIndex);
const part2 = originalString.slice(insertionIndex);
return part1 + stringToInsert + part2;
},
終於寫完了,擦擦腦門汗,發現有一個大問題,我可以監聽用戶修改條目時的新增,無論他在開頭結尾或中間,但是我卻無法監聽它的刪減,準確的說,無法監聽它刪減時對應的數據和下標。
因爲:passwordComputed
的值是一個基於base數據的***
,所以在刪減這個數據的時候拿到的新值也只是**
眼前真的一黑...
狠狠抽了一口空氣,突然想明白了一件事:當前需求是希望用戶不要在f12時修改dom,那麼我們就可以以此爲切入點:
網上的案例是當用戶打開f12時直接debugger:
mounted(){
// 監聽用戶f12時,直接debugger;可以但不該
((function () {
var callbacks = [],
timeLimit = 50,
open = false;
var str = /x/
str.toString = function () {
window.clearInterval = function () {
return '不能使用清除定時器了'
}
}
setInterval(loop, 1);
return {
addListener: function (fn) {
callbacks.push(fn);
},
cancleListenr: function (fn) {
callbacks = callbacks.filter(function (v) {
return v !== fn;
});
},
};
function loop() {
var startTime = new Date();
debugger;
if (new Date() - startTime > timeLimit) {
if (!open) {
callbacks.forEach(function (fn) {
fn.call(null);
});
}
open = true;
window.stop();
console.log(str)
window.location.reload();
} else {
open = false;
}
}
})()).addListener(function () {
window.location.reload();
});
}
這段代碼寫下來,當用戶一打開開發者工具時就直接進入調試態,這太粗暴,太不優雅,本着對用戶負責的態度,於是放棄了這個做法(畢竟我們不能不當人不是)
然後又在想,可不可以直接監聽用戶在按f12對dom修改的動作,於是就找到了mutationObserve
這個api,廢話不說,上代碼
貼貼:
<script>
let observer // 沒用必要將其變成響應式,浪費性能
mounted(){
this.$nextTick(() => {
// 選擇需要觀察變動的節點
const targetNode = document.getElementById("pswId");
// 觀察器的配置(需要觀察什麼變動)
// attributes: 觀察受監視元素的屬性值變更
// childList: 監視目標節點(如果 subtree 爲 true,則包含子孫節點)添加或刪除新的子節點
// subtree: 其他值也會作用於此子樹下的所有節點,而不僅僅只作用於目標節點
const config = { attributes: true, childList: false, subtree: false }; // childList && subtree須設置爲false以節省性能
// 當觀察到變動時執行的回調函數
const callback = function(mutationsList, observer) {
for (let mutation of mutationsList) {
if (mutation.type === "attributes") {
targetNode.type = "password";
// 停止監聽,一定要有這一步,否則頁面將直接卡死!
observer.disconnect(); //關鍵點1
// 隨即重新監聽
observer.observe(targetNode, config); // 關鍵點2
}
}
};
// 創建一個觀察器實例並傳入回調函數
observer = new MutationObserver(callback);
// 以上述配置開始觀察目標節點
observer.observe(targetNode, config);
}
},
beforeDestroy() {
// 停止觀察
observer.disconnect();
},
<script>
tips1: 關鍵點1必須要加,否則將會死循環至瀏覽器崩潰
tips1: 關鍵點2必須要加,否則將不再監聽
其實可以封裝成一個指令以便在整個項目裏使用,不過沒時間(其實就是懶)
以上。