<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>

          私藏的這些高級(jí)工具函數(shù),你擁有幾個(gè)?

          共 13094字,需瀏覽 27分鐘

           ·

          2021-07-31 02:15

          3667edc7a66294737ed57b04d3fcfdf1.webp

          作者:云的世界

          https://juejin.cn/post/6987166546502090788

          前言

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

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

          我們用精簡(jiǎn)的代碼來(lái)實(shí)現(xiàn)相對(duì)復(fù)雜的功能,沒(méi)有第三方庫(kù),你也能秀得飛起。

          目錄(方便移動(dòng)端閱讀)

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

          localStorage的已使用空間

          在較新的chrome上測(cè)試,localStorage的存儲(chǔ)是按照字符個(gè)數(shù)來(lái)算的。包含鍵和值的
          所以在測(cè)試代碼中,你把a修改,不會(huì)影響存儲(chǔ)的數(shù)量。但是鍵的長(zhǎng)度,會(huì)影響存儲(chǔ)的數(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ù)制代碼

          溢出測(cè)試

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


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

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

          注意

          1. 超過(guò)存儲(chǔ)上線是會(huì)報(bào)錯(cuò)的:
          8863783922a88af227f7d69196ea0361.webpimage.png
          1. 如何捕獲錯(cuò)誤,可以參考 MDN testing\_for\_availability[6]

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


          e?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)頁(yè)也可以以桌面彈框的形式進(jìn)行通知,先看個(gè)效果圖:
          有頭像,有標(biāo)題,有文本,點(diǎn)擊消息通知還能讓窗體聚焦,真帥。

          09c2ece9f4be9b79f14b8f55db93ac92.webpimage.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("中獎(jiǎng)提示",?{
          ????????????icon:?"https://sf1-ttcdn-tos.pstatp.com/img/user-avatar/f1a9f122e925aeef5e4534ff7f706729~300x300.image",
          ????????????body:?"恭喜你,掘金簽到一等獎(jiǎng)",
          ????????????tag:?"prize"
          ????????},?{
          ????????????onclick(ev)?{
          ????????????????console.log(ev);
          ????????????????ev.target.close();
          ????????????????window.focus();
          ????????????}
          ????????})
          復(fù)制代碼

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

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

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

          看一下效果:

          f35a5c7ee3ecc16cdf751e3a48564366.webp代碼

          ?????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,?0,?0,?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)為圖片會(huì)失敗。


          ??<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方法,其實(shí)不然,URLSearchParamsURL都能很好的實(shí)現(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ù)制代碼

          示例

          測(cè)試地址:?/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編碼和解碼的能力,第三方庫(kù),不需要的。

          代碼

          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ù)制代碼

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

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

          代碼

          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, 其后部分就是一個(gè)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ù),無(wú)序數(shù)據(jù),等等。

          代碼

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

          示例

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

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

          sendBeacon[24] 異步地向服務(wù)器發(fā)送數(shù)據(jù),同時(shí)不會(huì)延遲頁(yè)面的卸載或影響下一導(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ù),可能是會(huì)有問(wèn)題的。

          代碼

          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ù)制代碼

          延時(shí)執(zhí)行delay

          延時(shí)執(zhí)行某函數(shù),且只會(huì)執(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)度的場(chǎng)景。

          代碼

          function?adjustProgress(progress:?number,?mapping:?{?real:?number;?target:?number?}[]?=?[])?{
          ????if?(progress?<?0)?{
          ????????return?0;
          ????}
          ????if?(!mapping?||?mapping.length?<=?0)?{
          ????????return?progress;
          ????}
          ????//?第一個(gè)
          ????const?f?=?mapping[0];
          ????if?(progress?<=?f.real)?{
          ????????return?progress?*?(f.target?/?f.real);
          ????}
          ????//?最后一個(gè)
          ????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ù)?????+???實(shí)際進(jìn)度/最大實(shí)際進(jìn)度?*?期望間距
          ????return?pre.target?+?(progress?-?pre.real)?/?(cur.real?-?pre.real)?*?(cur.target?-?pre.target);
          }

          復(fù)制代碼

          示例

          const?mapping?=?[{
          ????real:?0,
          ????target:?0,
          },?{
          ????real:?30,
          ????target:?50
          },?{
          ????real:?60,
          ????target:?80
          },?{
          ????real:?100,
          ????target:?100
          }];


          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ù)制代碼

          滑滾動(dòng)頁(yè)面到頂部

          代碼

          PC端滾動(dòng)的根元素是document.documentElement,
          移動(dòng)端滾動(dòng)的的根元素是document.body,
          有一個(gè)更好的屬性document.scrollingElement能自己識(shí)別文檔的滾動(dòng)元素, 其在PC端等于document.documentElement, 其在移動(dòng)端等于document.body

          //?smooth?選項(xiàng)在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ù)制代碼

          自增長(zhǎng)ID

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

          代碼

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

          示例

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

          寫(xiě)在后面

          寫(xiě)作不易,你的一贊一在看,就是我前行的最大動(dòng)力。


          往期干貨

          ?26個(gè)經(jīng)典微信小程序+35套微信小程序源碼+微信小程序合集源碼下載(免費(fèi))

          ?干貨~~~2021最新前端學(xué)習(xí)視頻~~速度領(lǐng)取

          ?前端書(shū)籍-前端290本高清pdf電子書(shū)打包下載


          點(diǎn)贊和在看就是最大的支持??

          瀏覽 42
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  欧美全黄一级裸片 | 可以赌博看毛片的网站 | 亚洲欧美国产高清vA在线播放 | 久久久久无码国产精品一区 | 男人色天堂网 |