<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # canvas ## 1.簡介 HTML5 的新特性:在添加完成 `canvas` 元素后,通過 `js` 腳本繪制圖案。 ## 2.驗證碼案例 ![](https://img.kancloud.cn/29/ae/29aee7f3402b868d250b5f8d0c953f42_472x513.png) 案例說明:在用戶登錄時提供驗證碼功能(登錄錯誤超過幾次之后顯示,設置驗證碼的實效時間) 案例環境:vue 參考文檔:[登錄隨機驗證碼的實現](https://www.cnblogs.com/moning/p/7868731.html)、[如何給localStorage設置一個過期時間?](https://blog.csdn.net/weixin_43254766/article/details/83618630) ### 2.1實現思路: 使用canvas繪制驗證碼 localstorage中存儲密碼錯誤次數及第一次密碼錯誤時間 賬號或密碼驗證錯誤時從緩存中讀取錯誤次數 ### 2.2具體代碼 驗證碼頁面元素canvas屬性方法設置 ~~~ <li class="verification" v-if="showVerify"> ? ? ? ? ?<input @blur="handleVerify" type="text" v-model.trim="verification" placeholder="請輸入驗證碼" /> ? ? ? ? ?<Icon title="刷新驗證碼" @click="drawVerification" class="icon-refresh" type="md-refresh" /> ? ? ? ? ?<canvas title="點擊刷新" @click.prevent="drawVerification" id="canvas" width="150px" height="40px"></canvas> ? ? ? ?</li> ~~~ 繪制驗證碼方法 ~~~ // 繪制驗證碼方法 drawVerification() { ?const canvas = document.getElementById("canvas"); ?const str = ? ? ? ?"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; ?let verifyVal = ""; // 初始定義隨機數 ?const num = 4; // 設置隨機數個數 ?const width = canvas.clientWidth; ?const height = canvas.clientHeight; ?const ctx = canvas.getContext("2d"); ?// 設置、填充畫布底板 ?ctx.fillStyle = randomColor(180, 240); ?ctx.fillRect(0, 0, width, height); ?// 繪制隨機驗證碼 ?for (let i = 0; i < num; i++) { ? ?const x = (width / num) * i + 15; ? ?const y = randomNum(height / 1.8, height / 1.2); ? ?const deg = randomNum(-45, 45); ? ?const txt = str[randomNum(0, str.length)]; ? ?verifyVal += txt; // 獲取一個隨機數 ? ?ctx.fillStyle = randomColor(10, 100); // 字體填充隨機顏色 ? ?ctx.font = randomNum(18, 25) + "px SimHei"; // 設置字體 ? ?ctx.translate(x, y); // 將當前xy坐標作為原始坐標 ? ?ctx.rotate((deg * Math.PI) / 180); // 旋轉隨機角度 ? ?ctx.fillText(txt, 0, 0); // 繪制文本時以當前坐標為起點 ? ?ctx.rotate((-deg * Math.PI) / 180); // 重置文本旋轉角度 ? ?ctx.translate(-x, -y); // 將坐標系統重置為原始坐標 } ?// 繪制不規則線條 ?for (let i = 0; i < num; i++) { ? ?// 定義畫筆顏色 ? ?ctx.strokeStyle = randomColor(90, 180); ? ?ctx.beginPath(); ? ?// 定義線條路徑 ? ?ctx.moveTo(randomNum(0, width), randomNum(0, height)); ? ?ctx.lineTo(randomNum(0, width), randomNum(0, height)); ? ?// 按路徑繪制 ? ?ctx.stroke(); } ?// 繪制圓點 ?for (let i = 0; i < num * 10; i++) { ? ?ctx.fillStyle = randomColor(0, 255); ? ?ctx.beginPath(); ? ?ctx.arc(randomNum(0, width), randomNum(0, height), 1, 0, 2 * Math.PI); ? ?ctx.fill(); } ?this.verifyVal = verifyVal; } ~~~ 登錄驗證 ~~~ async login() { ?// ... ?try { ? ?const res = await loginCheck(userInfo); ? ?// ... ? ?localStorageUtils.remove("failureTimes"); ? ?localStorageUtils.remove("failureTimes__expired__"); } catch (err) { ? ?const failureTimes = (localStorageUtils.get("failureTimes") || 0) + 1; ? ?// 登錄驗證錯誤超過4次時,顯示并繪制 ? ?if (failureTimes > 4) { ? this.showVerify = true; ? if (this.verification) { ? this.verification = ""; ? } ? await this.$nextTick(); ? this.drawVerification(); ? } ? ?if (failureTimes === 1) { ? const userInfo = localStorageUtils.get("userInfo"); ? if (userInfo && userInfo.password) { ? ? ? ?// 若選擇了記住密碼,首次登錄驗證不通過時將密碼清空 ? ? ? ?localStorageUtils.save("userInfo", { ? ? ? ? ?loginName: userInfo.loginName ? ? ? }); ? ? } ? } ? ?// 緩存密碼錯誤次數與當前錯誤時間 ? ?localStorageUtils.save("failureTimes", failureTimes, true); } } ~~~ 緩存控制 ~~~ export default { ?save(key, value, expired = false) { ? ?this.remove(key); ? ?if (expired) { ? ? ?localStorage.setItem( ? ? ? ?`${key}__expired__`, ? ? ? ?Date.now() + 1000 * 60 * 60 * 3 ? ? ); ? } ? ?localStorage.setItem(key, JSON.stringify(value)); }, ?get(key) { ? ?const expired = localStorage.getItem(`${key}__expired__`); ? ?if (expired && Date.now() >= expired) { ? ? ?// 超出時間期限 ? ? ?this.remove(key); ? ? ?this.remove(`${key}__expired__`); ? ? ?return; ? } ? ?const value = localStorage.getItem(key); ? ?if (value) { ? ? ?try { ? ? ? ?return value ? JSON.parse(value) : null; ? ? } catch (error) { ? ? ? ?// JSON.parse("xxx") 非對象字符串出錯,直接返回對應的字符串 ? ? ? ?return value ? value : null; ? ? } ? } else { ? ? ?return; ? } }, ?remove(key) { ? ?localStorage.removeItem(key); }, ?removeAll() { ? ?localStorage.clear(); } }; ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看