<expanding-list>
Customized built-in elements (MDN), source code (GitHub)
helpers.js 👉 JS 常用函數
這個範例完全使用 light DOM 的內容,並沒有用到 shadow DOM。
/*
Customized built-in elements
----------------------------
https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements
Terms used in the following code
--------------------------------
• folder: <li> containing <ul>
• folder content: child <ul> (excluding host <ul>)
• folder title: <span> added by JS
*/
// customized built-in element
class ExpandingList extends HTMLUListElement {
constructor() {
// initialize HTMLUListElement
super();
// ⭐️ all folders
this.folders = Array
.from(this.$all('li'))
.filter(li => li.$all('ul').length > 0);
// for each folder
this.folders.forEach(li => {
// folder is closed by default
li.attr('class', 'closed');
// ⭐️ wrap <li>'s text in <span> in order to
// assign style and event handlers to the <span>
let textNode = li.firstChild; // `Text` node
const span = tag('span', {
textContent: textNode.textContent,
});
// decorate with Font Awesome (folder icon)
span.insertAdjacentHTML('afterbegin',
'<i class="fas fa-folder"></i>'
);
// add click handler
span.onclick = function(e){
const span = e.target; // folder title (<span>)
const li = span.parentNode; // folder (<li>)
const i = span.firstElementChild; // folder icon (<i>)
li.classList.toggle('closed'); // toggle folder status
// toggle folder icon
i.classList.toggle('fa-folder-open');
i.classList.toggle('fa-folder');
};
// prepend <span>, remove textNode
li.prepend(span);
textNode.remove();
});
}// end: constructor()
_openFolder(li){
// change folder status to open
li.classList.remove('closed');
// change to open folder icon
const i = li.$('span > i');
i.classList.add('fa-folder-open');
i.classList.remove('fa-folder');
}
// expand all folders
expandAll(){
this.folders.forEach(li => this._openFolder(li));
}
}// end: ExpandingList
// register <expanding-list>
customElements.define('expanding-list', ExpandingList, { extends: 'ul' });
Last updated
Was this helpful?