這篇延續上篇的波浪字體繼續進行講解
昨天說到javascript的部分可以從兩個部份來講解
<label>中的每個字母分開獨立包在<span>中以上兩點若轉換為程式碼,大概是如下這樣,不過這單純只是示意用喔~
<!-- Before -->
<label>Email</label>
<!-- After -->
<label>
<span style="transition-delay: 0ms">E</span>
<span style="transition-delay: 50ms">m</span>
<span style="transition-delay: 100ms">a</span>
<span style="transition-delay: 150ms">i</span>
<span style="transition-delay: 200ms">l</span>
</label>
實際上的程式碼是這樣
let labels = document.querySelectorAll(".form-control label");
console.log(labels); //NodeList(2) [label, label](類陣列)
labels.forEach((label) => {
label.innerHTML = label.innerText
.split("")
.map(
(letter, index) =>
`<span style="transition-delay:${index * 50}ms">${letter}</span>`
)
.join("");
});
HTMLElement.innerHTML returns all text, including html tags, that is contained by an element.
HTMLElement.innerText returns all text contained by an element and all its child elements.
innerHTML會選取到的是整個HTML tag,只要是在標籤內的所有內容,像是文字、子標籤都會被選到innerText會選取標籤和子標籤內的文字部分
上面我把labels這個變數印出來會得到NodeList(2) [label, label],再進一步展開來會看到

疑?哪安餒,明明就看起來一樣阿!!
不過還是有一點差別的,只是因為這個例子蒙蔽了我們的雙眼,下面這個例子就可以看出差異了
<div id="test">
This is the test for<b>innerHTML and innerText</b>:
<ul>
<li><a href="#"><b>Hello World</b></a></li>
<li><a href="#">Welcome To Be A<b>Front-end Engineer</b></a></li>
</ul>
</div>
let a = document.getElementById('test').innerText
console.log(a)
let b = document.getElementById('test').innerHTML
console.log(b)
印出來的結果如下,想看完整範例檔點此
至於賽project中寫label.innerHTML = label.innerText...(後面省略)
是因為我們要選取每個<label>標籤,並把標籤內的內容重新賦值為 <span style="transition-delay: 0ms">E</span>,
擷取MDN上的解釋
The split() method takes a pattern and divides a String into an ordered list of substrings by searching for the pattern, puts these substrings into an array, and returns the array.
split()是字串處理方法,它可以將原字串依照指定的分割符(separator)拆分成子字串,並放入陣列中回傳

console.log(label.innerText); //Email Password
出於好奇心,想看看所有的東西內部到底是啥,所以把label.innerText印出來,會得到Email、Password,資料型別是string,那我們要把它拆分成E、m、a、i、l並放入一個陣列中,最好用的當然就是split()啦~它可以把原字串依照指定的符號分割成子字串,並放入陣列中回傳
console.log(label.innerText.split("")); //['E', 'm', 'a', 'i', 'l'] ['P', 'a', 's', 's', 'w', 'o', 'r', 'd']
擷取MDN上的解釋
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
意思上大致是說map()會創建一個新的array並回傳,我們可以用map()來迭代陣列內的每個元素

那我把我們賽project的部分程式碼複製下來看,不然一直捲捲很麻煩
label.innerText
.split("")
.map(
(letter, index) =>
`<span style="transition-delay:${idx * 50}ms">${letter}</span>`
)
我們利用map(letter, idx)=>{...省略...}來迭代陣列中的元素讓它去做我們想讓它做的事,在這裡又發揮了我雞婆的精神(?),把兩個參數印出來看看XD
console.log(letter, index);
打開開發者工具,呈現如下

回想一下一開始所說的,字母是一個接著一個呈現高低起伏的效果,如同波浪一樣,下一個字母會比上一個字母延遲一下再上升 這句話一直在我腦海中迴盪~
我得到了每個字母,那我不是可以把每個字母放在
<span>中嗎?
我得到了每個字母的順序,那我不是可以依照它的先後順序來控制延遲時間transition-delay嗎?
看到這裡開始覺得熱血沸騰了?好像搞懂為甚麼要這樣寫了?
所以<span style="transition-delay:${idx * 50}ms">${letter}</span>
就是 <span style="transition-delay: 0ms">E</span> (比較直覺式的呈現XD)
記得要加上ms
[注意]map()常被拿來跟forEach()做比較,這裡可以參考這篇文章
擷取MDN上的解釋
The join() method creates and returns a new string by concatenating all of the elements in an array (or an array-like object), separated by commas or a specified separator string.
意思大致上是說map()會將陣列或一個類陣列集合(array-like collection)中所有的元素連接、合併成一個字串(根據join()中的給的參數),並回傳。

我們的程式碼我再把它貼下來來一次
let labels = document.querySelectorAll(".form-control label");
console.log(labels); //NodeList(2) [label, label](類陣列)
labels.forEach((label) => {
label.innerHTML = label.innerText
.split("")
.map(
(letter, index) =>
`<span style="transition-delay:${index * 50}ms">${letter}</span>`
)
.join("");
});
上面map()會回傳的是一個新的陣列,但是我們要的是"字串"而不是陣列,所以這時候join()就登場了!! 原本['E','m','a','i','l']因為.join("")的加入,變成"Email",字串的形式
為了配合javaScript新增加的CSS
.form-control label span {
display: inline-block;
font-size: 18px;
min-width: 5px;
transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.form-control input:focus + label span,
.form-control input:valid + label span {
color: lightblue;
transform: translateY(-30px);
}
字母的波浪在:focus跟:valid的狀態時會向上移動,所以transform: translateY(-30px)代表字母會往y軸的方向往上移動30px,並且為了讓動畫更平滑更自然一點,加上transition的timing-function為貝茲曲線(Cubic Bezier)
cubic-bezier(x1,y1,x2,y2)是一個連續曲線,總共有四個點,分別是第一個貝茲曲線控制點x1和y1以及第二個貝茲曲線控制點x2和y2、此外,x1、x2的範圍為0-1,y1,y2的範圍就不侷限,可以是負數,藉由控制Cubic Bezier,我們可以更容易的做出加減速的效果
附上codepen連結https://codepen.io/hangineer/pen/NWMbNZL
那今天的部分就先到這啦
若有解說不夠詳盡或是錯誤歡迎指教,感激不盡!那明天見囉![]()
Difference Between textContents, innerText, and innerHtml
MDN-Array.prototype.map()
非常彈性好用的陣列 Array 方法 map()
CSS3 Cubic Bezier