溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

vue怎么自定義密碼輸入框解決瀏覽器自動(dòng)填充密碼問題

發(fā)布時(shí)間:2023-04-17 11:18:16 來源:億速云 閱讀:158 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“vue怎么自定義密碼輸入框解決瀏覽器自動(dòng)填充密碼問題”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“vue怎么自定義密碼輸入框解決瀏覽器自動(dòng)填充密碼問題”吧!

    問題描述

    瀏覽器對(duì)于type="password"的輸入框會(huì)自動(dòng)填充密碼,但有時(shí)出于安全或者其他原因,我們不希望瀏覽器記住并自動(dòng)填充密碼。通過網(wǎng)上查到的一些解決方案,可以總結(jié)出以下幾種解決方案(主要用edge瀏覽器進(jìn)行測(cè)試):

    • 通過autocomplete="off"/autocomplete="new-password"來關(guān)閉瀏覽器自動(dòng)填充密碼的功能, 但某些對(duì)于瀏覽器像edge,firfox等,這種方法并不起作用

    • 通過type="text"來解決,當(dāng)focus時(shí),通過js將type="text"改為type="password"。

    <input type="text" onfocus="this.type='password'">

    但同樣對(duì)某些瀏覽器不起作用,如edge,在點(diǎn)擊輸入框時(shí),仍會(huì)自動(dòng)彈出填充密碼的提示框。

    3.某些瀏覽器可能只會(huì)識(shí)別第一個(gè)type="password"的輸入框,所以可以在前面添加一些隱藏的type="password"的輸入框,來解決這個(gè)問題。

    <form >
      <input type="password">
    </form>
    <input type="password" >
    <input type="password">

    但同樣并不是總是有效,拿edge測(cè)試時(shí)即使前幾個(gè)密碼輸入框沒有隱藏,最后一個(gè)輸入框也會(huì)自動(dòng)填充密碼,如圖:

    vue怎么自定義密碼輸入框解決瀏覽器自動(dòng)填充密碼問題

    4.通過readonly屬性來解決,初始化時(shí)將readonly設(shè)置為true,通過setTimeout來延時(shí)設(shè)置readonlyfalse。

    <input id="passwordInput" type="password" readonly>
    setTimeout(() => {
        document.getElementById('passwordInput').removeAttribute('readonly')
    }, 100)

    但同樣并非總是有效,拿edge測(cè)試時(shí),雖然點(diǎn)擊輸入框時(shí)并沒有彈出填充密碼的提示框,但是在輸入框中輸入密碼然后退格到輸入框?yàn)榭諘r(shí),又會(huì)重新彈出填充密碼的提示框。

    上述幾種方法除了會(huì)彈出填充密碼的提示框外,在頁面跳轉(zhuǎn)或刷新時(shí)(如edge瀏覽器),都會(huì)彈出保存密碼的提示框,如圖:

    vue怎么自定義密碼輸入框解決瀏覽器自動(dòng)填充密碼問題

    當(dāng)然,應(yīng)該還會(huì)有其他解決方案我暫時(shí)還沒找到,如果有的話,歡迎留言。

    自定義密碼輸入框組件解決方案

    在嘗試了上述幾種解決方案后,發(fā)現(xiàn)效果都不是很好,所以我感覺只有讓inputtype屬性始終為password,才能更有效的解決這個(gè)問題??梢钥紤]自定義一個(gè)密碼輸入框組件,通過某些方法去改變input的值的顯示方式,來達(dá)到隱藏密碼的效果。
    目前想出了兩種方法:一個(gè)是不改變input的值,僅僅隱藏input的內(nèi)容,用另一個(gè)容器去顯示密碼或者顯示*;另一個(gè)是將實(shí)際密碼存在另一個(gè)變量中,將inputvalue值改成*來顯示。

    方案一

    可以用兩個(gè)input來實(shí)現(xiàn),父容器是relative定位,兩個(gè)input都是absolute,一個(gè)實(shí)際的輸入框位于上層,設(shè)置為透明,另一個(gè)用于顯示星號(hào)的輸入框位于下層。

    <div class="container">
      <input v-model="passwordDisplay">
      <input
        v-model="password"
        class="password"
        @input="passwordDisplay = password.replace(/./g, '*')">
    </div>
    
    <style scoped>
    .container {
      position: relative;
    }
    .container input {
      position: absolute;
      left: 0;
      top: 0;
      font-size: 12px;
    }
    .password {
      opacity: 0;
    }
    </style>

    效果如下圖所示:

    vue怎么自定義密碼輸入框解決瀏覽器自動(dòng)填充密碼問題

    確實(shí)沒有彈出密碼填充的對(duì)話框,但樣式上并不是很滿意。因?yàn)閷?shí)際的輸入框被設(shè)置成了透明,且在密碼顯示框之上,所以光標(biāo)無法顯示出來,且無法進(jìn)行選中一部分內(nèi)容。

    方案二

    跟方案一差不多的方式,用input來接收用戶輸入的密碼,但僅改變輸入內(nèi)容的透明度, 由于在opacity為0的情況下設(shè)置光標(biāo)顏色無效,所以要將方案一中的opacity: 0改為:

    .password {
      color: transparent;
      background-color: transparent;
      caret-color: #000; /* 光標(biāo)顏色 */
    }

    但是這會(huì)有個(gè)問題,選中一部分內(nèi)容時(shí),會(huì)導(dǎo)致透明的內(nèi)容選中后顯現(xiàn)出來,如圖所示:

    vue怎么自定義密碼輸入框解決瀏覽器自動(dòng)填充密碼問題

    這種情況下可以考慮監(jiān)聽選中事件,當(dāng)選中一部分內(nèi)容時(shí),將后面的星號(hào)也選中,同時(shí)通過::selection偽類來設(shè)置選中的內(nèi)容的背景色,讓兩個(gè)選中的內(nèi)容顏色一致。要實(shí)現(xiàn)這種效果,input顯然做不到修改部分內(nèi)容的背景色,所以可以考慮用span代替input,向其innerHTML中插入帶背景色的span

    <div class="container">
      <span
        ref="passwordInputDisplay"
        class="password password-input__behind"
      />
      <input
        v-model="password"
        class="password password-input__front"
        @focus="isActive = true"
        @blur="isActive = false"
        @input="passwordDisplay = password.replace(/./g, '*')">
    </div>
    <style scoped>
    ::selection {
      background-color: #409eff;
    }
    .container {
      position: relative;
    }
    .password {
      position: absolute;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      font-size: 12px;
      font-family: monospace; /* 必須用等寬字體 */
    }
    .password-input__behind {
      text-align: left;
      z-index: 1;
    }
    .password-input__front {
      color: transparent;
      background-color: transparent;
      caret-color: #000;
      z-index: 2;
    }
    export default {
      props: {
        value: {
          type: String,
          default: ''
        }
      },
      methods: {
        handleInput (e) {
          // 刪除非法字符(只保留code>=32且code<=126的字符)
          const value = e.target.value
          const newValue = value.replace(/[^\x20-\x7E]/g, '')
          if (newValue !== value) {
            this.password = newValue
          }
          // 發(fā)布input事件,從而修改props中的value值
          this.$emit('input', this.password)
        }
    
      },
      created() {
        this.selectionEvent = () => {
          const display = this.$refs.passwordInputDisplay
          display.style.zIndex = 1
          display.innerHTML = this.passwordDisplay
          if (!this.isActive) { return }
          const selection = window.getSelection()
          // 如果選中的內(nèi)容不為空, 則由passwordInputDisplay顯示
          if (!selection.toString()) { return }
          const input = this.$refs.passwordInput
          const start = input.selectionStart
          const end = input.selectionEnd
          const highlightString = '<span >' + this.passwordDisplay.slice(start, end) + '</span>'
          display.innerHTML = this.passwordDisplay.slice(0, start) + highlightString + this.passwordDisplay.slice(end)
          display.style.zIndex = 4
        }
        document.addEventListener('selectionchange', this.selectionEvent)
      },
      beforeDestory() {
        document.removeEventListener('selectionchange', this.selectionEvent)
      }
    }

    需要注意以下幾點(diǎn):

    • 監(jiān)聽select事件不能用input自帶的onselect@select,因?yàn)檫@只會(huì)在鼠標(biāo)松開時(shí)觸發(fā),并不能實(shí)時(shí)相應(yīng)選取區(qū)域的變化。所以要監(jiān)聽selectionchange事件。注意selectionchange事件在沒選中內(nèi)容時(shí)也會(huì)觸發(fā)。

    • 由于相比方案一顯示了光標(biāo),光標(biāo)的位置會(huì)受到實(shí)際字符寬度的影響,所以要使星號(hào)與其他字符寬度相等,必須使用如monospace之類的等寬字體,且必須阻止中文字符的輸入。

    • 修改innerHtml后需要改變密碼顯示框的z-index,否則仍然會(huì)被input中選中的內(nèi)容覆蓋。

    效果如下圖所示:

    vue怎么自定義密碼輸入框解決瀏覽器自動(dòng)填充密碼問題

    這里還有個(gè)問題,當(dāng)輸入內(nèi)容超過了input的長(zhǎng)度,顯示上就會(huì)出現(xiàn)錯(cuò)誤,可以考慮根據(jù)字體寬度計(jì)算出最大容納的字符個(gè)數(shù),阻止過多字符的輸入。也可以在光標(biāo)移動(dòng)時(shí)同時(shí)移動(dòng)后面的span,不過邏輯太過復(fù)雜沒必要。

    const width = this.$refs.passwordInput.clientWidth - 20 // 20為padding
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    ctx.font = '16px monospace'
    const fontWidth = ctx.measureText('A').width
    this.maxLength = Math.floor(width / fontWidth)

    這里用的是canvas進(jìn)行計(jì)算字體寬度。

    雖然最終實(shí)現(xiàn)了目標(biāo)效果,不過邏輯上還是稍微復(fù)雜了點(diǎn)。

    方案三

    只使用一個(gè)input,另外設(shè)置一個(gè)變量去保存真實(shí)密碼。這種方法比上述方法邏輯上要稍微簡(jiǎn)單一些,唯一需要注意的就是當(dāng)輸入框中顯示為星號(hào)時(shí),如何區(qū)分哪些是新輸入的內(nèi)容,因?yàn)闀?huì)有鼠標(biāo)選中一段內(nèi)容再刪除或輸入、粘貼的操作,而新輸入的內(nèi)容中也可能包含星號(hào),所以不能處理的過于簡(jiǎn)單。最后采用的是監(jiān)聽selectionchange事件來隨時(shí)更新光標(biāo)所在位置,從而區(qū)分新輸入的內(nèi)容。

    const width = this.$refs.passwordInput.clientWidth - 20 // 20為padding
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    ctx.font = '16px monospace'
    const fontWidth = ctx.measureText('A').width
    this.maxLength = Math.floor(width / fontWidth)
    export default {
      methods: {
        handleInput () {
          // 獲取新輸入的字符
          const tempEnd = this.passwordDisplaylength - (this.password.length - thisselection.end)
          const newStr = this.passwordDisplay.slic(this.selection.start, tempEnd)
          // 更新輸入框的值
          const currentPosition = this.$refspasswordInput.selectionStart
          this.password = this.password.slice(0,Math.min(this.selection.start,currentPosition)) + newStr + this.passwordslice(this.selection.end)
          this.selection.start = currentPosition
          this.selection.end = currentPosition
          this.$emit('input', this.password)
        }
      },
      created () {
        this.selectionEvent = () => {
          if (!this.isActive) { return }
          const input = this.$refs.passwordInput
          this.selection = {
            start: input.selectionStart,
            end: input.selectionEnd
          }
        }
        this.copyEvent = (e) => {
          if (!this.isActive) { return }
          const clipboardData = e.clipboardData || window.clipboardData
          clipboardData.setData('text', this.password.slice(this.selection.start, this.selection.end))
          e.preventDefault()
        }
        document.addEventListener('selectionchange', this.selectionEvent)
        document.addEventListener('copy', this.copyEvent)
      },
      beforeDestroy () {
        document.removeEventListener('selectionchange', this.selectionEvent)
        document.removeEventListener('copy', this.copyEvent)
      }
    }

    有幾點(diǎn)需要注意:

    • 輸入框中選定的內(nèi)容的起始和結(jié)束位置無法通過window.getSelection().anchorOffset等參數(shù)獲取(window.getSelection()的幾個(gè)offset都是0), 只能通過inputselectionStartselectionEnd可以拿到當(dāng)前選中區(qū)域的起始和結(jié)束位置。

    • 由于輸入框內(nèi)實(shí)際顯示的是星號(hào),所以復(fù)制時(shí)若不處理則復(fù)制的也是星號(hào),所以需要監(jiān)聽復(fù)制事件,將實(shí)際密碼寫入剪貼板。剪貼板通過e.clipboardData || window.clipboardData獲取。

    相比于方案二,這種方法無需要求一定要等寬字體,也無需另外去處理選中內(nèi)容的事件,唯一多出的地方就是對(duì)輸入框?qū)嶋H值的處理,包括輸入和復(fù)制,而這里的邏輯顯然比方案二中修改樣式容易的多。

    效果上跟方案二基本差不多,而且沒有長(zhǎng)度限制,這里用this.passwordDisplay = '\u2022'.repeat(this.value.length)把星號(hào)改成了圓點(diǎn),如下:

    vue怎么自定義密碼輸入框解決瀏覽器自動(dòng)填充密碼問題

    密碼顯示與隱藏

    點(diǎn)擊眼睛圖標(biāo),切換密碼的顯示與隱藏狀態(tài)。

    export default {
      watch: {
        value () {
          this.updatePasswordDisplay()
        },
        showPassword () {
          this.updatePasswordDisplay()
        }
      },
      methods: {
        updatePasswordDisplay () {
          if (this.showPassword) {
            this.passwordDisplay = this.value
          } else {
            // this.passwordDisplay = '*'.repeat(this.value.length)
            this.passwordDisplay = '\u2022'.repeat(this.value.length) // 圓點(diǎn)
          }
        }
      }
    }

    眼睛圖標(biāo)可以用圖標(biāo)庫或者導(dǎo)入圖片,我這里用的是svg,眼睛圖標(biāo)的svg可以通過一些轉(zhuǎn)換工具來實(shí)現(xiàn)

    <div class="password-input__eye-wrap">
      <div
          class="password-input__eye"
          @click="showPassword = !showPassword"
      >
          <svg version="1.0" xmlns="http://www.w3.org/2000/svg"
          width="58.000000pt" height="50.000000pt" viewBox="0 0 58.000000 50.000000"
          preserveAspectRatio="xMidYMid meet">
              <g transform="translate(0.000000,50.000000) scale(0.100000,-0.100000)"
              fill="#000000" stroke="none">
                  <path d="M228 390 c-61 -19 -148 -96 -148 -130 0 -21 61 -87 103 -110 50 -29
                  127 -32 173 -8 39 21 114 98 114 118 0 19 -74 97 -111 115 -36 19 -98 26 -131
                  15z m121 -40 c37 -18 91 -72 91 -90 0 -18 -54 -72 -91 -90 -70 -36 -138 -22
                  -206 43 -18 17 -33 38 -33 47 0 19 53 71 95 93 41 22 98 21 144 -3z"/>
                  <path d="M235 338 c-31 -18 -44 -40 -45 -75 0 -45 9 -62 42 -79 84 -43 168 60
                  106 130 -27 30 -74 41 -103 24z m79 -34 c20 -20 20 -68 0 -88 -35 -35 -104 -6
                  -104 44 0 50 69 79 104 44z"/>
              </g>
          </svg>
      </div>
    </div>
    <style scoped>
    .password-input__eye-wrap {
        display: flex;
        align-items: center;
        justify-content: center;
    }
    .password-input__eye {
        width: 20px;
        height: 20px;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
    }
    </style>

    效果如下:

    vue怎么自定義密碼輸入框解決瀏覽器自動(dòng)填充密碼問題

    感謝各位的閱讀,以上就是“vue怎么自定義密碼輸入框解決瀏覽器自動(dòng)填充密碼問題”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)vue怎么自定義密碼輸入框解決瀏覽器自動(dòng)填充密碼問題這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    vue
    AI