<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【干貨】私藏的這些高級工具函數(shù),你擁有幾個?

          共 25704字,需瀏覽 52分鐘

           ·

          2021-08-03 14:54

          點擊上方 前端瓶子君,關(guān)注公眾號

          回復(fù)算法,加入前端編程面試算法每日一題群

          前言

          很多功能,其實內(nèi)置的Web API已支持,

          • 比如基于URLSearchParams或者URL的queryString獲取和生成
          • 比如基于btoa,atob的base64的編碼和解碼
          • 比如基于sendBeacon的數(shù)據(jù)上報
          • 比如基于 Array.from的序列生成
          • 比如基于canvas的視頻截圖
          • 比如基于URL的UUID生成

          我們用精簡的代碼來實現(xiàn)相對復(fù)雜的功能,沒有第三方庫,你也能秀得飛起。

          目錄(方便移動端閱讀)

          • localStorage的已使用空間
          • 帶圖帶事件的桌面通知
          • 原生30行代碼實現(xiàn)視頻截圖
          • 基于URLSearchParams獲取queryString的值
          • 基于atobbtoa的base64編碼和解碼
          • 非正則替換html代碼encode和decode
          • 相對地址轉(zhuǎn)換為絕對地址
          • 基于URL或者Crypto.getRandomValues生成UUID
          • 基于Array.from的序列生成器
          • 基于sendBeacon的安全的數(shù)據(jù)上報
          • 基于toLocaleString千分位
          • Promise順序執(zhí)行
          • 延時執(zhí)行delay
          • 進(jìn)度值映射
          • 滑滾動頁面到頂部
          • 禁止選擇和復(fù)制
          • 禁止圖片拖拽
          • 自增長ID

          localStorage的已使用空間

          在較新的chrome上測試,localStorage的存儲是按照字符個數(shù)來算的。包含鍵和值的。
          所以在測試代碼中,你把a修改,不會影響存儲的數(shù)量。但是鍵的長度,會影響存儲的數(shù)量。

          代碼

          function getLSUsedSpace() {
              return Object.keys(localStorage).reduce((total, curKey) => {
                  if (!localStorage.hasOwnProperty(curKey)) {
                      return total;
                  }
                  total += localStorage[curKey].length + curKey.length;
                  return total;
              }, 0)
          }

          復(fù)制代碼

          示例

          localStorage.clear();
          localStorage.a = "啊";
          console.log(getLSUsedSpace()); // 2
          復(fù)制代碼

          溢出測試

          key的值為長度為10的 kkkkkkkkkk:
          輸出結(jié)果:Max: 5242880 value Length: 5242870
          當(dāng)你把key修改長度為1的k:
          輸出結(jié)果:Max: 5242880 value Length: 5242879


          localStorage.clear();
          let valLength = 0
          try {
              let str = Array.from({ length5242800 }, () => "啊").join("");
              valLength = str.length;
              for (let i = 0; i < 10000000000000; i++) {
                  str += "a"
                  valLength += 1;
                  localStorage.setItem(`kkkkkkkkkk`, str);
              }

          catch (err) {
              console.error("存儲失敗", err);
              console.log("Max:", getLSUsedSpace(), " value Length:", valLength)
          }
          復(fù)制代碼
          image.png

          注意

          1. 超過存儲上線是會報錯的:
          image.png
          1. 如何捕獲錯誤,可以參考 MDN testing\_for\_availability[6]

          大致是對Error的錯誤碼和name進(jìn)行判斷


          instanceof DOMException && (
                      // everything except Firefox
                      e.code === 22 ||
                      // Firefox
                      e.code === 1014 ||
                      // test name field too, because code might not be present
                      // everything except Firefox
                      e.name === 'QuotaExceededError' ||
                      // Firefox
                      e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
                      // acknowledge QuotaExceededError only if there's something already stored
                      (storage && storage.length !== 0);

          復(fù)制代碼

          參考引用
          calculating-usage-of-localstorage-space[7]
          what-is-the-max-size-of-localstorage-values[8]
          Test of localStorage limits/quota[9]

          帶圖帶事件的桌面通知

          網(wǎng)頁也可以以桌面彈框的形式進(jìn)行通知,先看個效果圖:
          有頭像,有標(biāo)題,有文本,點擊消息通知還能讓窗體聚焦,真帥。

          image.png

          代碼

          function doNotify(title, options = {}, events = {}{
              const notification = new Notification(title, options);
              for (let event in events) {
                  notification[event] = events[event];
              }
          }

          function notify(title, options = {}, events = {}{
              if (!("Notification" in window)) {
                  return console.error("This browser does not support desktop notification");
              }
              else if (Notification.permission === "granted") {
                  doNotify(title, options, events);
              } else if (Notification.permission !== "denied") {
                  Notification.requestPermission().then(function (permission{           
                      if (permission === "granted") {
                          doNotify(title, options, events);
                      }
                  });
              }
          }
          復(fù)制代碼

          示例
          tag還可以用去重消息。

               notify("中獎提示", {
                      icon"https://sf1-ttcdn-tos.pstatp.com/img/user-avatar/f1a9f122e925aeef5e4534ff7f706729~300x300.image",
                      body"恭喜你,掘金簽到一等獎",
                      tag"prize"
                  }, {
                      onclick(ev) {
                          console.log(ev);
                          ev.target.close();
                          window.focus();
                      }
                  })
          復(fù)制代碼

          參考引用
          notification[10]
          使用 Web Notifications[11]

          原生30行代碼實現(xiàn)視頻截圖

          基本原理就是把視頻畫到Canvas里面,然后調(diào)用toDataURL或者toBlob,再利用a標(biāo)簽?zāi)M點擊,download屬性指定名字。

          看一下效果:

          代碼

               function captureVideo(videoEl{
                      let canvasEl;
                      let dataUrl;
                      try {
                          const cps = window.getComputedStyle(videoEl);
                          const width = +cps.getPropertyValue("width").replace("px""");
                          const height = +cps.getPropertyValue("height").replace("px""");

                          canvasEl = document.createElement("canvas");
                          canvasEl.style.cssText = `position:fixed;left:-9999px`;
                          canvasEl.height = height;
                          canvasEl.width = width;

                          document.body.appendChild(canvasEl);
                          
                          const ctx = canvasEl.getContext("2d");
                          ctx.drawImage(videoEl, 00, width, height);
                          // const image = canvas.toDataURL("image/png");
                          dataUrl = canvasEl.toDataURL();

                          document.body.removeChild(canvasEl);
                          canvasEl = null;
                          return dataUrl;
                      } finally {
                          if (canvasEl) {
                              document.body.removeChild(canvasEl);
                          }
                          if (dataUrl) {
                              return dataUrl;
                          }
                      }
                  }

          復(fù)制代碼

          示例
          注意添加crossorigin="anonymous",不然轉(zhuǎn)為圖片會失敗。


            <video id="videoEL" controls autoplay crossorigin="anonymous"
                  src="https://api.dogecloud.com/player/get.mp4?vcode=5ac682e6f8231991&userId=17&ext=.mp4" width="500"></video>

          function download(url) {
              const aEl = document.createElement("a");
              aEl.href = url;
              aEl.download = "視頻.png";
              aEl.click();
          }


          function doCaptureVideo() {
              const url = captureVideo(videoEL);
              download(url);
          }

          doCaptureVideo()
          復(fù)制代碼

          基于URLSearchParamsURL獲取queryString的值

          常用的方式是使用正則或者split方法,其實不然,URLSearchParamsURL都能很好的實現(xiàn)功能。

          代碼

          const urlSP = new URLSearchParams(location.search);
          function getQueryString(key){
              return urlSP.get(key)
          }

          const urlObj = new URL(location.href);
          function getQueryString(key){
              return urlObj.searchParams.get(key)
          }

          復(fù)制代碼

          示例

          測試地址: /index.html?pid=10

          const log = console.log;
          getQueryString

          log("pid", getQueryString("pid"));  // pid 10
          log("cid", getQueryString("cid"));  // cid null

          復(fù)制代碼

          參考引用
          MDN文獻(xiàn):URLSearchParams-MDN[12]
          CanIUse兼容性: URLSearchParams: 95.63\%[13]
          Polyfill: url-search-params-polyfill[14]

          基于atobbtoa的base64編碼和解碼

          瀏覽器內(nèi)置了base64編碼和解碼的能力,第三方庫,不需要的。

          代碼

          function utf8_to_b64( str {
            return window.btoa(unescape(encodeURIComponent( str )));
          }

          function b64_to_utf8( str {
            return decodeURIComponent(escape(window.atob( str )));
          }
          復(fù)制代碼

          示例

          utf8_to_b64('? à la mode'); // "4pyTIMOgIGxhIG1vZGU="
          b64_to_utf8('4pyTIMOgIGxhIG1vZGU='); // "? à la mode"
          復(fù)制代碼

          參考引用
          MDN文獻(xiàn):atob[15], btoa[16]
          CanIUse兼容性: btoa 99.68\%[17]
          Polyfill: MDN Polyfill[18]
          Base64[19]

          非正則替換的html代碼encode和decode

          常規(guī)的方式是使用正則替換,這里是另外一種思路。

          代碼

          function htmlencode(s){
              var div = document.createElement('div');
              div.appendChild(document.createTextNode(s));
              var result = div.innerHTML;
              div = null;
              return result;
          }
          function htmldecode(s){
              var div = document.createElement('div');
              div.innerHTML = s;
              var result = div.innerText || div.textContent;
              div = null;
              return result;
          }
          復(fù)制代碼

          示例

          htmlencode("<div>3>5 & 666</div>"); // &lt;div&gt;3&gt;5 &amp; 666&lt;/div&gt;
          htmldecode("&lt;div&gt;3&gt;5 &amp; 666&lt;/div&gt;") // <div>3>5 & 666</div>
          復(fù)制代碼

          相對地址轉(zhuǎn)換為絕對地址

          基于當(dāng)前頁面的相對地址轉(zhuǎn)換為絕對地址。

          代碼

          function realativeToAbs(href{
              let aEl = document.createElement("a");
              aEl.href = href;    

              const result = aEl.href;
              aEl = null;
              return result;
          }
          復(fù)制代碼

          示例

          console.log("realativeToAbs", realativeToAbs("../a/b/b/index.html"));
          // realativeToAbs http://127.0.0.1:5500/a/b/b/index.html
          復(fù)制代碼

          基于URL或者Crypto.getRandomValues生成UUID

          基于URL.createObjectURL[20]或者Crypto.getRandomValues[21]

          URL.createObjectURL 產(chǎn)生的地址為 blob:https://developer.mozilla.org/cb48b940-c625-400a-a393-176c3635020b, 其后部分就是一個UUID

          代碼
          方式一:

          function genUUID() {
              const url = URL.createObjectURL(new Blob([]));
              // const uuid = url.split("/").pop();
              const uuid = url.substring(url.lastIndexOf('/')+ 1);
              URL.revokeObjectURL(url);
              return uuid;
          }

          genUUID() // cd205467-0120-47b0-9444-894736d873c7

          復(fù)制代碼

          方式二:

          function uuidv4() {
            return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
              (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
          }

          uuidv4() // 38aa1602-ba78-4368-9235-d8703cdb6037
          復(fù)制代碼

          參考引用
          generating-uuids-at-scale-on-the-web-2877f529d2a2[22]
          collisions-when-generating-uuids-in-javascript[23]

          基于Array.from的序列生成器

          造有序數(shù)據(jù),無序數(shù)據(jù),等等。

          代碼

          const range = (start, stop, step) => Array.from(
              { length: (stop - start) / step + 1}, 
              (_, i) => start + (i * step)
          );
          復(fù)制代碼

          示例

          range(041); // [0, 1, 2, 3, 4]
          range(093); // [0, 3, 6, 9]
          range(082.5// [0, 2.5, 5, 7.5]
          復(fù)制代碼

          基于sendBeacon的安全的數(shù)據(jù)上報

          sendBeacon[24] 異步地向服務(wù)器發(fā)送數(shù)據(jù),同時不會延遲頁面的卸載或影響下一導(dǎo)航的載入性能。

          function report(url, data{
              if (typeof navigator.sendBeacon !== "function") {
                  return console.error("sendBeacon不被支持");
              }
              navigator.sendBeacon(url, data);
          }
          復(fù)制代碼

          示例

          window.addEventListener('unload', logData, false);
          function logData() {
             report("/log""被卸載了");
          }
          復(fù)制代碼

          基于toLocaleString千分位

          正則?遍歷?不需要的。內(nèi)置函數(shù)就解決。
          當(dāng)然,如果是超大的數(shù),可能是會有問題的。

          代碼

          function formatMoney(num){
              return (+num).toLocaleString("en-US");
          }
          復(fù)制代碼

          示例

          console.log(formatMoney(123456789));  // 123,456,789
          console.log(formatMoney(6781)) // 6,781
          console.log(formatMoney(5)) // 5

          超大的數(shù)
          formatMoney(19999999933333333333333) // 19,999,999,933,333,333,000,000
          復(fù)制代碼

          Promise順序執(zhí)行

          讓Promise順序的執(zhí)行,并支持初始化參數(shù)和結(jié)果作為參數(shù)傳遞。

          代碼

          function runPromises(promiseCreators, initData{
              return promiseCreators
                  .reduce((promise, next) => promise
                          .then((data) => next(data))
                      , Promise.resolve(initData));
          }
          復(fù)制代碼

          示例

          var promise1 = function (data = 0{
              return new Promise(resolve => {
                  resolve(data + 1000);
              });
          }
          var promise2 = function (data{
              return new Promise(resolve => {
                  resolve(data -500);
              });
          }

          runPromises([promise1, promise2], 1).then(res=>console.log(res));
          復(fù)制代碼

          延時執(zhí)行delay

          延時執(zhí)行某函數(shù),且只會執(zhí)行一次。

          代碼

          function delay(fn = () => { }, delay = 5000, context = null) {
              let ticket = null;
              let runned = false;
              return {
                  run(...args) {
                      return new Promise((resolve, reject) => {
                          if (runned === true) {
                              return;
                          }
                          runned = true;
                          ticket = setTimeout(async () => {
                              try {
                                  const res = await fn.apply(context, args);
                                  resolve(res);
                              } catch (err) {
                                  reject(err)
                              }
                          }, delay)
                      })
                  },
                  cancel() => {
                      clearTimeout(ticket);
                  }
              }
          }
          復(fù)制代碼

          示例

          delay(function () {
              console.log("你們好");
          }).run();

          const { run, cancel } = delay(function (name{
              console.log("你好:", name);
          });

          run("吉他");
          run("吉他");

          // 你們好
          // 你好: 吉他


          復(fù)制代碼

          進(jìn)度值映射

          進(jìn)度映射,比較只有 10%的進(jìn)度,確要顯示50%的進(jìn)度的場景。

          代碼

          function adjustProgress(progress: number, mapping: { real: number; target: number }[] = []{
              if (progress < 0) {
                  return 0;
              }
              if (!mapping || mapping.length <= 0) {
                  return progress;
              }
              // 第一個
              const f = mapping[0];
              if (progress <= f.real) {
                  return progress * (f.target / f.real);
              }
              // 最后一個
              const l = mapping[mapping.length - 1];
              if (progress >= l.target) {
                  return l.target;
              }
              const curIndex = mapping.findIndex(m => m.real >= progress);
              if (!curIndex) {
                  return progress;
              }
              const cur = mapping[curIndex];
              const pre = mapping[curIndex - 1];
              //     原基數(shù)     +   實際進(jìn)度/最大實際進(jìn)度 * 期望間距
              return pre.target + (progress - pre.real) / (cur.real - pre.real) * (cur.target - pre.target);
          }

          復(fù)制代碼

          示例

          const mapping = [{
              real0,
              target0,
          }, {
              real30,
              target50
          }, {
              real60,
              target80
          }, {
              real100,
              target100
          }];


          console.log("15", adjustProgress(15, mapping));  // 15 25
          console.log("25", adjustProgress(25, mapping)); // 25 41.66666666666667
          console.log("50", adjustProgress(50, mapping)); // 50 70
          console.log("60", adjustProgress(60, mapping)); // 60 80
          console.log("100", adjustProgress(100, mapping)); // 100 100
          復(fù)制代碼

          滑滾動頁面到頂部

          代碼

          PC端滾動的根元素是document.documentElement,
          移動端滾動的的根元素是document.body,
          有一個更好的屬性document.scrollingElement能自己識別文檔的滾動元素, 其在PC端等于document.documentElement, 其在移動端等于document.body

          // smooth 選項在Safari上支持不好
          function scrollToTop(){
              window.scrollTo({
                  left: 0,
                  top: 0,
                  behavior: 'smooth
              })
          }

          function scrollToTop() {
              let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
              if (scrollTop > 0) {
                  window.requestAnimationFrame(scrollToTop);
                  window.scrollTo(0, scrollTop - scrollTop / 8);
              }
          };

          復(fù)制代碼

          禁止選擇和復(fù)制

          代碼

          ['contextmenu''selectstart''copy'].forEach(function(ev){
              document.addEventListener(ev, function(ev){
                  ev.preventDefault();
                  ev.returnValue = false;
              })
          });
          復(fù)制代碼

          當(dāng)然也有CSS方案

          body {
              -moz-user-select: none;
              -webkit-user-select: none;
              -ms-user-select: none;
              -khtml-user-select: none;
              user-select: none;
          }
          復(fù)制代碼

          禁止圖片拖拽

          代碼

          ['dragstart'].forEach(function(ev){
              document.addEventListener(ev, function(ev){
                  ev.preventDefault();
                  ev.returnValue = false;
              })
          });

          復(fù)制代碼

          自增長ID

          自己生產(chǎn)自增長的ID值,當(dāng)然可以更復(fù)雜一些。

          代碼

          let id = 0;
          function getId() {
              return id++;
          }
          復(fù)制代碼

          示例

          console.log(getId()); // 1
          console.log(getId()); // 2
          復(fù)制代碼

          寫在后面

          寫作不易,你的一贊一在看,就是我前行的最大動力。

          關(guān)于本文

          來源:云的世界

          https://juejin.cn/post/6987166546502090788


          最后

          歡迎關(guān)注【前端瓶子君】??ヽ(°▽°)ノ?
          回復(fù)「算法」,加入前端編程源碼算法群,每日一道面試題(工作日),第二天瓶子君都會很認(rèn)真的解答喲!
          回復(fù)「交流」,吹吹水、聊聊技術(shù)、吐吐槽!
          回復(fù)「閱讀」,每日刷刷高質(zhì)量好文!
          如果這篇文章對你有幫助,在看」是最大的支持
           》》面試官也在看的算法資料《《
          “在看和轉(zhuǎn)發(fā)”就是最大的支持



          瀏覽 76
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  经典三级在线视频 | 欧美一级手机在线免费 | 看澡逼做爱黄色视频 | 精品久久久久久中文字幕无码专区 | 日本中文字幕中文翻译歌词 |