DD每週前端七題詳解-第二期

語言: CN / TW / HK

系列介紹

你盼世界,我盼望你無bug。Hello 大家好!我是霖呆呆!

呆呆每週都會分享七道前端題給大家,系列名稱就是「DD每週七題」。

系列的形式主要是:3道JavaScript + 2道HTML + 2道CSS,幫助我們大家一起鞏固前端基礎。

所有題目也都會整合至 LinDaiDai/niubility-coding-jsissues中,歡迎大家提供更好的解題思路,謝謝大家😁。

正題

一、設計一個方法提取物件中所有value大於2的鍵值對並返回最新的物件

實現:

var obj = { a: 1, b: 3, c: 4 }
foo(obj) // { b: 3, c: 4 }
複製程式碼

方法有很多種,這裡提供一種比較簡潔的寫法,用到了ES10Object.fromEntries()

var obj = { a: 1, b: 3, c: 4 }
function foo (obj) {
  return Object.fromEntries(
    Object.entries(obj).filter(([key, value]) => value > 2)
  )
}
var obj2 = foo(obj) // { b: 3, c: 4 }
console.log(obj2)
複製程式碼
// ES8中 Object.entries()的作用:
var obj = { a: 1, b: 2 }
var entries = Object.entries(obj); // [['a', 1], ['b', 2]]
// ES10中 Object.fromEntries()的作用:
Object.fromEntries(entries); // { a: 1, b: 2 }
複製程式碼

github.com/LinDaiDai/n…

二、實現一個padStart()或padEnd()的polyfill

String.prototype.padStartString.prototype.padEndES8中新增的方法,允許將空字串或其他字串新增到原始字串的開頭或結尾。我們先看下使用語法:

String.padStart(targetLength,[padString])
複製程式碼

用法:

'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'

// 1. 若是輸入的目標長度小於字串原本的長度則返回字串本身
'xxx'.padStart(2, 's') // 'xxx'

// 2. 第二個引數的預設值為 " ",長度是為1的
// 3. 而此引數可能是個不確定長度的字串,若是要填充的內容達到了目標長度,則將不要的部分擷取
'xxx'.padStart(5, 'sss') // ssxxx

// 4. 可用來處理日期、金額格式化問題
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
複製程式碼

polyfill實現:

String.prototype.myPadStart = function (targetLen, padString = " ") {
  if (!targetLen) {
    throw new Error('請輸入需要填充到的長度');
  }
  let originStr = String(this); // 獲取到呼叫的字串, 因為this原本是String{},所以需要用String轉為字串
  let originLen = originStr.length; // 呼叫的字串原本的長度
  if (originLen >= targetLen) return originStr; // 若是 原本 > 目標 則返回原本字串
  let diffNum = targetLen - originLen; // 10 - 6 // 差值
  for (let i = 0; i < diffNum; i++) { // 要新增幾個成員
    for (let j = 0; j < padString.length; j++) { // 輸入的padString的長度可能不為1
      if (originStr.length === targetLen) break; // 判斷每一次新增之後是否到了目標長度
      originStr = `${padString[j]}${originStr}`;
    }
    if (originStr.length === targetLen) break;
  }
  return originStr;
}
console.log('xxx'.myPadStart(16))
console.log('xxx'.padStart(16))
複製程式碼

還是比較簡單的,而padEnd的實現和它一樣,只需要把第二層for迴圈裡的${padString[j]}${orignStr}換下位置就可以了。

github.com/LinDaiDai/n…

三、用正則寫一個根據name獲取cookie中的值的方法

function getCookie(name) {
  var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]*)'));
  if (match) return unescape(match[2]);
}
複製程式碼
  1. 獲取頁面上的cookie可以使用 document.cookie 這裡獲取到的是類似於這樣的字串:
'username=lindaidai; user-id=12345; user-roles=home, me, setting'
複製程式碼

可以看到這麼幾個資訊:

  • 每一個cookie都是由 name=value 這樣的形式儲存的
  • 每一項的開頭可能是一個空串''(比如username的開頭其實就是), 也可能是一個空字串' '(比如user-id的開頭就是)
  • 每一項用";"來區分
  • 如果某項中有多個值的時候,是用","來連線的(比如user-roles的值)
  • 每一項的結尾可能是有";"的(比如username的結尾),也可能是沒有的(比如user-roles的結尾)
  1. 所以我們將這裡的正則拆分一下:
  • '(^| )'表示的就是獲取每一項的開頭,因為我們知道如果^不是放在[]裡的話就是表示開頭匹配。所以這裡(^| )的意思其實就被拆分為(^)表示的匹配username這種情況,它前面什麼都沒有是一個空串(你可以把(^)理解為^它後面還有一個隱藏的'');而|表示的就是或者是一個" "(為了匹配user-id開頭的這種情況)
  • +name+這沒什麼好說的
  • =([^;]*)這裡匹配的就是=後面的值了,比如lindaidai;剛剛說了^要是放在[]裡的話就表示"除了^後面的內容都能匹配",也就是非的意思。所以這裡([^;]*)表示的是除了";"這個字串別的都匹配(*應該都知道什麼意思吧,匹配0次或多次)
  • 有的大佬等號後面是這樣寫的'=([^;]*)(;|$)',而最後為什麼可以把'(;|$)'給省略呢?因為其實最後一個cookie項是沒有';'的,所以它可以合併到=([^;]*)這一步。
  1. 最後獲取到的match其實是一個長度為4的陣列。比如:
[
  "username=lindaidai;",
  "",
  "lindaidai",
  ";"
]
複製程式碼
  • 第0項:全量
  • 第1項:開頭
  • 第2項:中間的值
  • 第3項:結尾

所以我們是要拿第2項match[2]的值。

  1. 為了防止獲取到的值是%xxx這樣的字元序列,需要用unescape()方法解碼。

github.com/LinDaiDai/n…

四、實現一個拖拽(相容寫法)

考察知識點

  1. event的相容性
  • 其它瀏覽器window.event
  • 火狐下沒有window.event,所以用傳入的引數ev代替
  • 最終寫法:var oEvent = ev || window.event
  1. 實現拖拽的事件有哪些(box為需要拖拽的元素)
  • box.onmousedown
  • document.onmousemove
  • box.onmouseup
  1. 實現的事件順序
  • 首先監聽box.onmousedown,即滑鼠按下box時觸發的事件,記錄下滑鼠按下時距離螢幕上邊和左邊的距離,以及box距離螢幕上邊和左邊的距離,再用前者減去後者得到差值distanceXdistanceY
  • 然後在此事件中監聽document.onmousemove事件,記錄下每次滑鼠移動時距離螢幕上邊和左邊的距離,然後用它們減去distanceXdistanceY,再將其賦值給boxlefttop,使其能跟著滑鼠移動
  • 不過需要考慮box距離螢幕最上面/下面/左邊/右邊的邊界情況
  • box.onmouseup的時候需要將document.onmousemove事件設定為null

如圖所示:

Coding

css

<style>
  html, body {
    margin: 0;
    height: 100%;
  }
  #box {
    width: 100px;
    height: 100px;
    background-color: red;
    position: absolute;
    top: 100px;
    left: 100px;
  }
</style>
複製程式碼

html

<div id="box"></div>
複製程式碼

javascript

window.onload = function () {
  var box = document.getElementById('box');
  box.onmousedown = function (ev) {
    var oEvent = ev || window.event; // 相容火狐,火狐下沒有window.event
    var distanceX = oEvent.clientX - box.offsetLeft; // 滑鼠到可視區左邊的距離 - box到頁面左邊的距離
    var distanceY = oEvent.clientY - box.offsetTop;
    document.onmousemove = function (ev) {
      var oEvent = ev || window.event;
      var left = oEvent.clientX - distanceX;
      var top = oEvent.clientY - distanceY;
      if (left <= 0) {
        left = 0;
      } else if (left >= document.documentElement.clientWidth - box.offsetWidth) {
        left = document.documentElement.clientWidth - box.offsetWidth;
      }
      if (top <= 0) {
        top = 0;
      } else if (top >= document.documentElement.clientHeight - box.offsetHeight) {
        top = document.documentElement.clientHeight - box.offsetHeight;
      }
      box.style.left = left + 'px';
      box.style.top = top + 'px';
    }
    box.onmouseup = function () {
      document.onmousemove = null;
      box.onmouseup = null;
    }
  }
}
複製程式碼

github.com/LinDaiDai/n…

五、如何阻止冒泡和預設事件(相容寫法)

阻止冒泡:

function stopBubble (e) { // 阻止冒泡
  if (e && e.stopPropagation) {
    e.stopPropagation();
  } else {
    // 相容 IE
    window.event.cancelBubble = true;
  }
}
function stopDefault (e) { // 阻止預設事件
  if (e && e.preventDefault) {
    e.preventDefault();
  } else {
    // 相容 IE
    window.event.returnValue = false;
    return false;
  }
}
複製程式碼

github.com/LinDaiDai/n…

六、如何畫扇形?三角形?

/*扇形*/
.sector {
  width: 0;
  height: 0;
  border: 100px solid red;
  border-color: red transparent transparent transparent;
  border-radius: 50%;
}
/*或者*/
.sector {
  width: 100px;
  height: 100px;
  border: 100px solid transparent;
  border-top-color: red;
  box-sizing: border-box; /* 這步很重要 */
  border-radius: 50%;
}
複製程式碼
/*三角形*/
.triangle {
  width: 0;
  height: 0;
  border: 100px solid red;
  border-color: red transparent transparent transparent;
}
/*或者*/
.triangle {
  width: 100px;
  height: 100px;
  border: 100px solid transparent;
  border-top-color: red;
  box-sizing: border-box;
}
複製程式碼

github.com/LinDaiDai/n…

七、圓?半圓?橢圓?

div {
  width: 100px;
  height: 100px;
  background-color: red;
  margin-top: 20px;
}
.box1 { /* 圓 */
  /* border-radius: 50%; */
  border-radius: 50px;
}
.box2 { /* 半圓 */
  height: 50px;
  border-radius: 50px 50px 0 0;
}
.box3 { /* 橢圓 */
  height: 50px;
  border-radius: 50px/25px; /* x軸/y軸 */
}
複製程式碼

github.com/LinDaiDai/n…

後語

你盼世界,我盼望你無bug。這篇文章就介紹到這裡。

您每週也許會花48小時的時間在工作💻上,會花49小時的時間在睡覺😴上,也許還可以再花20分鐘的時間在呆呆的7道題上,日積月累,我相信我們都能見證彼此的成長😊。

什麼?你問我為什麼系列的名字叫DD?因為呆呆呀,哈哈😄。

喜歡霖呆呆的小夥還希望可以關注霖呆呆的公眾號 LinDaiDai 或者掃一掃下面的二維碼👇👇👇。

我會不定時的更新一些前端方面的知識內容以及自己的原創文章🎉

你的鼓勵就是我持續創作的主要動力 😊。

本文使用 mdnice 排版