Ihsan Magazine – Kali ini kita akan mencoba belajar membuat Custom Element dasar di Javascript, apa itu Custom Element? Gampang nya Custom Element seperti kita Membuat Tag HTML baru untuk Front End Developer.
Bisa untuk memperluas elemen bawaan HTML, dan masih banyak lagi, dasarnya menggunakan Elements global digunakan untuk mendefinisikan elemen khusus dan mengajarkan tag baru pada browser.
Panggil customElements.define() dengan nama tag yang ingin Anda buat dan class JavaScript yang memperluas HTMLElement dasar.
Selengkapnya Baca Disini
Kali ini Study Kasus dengan ClubFinder.zip
Jika kita telaah dengan seksama, pada proyek Club Finder terdapat 4 (empat) bagian yang berpotensi untuk dijadikan custom element, yaitu:
- App Bar : Komponen di posisi atas yang menunjukkan identitas atau nama dari aplikasi web.
- Search Bar : Komponen yang terdiri dari elemen <input> dan <button> dan berfungsi untuk melakukan pencarian club sesuai dengan input pengguna.
- Club List : Komponen yang berfungsi untuk menampung data dari hasil pencarian, kemudian menampilkannya dalam bentuk list.
- Club Item : Komponen yang menampilkan data individual club yang diberikan dari club list. Komponen ini terdiri dari gambar, nama, dan deskripsi singkat club.
Solution: Membuat app-bar Component
- class AppBar extends HTMLElement {
- }
- class AppBar extends HTMLElement {
- connectedCallback(){
- }
- render() {
- }
- }
- class AppBar extends HTMLElement {
- connectedCallback(){
- this.render();
- }
- render() {
- }
- }
- <header>
- <div id="appBar" class="app-bar">
- <h2>Club Finder</h2>
- </div>
- </header>
- class AppBar extends HTMLElement {
- connectedCallback(){
- this.render();
- }
- render() {
- this.innerHTML = `<h2>Club Finder</h2>`;
- }
- }
- class AppBar extends HTMLElement {
- connectedCallback(){
- this.render();
- }
- render() {
- this.innerHTML = `<h2>Club Finder</h2>`;
- }
- }
- customElements.define("app-bar", AppBar);
- <header>
- <app-bar></app-bar>
- </header>
- import "./src/script/component/app-bar.js";
- import "./src/script/component/app-bar.js";
- import main from "./src/script/view/main.js";
- document.addEventListener("DOMContentLoaded", main);
- app-bar {
- padding: 16px;
- width: 100%;
- background-color: cornflowerblue;
- color: white;
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- }
- app-bar {
- display: block;
- padding: 16px;
- width: 100%;
- background-color: cornflowerblue;
- color: white;
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- }
Membuat search-bar Component
- class SearchBar extends HTMLElement {
- }
- class SearchBar extends HTMLElement {
- connectedCallback(){
- }
- render() {
- }
- }
- class SearchBar extends HTMLElement {
- connectedCallback(){
- this.render();
- }
- render() {
- }
- }
- <div id="search-container" class="search-container">
- <input placeholder="Search football club" id="searchElement" type="search">
- <button id="searchButtonElement" type="submit">Search</button>
- </div>
- class SearchBar extends HTMLElement {
- connectedCallback(){
- this.render();
- }
- render() {
- this.innerHTML = `
- <div id="search-container" class="search-container">
- <input placeholder="Search football club" id="searchElement" type="search">
- <button id="searchButtonElement" type="submit">Search</button>
- </div>
- `;
- }
- }
- class SearchBar extends HTMLElement {
- connectedCallback(){
- this.render();
- }
- set clickEvent(event) {
- this._clickEvent = event;
- this.render();
- }
- render() {
- this.innerHTML = `
- <div id="search-container" class="search-container">
- <input placeholder="Search football club" id="searchElement" type="search">
- <button id="searchButtonElement" type="submit">Search</button>
- </div>
- `;
- }
- }
- this.querySelector("#searchButtonElement").addEventListener("click", this._clickEvent);
- render() {
- this.innerHTML = `
- <div id="search-container" class="search-container">
- <input placeholder="Search football club" id="searchElement" type="search">
- <button id="searchButtonElement" type="submit">Search</button>
- </div>`;
- this.querySelector("#searchButtonElement").addEventListener("click", this._clickEvent);
- }
- get value() {
- return this.querySelector("#searchElement").value;
- }
- class SearchBar extends HTMLElement {
- connectedCallback(){
- this.render();
- }
- set clickEvent(event) {
- this._clickEvent = event;
- this.render();
- }
- get value() {
- return this.querySelector("#searchElement").value;
- }
- render() {
- this.innerHTML = `
- <div id="search-container" class="search-container">
- <input placeholder="Search football club" id="searchElement" type="search">
- <button id="searchButtonElement" type="submit">Search</button>
- </div>
- `;
- this.querySelector("#searchButtonElement").addEventListener("click", this._clickEvent);
- }
- }
- class SearchBar extends HTMLElement {
- connectedCallback(){
- this.render();
- }
- set clickEvent(event) {
- this._clickEvent = event;
- this.render();
- }
- get value() {
- return this.querySelector("#searchElement").value;
- }
- render() {
- this.innerHTML = `
- <div id="search-container" class="search-container">
- <input placeholder="Search football club" id="searchElement" type="search">
- <button id="searchButtonElement" type="submit">Search</button>
- </div>
- `;
- this.querySelector("#searchButtonElement").addEventListener("click", this._clickEvent);
- }
- }
- customElements.define("search-bar", SearchBar);
- <div id="search-container" class="search-container">
- <input placeholder="Search football club" id="searchElement" type="search">
- <button id="searchButtonElement" type="submit">Search</button>
- </div>
- <search-bar></search-bar>
- const searchElement = document.querySelector("#searchElement");
- const searchElement = document.querySelector("search-bar");
- const buttonSearchElement = document.querySelector("#searchButtonElement");
- buttonSearchElement.addEventListener("click", onButtonSearchClicked);
- searchElement.clickEvent = onButtonSearchClicked;
- import '../component/search-bar.js';
- import '../component/search-bar.js';
- import DataSource from '../data/data-source.js';
- const main = () => {
- const searchElement = document.querySelector("search-bar");
- const clubListElement = document.querySelector("#clubList");
- const onButtonSearchClicked = async () => {
- try {
- const result = await DataSource.searchClub(searchElement.value);
- renderResult(result);
- } catch (message) {
- fallbackResult(message)
- }
- };
- const renderResult = results => {
- clubListElement.innerHTML = "";
- results.forEach(club => {
- const { name, fanArt, description } = club;
- const clubElement = document.createElement("div");
- clubElement.setAttribute("class", "club");
- clubElement.innerHTML = `
- <img class="fan-art-club" src="${fanArt}" alt="Fan Art">
- <div class="club-info">
- <h2>${name}</h2>
- <p>${description}</p>
- </div>`;
- clubListElement.appendChild(clubElement);
- })
- };
- const fallbackResult = message => {
- clubListElement.innerHTML = "";
- clubListElement.innerHTML += `<h2 class="placeholder">${message}</h2>`;
- };
- searchElement.clickEvent = onButtonSearchClicked;
- };
- export default main;
Solution: Membuat club-list dan club-item Component
Membuat <club-list> element
- class ClubList extends HTMLElement {
- }
- class ClubList extends HTMLElement {
- set clubs(clubs) {
- }
- render() {
- }
- }
- set clubs(clubs) {
- this._clubs = clubs;
- this.render();
- }
- render() {
- this.innerHTML = "";
- this._clubs.forEach(club => {
- const clubItemElement = document.createElement("club-item");
- clubItemElement.club = club
- this.appendChild(clubItemElement);
- })
- }
- renderError(message) {
- }
- clubListElement.innerHTML = "";
- clubListElement.innerHTML += `<h2 class="placeholder">${message}</h2>`;
- renderError(message) {
- this.innerHTML = "";
- this.innerHTML += `<h2 class="placeholder">${message}</h2>`;
- }
- customElements.define("club-list", ClubList);
- import './club-item.js';
- import './club-item.js';
- class ClubList extends HTMLElement {
- set clubs(clubs) {
- this._clubs = clubs;
- this.render();
- }
- renderError(message) {
- this.innerHTML = "";
- this.innerHTML += `<h2 class="placeholder">${message}</h2>`;
- }
- render() {
- this.innerHTML = "";
- this._clubs.forEach(club => {
- const clubItemElement = document.createElement("club-item");
- clubItemElement.club = club
- this.appendChild(clubItemElement);
- })
- }
- }
- customElements.define("club-list", ClubList);
Membuat <club-item> element
- class ClubItem extends HTMLElement {
- }
- class ClubItem extends HTMLElement {
- set club(club) {
- }
- render() {
- }
- }
- class ClubItem extends HTMLElement {
- set club(club) {
- this._club = club;
- this.render();
- }
- render() {
- }
- }
- clubElement.innerHTML = `
- <img class="fan-art-club" src="${fanArt}" alt="Fan Art">
- <div class="club-info">
- <h2>${name}</h2>
- <p>${description}</p>
- </div>`;
- class ClubItem extends HTMLElement {
- set club(club) {
- this._club = club;
- this.render();
- }
- render() {
- this.innerHTML = `
- <img class="fan-art-club" src="${fanArt}" alt="Fan Art">
- <div class="club-info">
- <h2>${name}</h2>
- <p>${description}</p>
- </div>`;
- }
- }
- class ClubItem extends HTMLElement {
- set club(club) {
- this._club = club;
- this.render();
- }
- render() {
- this.innerHTML = `
- <img class="fan-art-club" src="${this._club.fanArt}" alt="Fan Art">
- <div class="club-info">
- <h2>${this._club.name}</h2>
- <p>${this._club.description}</p>
- </div>`;
- }
- }
- class ClubItem extends HTMLElement {
- set club(club) {
- this._club = club;
- this.render();
- }
- render() {
- this.innerHTML = `
- <img class="fan-art-club" src="${this._club.fanArt}" alt="Fan Art">
- <div class="club-info">
- <h2>${this._club.name}</h2>
- <p>${this._club.description}</p>
- </div>`;
- }
- }
- customElements.define("club-item", ClubItem);
Menggunakan <club-list> element
- <div id="clubList"></div>
- <club-list></club-list>
- const clubListElement = document.querySelector("#clubList");
- const clubListElement = document.querySelector("club-list");
- const renderResult = results => {
- clubListElement.innerHTML = "";
- results.forEach(club => {
- const { name, fanArt, description } = club;
- const clubElement = document.createElement("div");
- clubElement.setAttribute("class", "club");
- clubElement.innerHTML = `
- <img class="fan-art-club" src="${fanArt}" alt="Fan Art">
- <div class="club-info">
- <h2>${name}</h2>
- <p>${description}</p>
- </div>`;
- clubListElement.appendChild(clubElement);
- })
- };
- const renderResult = results => {
- clubListElement.clubs = results;
- };
- const fallbackResult = message => {
- clubListElement.renderError(message);
- };
- import '../component/club-list.js';
- import '../component/club-list.js';
- import '../component/search-bar.js';
- import DataSource from '../data/data-source.js';
- const main = () => {
- const searchElement = document.querySelector("search-bar");
- const clubListElement = document.querySelector("club-list");
- const onButtonSearchClicked = async () => {
- try {
- const result = await DataSource.searchClub(searchElement.value);
- renderResult(result);
- } catch (message) {
- fallbackResult(message)
- }
- };
- const renderResult = results => {
- clubListElement.clubs = results;
- };
- const fallbackResult = message => {
- clubListElement.renderError(message);
- };
- searchElement.clickEvent = onButtonSearchClicked;
- };
- export default main;
- club-list {
- margin-top: 32px;
- width: 100%;
- padding: 16px;
- }
- club-list > .placeholder {
- font-weight: lighter;
- color: rgba(0,0,0,0.5);
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- }
- club-item {
- margin-bottom: 18px;
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- border-radius: 10px;
- overflow: hidden;
- }
- club-item .fan-art-club {
- width: 100%;
- max-height: 300px;
- object-fit: cover;
- object-position: center;
- }
- .club-info {
- padding: 24px;
- }
- .club-info > h2 {
- font-weight: lighter;
- }
- .club-info > p {
- margin-top: 10px;
- overflow: hidden;
- text-overflow: ellipsis;
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 10; /* number of lines to show */
- }
- club-list {
- display: block;
- ….
- }
- ….
- club-item {
- display: block;
- ….
- }
- ….
- club-list {
- display: block;
- margin-top: 32px;
- width: 100%;
- padding: 16px;
- }
- club-list > .placeholder {
- font-weight: lighter;
- color: rgba(0,0,0,0.5);
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- }
- club-item {
- display: block;
- margin-bottom: 18px;
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- border-radius: 10px;
- overflow: hidden;
- }
- club-item .fan-art-club {
- width: 100%;
- max-height: 300px;
- object-fit: cover;
- object-position: center;
- }
- .club-info {
- padding: 24px;
- }
- .club-info > h2 {
- font-weight: lighter;
- }
- .club-info > p {
- margin-top: 10px;
- overflow: hidden;
- text-overflow: ellipsis;
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 10; /* number of lines to show */
- }
Shadow DOM
Menerapkan Shadow DOM pada Proyek Club Finder
- class AppBar extends HTMLElement {
- constructor() {
- super();
- this.shadowDOM = this.attachShadow({mode: "open"});
- }
- connectedCallback(){
- this.render();
- }
- render() {
- this.innerHTML = `<h2>Club Finder</h2>`;
- }
- }
- customElements.define("app-bar", AppBar);
- class AppBar extends HTMLElement {
- constructor() {
- super();
- this.shadowDOM = this.attachShadow({mode: "open"});
- }
- connectedCallback(){
- this.render();
- }
- render() {
- this.shadowDOM.innerHTML = `<h2>Club Finder</h2>`;
- }
- }
- customElements.define("app-bar", AppBar);
- app-bar {
- display: block;
- padding: 16px;
- width: 100%;
- background-color: cornflowerblue;
- color: white;
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- }
- class AppBar extends HTMLElement {
- constructor() {
- super();
- this.shadowDOM = this.attachShadow({mode: "open"});
- }
- connectedCallback(){
- this.render();
- }
- render() {
- this.shadowDOM.innerHTML = `
- <style>
- app-bar {
- display: block;
- padding: 16px;
- width: 100%;
- background-color: cornflowerblue;
- color: white;
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- }
- </style>
- <h2>Club Finder</h2>`;
- }
- }
- customElements.define("app-bar", AppBar);
- class AppBar extends HTMLElement {
- constructor() {
- super();
- this.shadowDOM = this.attachShadow({mode: "open"});
- }
- connectedCallback(){
- this.render();
- }
- render() {
- this.shadowDOM.innerHTML = `
- <style>
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
- :host {
- display: block;
- width: 100%;
- background-color: cornflowerblue;
- color: white;
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- }
- h2 {
- padding: 16px;
- }
- </style>
- <h2>Club Finder</h2>`;
- }
- }
- customElements.define("app-bar", AppBar);
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
- @import "clublist.css";
- @import "searchbar.css";
- * {
- padding: 0;
- margin: 0;
- box-sizing: border-box;
- }
- body {
- font-family: sans-serif;
- }
- main {
- width: 90%;
- max-width: 800px;
- margin: 32px auto;
- }
Menerapkan Shadow DOM pada Search Bar
- class SearchBar extends HTMLElement {
- constructor() {
- super();
- this.shadowDOM = this.attachShadow({mode: "open"});
- }
- connectedCallback(){
- this.render();
- }
- set clickEvent(event) {
- this._clickEvent = event;
- this.render();
- }
- get value() {
- return this.querySelector("#searchElement").value;
- }
- render() {
- this.innerHTML = `
- <div id="search-container" class="search-container">
- <input placeholder="Search football club" id="searchElement" type="search">
- <button id="searchButtonElement" type="submit">Search</button>
- </div>
- `;
- this.querySelector("#searchButtonElement").addEventListener("click", this._clickEvent);
- }
- }
- customElements.define("search-bar", SearchBar);
- class SearchBar extends HTMLElement {
- constructor() {
- super();
- this.shadowDOM = this.attachShadow({mode: "open"});
- }
- connectedCallback(){
- this.render();
- }
- set clickEvent(event) {
- this._clickEvent = event;
- this.render();
- }
- get value() {
- return this.querySelector("#searchElement").value;
- }
- render() {
- this.shadowDOM.innerHTML = `
- <div id="search-container" class="search-container">
- <input placeholder="Search football club" id="searchElement" type="search">
- <button id="searchButtonElement" type="submit">Search</button>
- </div>
- `;
- this.querySelector("#searchButtonElement").addEventListener("click", this._clickEvent);
- }
- }
- customElements.define("search-bar", SearchBar);
- class SearchBar extends HTMLElement {
- ..........
- get value() {
- return this.shadowDOM.querySelector("#searchElement").value;
- }
- render() {
- .........
- this.shadowDOM.querySelector("#searchButtonElement").addEventListener("click", this._clickEvent);
- }
- }
- ...........
- .search-container {
- max-width: 800px;
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- padding: 16px;
- border-radius: 5px;
- display: flex;
- position: sticky;
- top: 10px;
- background-color: white;
- }
- .search-container > input {
- width: 75%;
- padding: 16px;
- border: 0;
- border-bottom: 1px solid cornflowerblue;
- font-weight: bold;
- }
- .search-container > input:focus {
- outline: 0;
- border-bottom: 2px solid cornflowerblue;
- }
- .search-container > input:focus::placeholder {
- font-weight: bold;
- }
- .search-container > input::placeholder {
- color: cornflowerblue;
- font-weight: normal;
- }
- .search-container > button {
- width: 23%;
- cursor: pointer;
- margin-left: auto;
- padding: 16px;
- background-color: cornflowerblue;
- color: white;
- border: 0;
- text-transform: uppercase;
- }
- @media screen and (max-width: 550px){
- .search-container {
- flex-direction: column;
- position: static;
- }
- .search-container > input {
- width: 100%;
- margin-bottom: 12px;
- }
- .search-container > button {
- width: 100%;
- }
- }
- class SearchBar extends HTMLElement {
- .........
- render() {
- this.shadowDOM.innerHTML = `
- <style>
- .search-container {
- max-width: 800px;
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- padding: 16px;
- border-radius: 5px;
- display: flex;
- position: sticky;
- top: 10px;
- background-color: white;
- }
- .search-container > input {
- width: 75%;
- padding: 16px;
- border: 0;
- border-bottom: 1px solid cornflowerblue;
- font-weight: bold;
- }
- .search-container > input:focus {
- outline: 0;
- border-bottom: 2px solid cornflowerblue;
- }
- .search-container > input:focus::placeholder {
- font-weight: bold;
- }
- .search-container > input::placeholder {
- color: cornflowerblue;
- font-weight: normal;
- }
- .search-container > button {
- width: 23%;
- cursor: pointer;
- margin-left: auto;
- padding: 16px;
- background-color: cornflowerblue;
- color: white;
- border: 0;
- text-transform: uppercase;
- }
- @media screen and (max-width: 550px){
- .search-container {
- flex-direction: column;
- position: static;
- }
- .search-container > input {
- width: 100%;
- margin-bottom: 12px;
- }
- .search-container > button {
- width: 100%;
- }
- }
- </style>
- <div id="search-container" class="search-container">
- <input placeholder="Search football club" id="searchElement" type="search">
- <button id="searchButtonElement" type="submit">Search</button>
- </div>
- `;
- .......
- }
- }
- customElements.define("search-bar", SearchBar);
- @import "clublist.css";
- * {
- padding: 0;
- margin: 0;
- box-sizing: border-box;
- }
- body {
- font-family: sans-serif;
- }
- main {
- width: 90%;
- max-width: 800px;
- margin: 32px auto;
- }
Menerapkan Shadow DOM pada Club List dan Club Item
- import './club-item.js';
- class ClubList extends HTMLElement {
- constructor() {
- super();
- this.shadowDOM = this.attachShadow({mode: "open"});
- }
- set clubs(clubs) {
- this._clubs = clubs;
- this.render();
- }
- renderError(message) {
- this.innerHTML = "";
- this.innerHTML += `<h2 class="placeholder">${message}</h2>`;
- }
- render() {
- this.innerHTML = "";
- this._clubs.forEach(club => {
- const clubItemElement = document.createElement("club-item");
- clubItemElement.club = club
- this.appendChild(clubItemElement);
- })
- }
- }
- customElements.define("club-list", ClubList);
- import './club-item.js';
- class ClubList extends HTMLElement {
- constructor() {
- super();
- this.shadowDOM = this.attachShadow({mode: "open"});
- }
- set clubs(clubs) {
- this._clubs = clubs;
- this.render();
- }
- renderError(message) {
- this.shadowDOM.innerHTML = "";
- this.shadowDOM.innerHTML += `<h2 class="placeholder">${message}</h2>`;
- }
- render() {
- this.shadowDOM.innerHTML = "";
- this._clubs.forEach(club => {
- const clubItemElement = document.createElement("club-item");
- clubItemElement.club = club
- this.shadowDOM.appendChild(clubItemElement);
- })
- }
- }
- customElements.define("club-list", ClubList);
- club-list > .placeholder {
- font-weight: lighter;
- color: rgba(0,0,0,0.5);
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- }
- import './club-item.js';
- class ClubList extends HTMLElement {
- .........
- renderError(message) {
- this.shadowDOM.innerHTML = `
- <style>
- club-list > .placeholder {
- font-weight: lighter;
- color: rgba(0,0,0,0.5);
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- }
- </style>
- `;
- this.shadowDOM.innerHTML += `<h2 class="placeholder">${message}</h2>`;
- }
- .......
- }
- customElements.define("club-list", ClubList);
- import './club-item.js';
- class ClubList extends HTMLElement {
- constructor() {
- super();
- this.shadowDOM = this.attachShadow({mode: "open"});
- }
- set clubs(clubs) {
- this._clubs = clubs;
- this.render();
- }
- renderError(message) {
- this.shadowDOM.innerHTML = `
- <style>
- .placeholder {
- font-weight: lighter;
- color: rgba(0,0,0,0.5);
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- }
- </style>
- `;
- this.shadowDOM.innerHTML += `<h2 class="placeholder">${message}</h2>`;
- }
- render() {
- this.shadowDOM.innerHTML = "" ;
- this._clubs.forEach(club => {
- const clubItemElement = document.createElement("club-item");
- clubItemElement.club = club
- this.shadowDOM.appendChild(clubItemElement);
- })
- }
- }
- customElements.define("club-list", ClubList);
- class ClubItem extends HTMLElement {
- constructor() {
- super();
- this.shadowDOM = this.attachShadow({mode: "open"});
- }
- set club(club) {
- this._club = club;
- this.render();
- }
- render() {
- this.innerHTML = `
- <img class="fan-art-club" src="${this._club.fanArt}" alt="Fan Art">
- <div class="club-info">
- <h2>${this._club.name}</h2>
- <p>${this._club.description}</p>
- </div>`;
- }
- }
- customElements.define("club-item", ClubItem);
- class ClubItem extends HTMLElement {
- constructor() {
- super();
- this.shadowDOM = this.attachShadow({mode: "open"});
- }
- set club(club) {
- this._club = club;
- this.render();
- }
- render() {
- this.shadowDOM.innerHTML = `
- <img class="fan-art-club" src="${this._club.fanArt}" alt="Fan Art">
- <div class="club-info">
- <h2>${this._club.name}</h2>
- <p>${this._club.description}</p>
- </div>`;
- }
- }
- customElements.define("club-item", ClubItem);
- club-item {
- display: block;
- margin-bottom: 18px;
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- border-radius: 10px;
- overflow: hidden;
- }
- club-item .fan-art-club {
- width: 100%;
- max-height: 300px;
- object-fit: cover;
- object-position: center;
- }
- .club-info {
- padding: 24px;
- }
- .club-info > h2 {
- font-weight: lighter;
- }
- .club-info > p {
- margin-top: 10px;
- overflow: hidden;
- text-overflow: ellipsis;
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 10; /* number of lines to show */
- }
- class ClubItem extends HTMLElement {
- .......
- render() {
- this.shadowDOM.innerHTML = `
- <style>
- club-item {
- display: block;
- margin-bottom: 18px;
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- border-radius: 10px;
- overflow: hidden;
- }
- club-item .fan-art-club {
- width: 100%;
- max-height: 300px;
- object-fit: cover;
- object-position: center;
- }
- .club-info {
- padding: 24px;
- }
- .club-info > h2 {
- font-weight: lighter;
- }
- .club-info > p {
- margin-top: 10px;
- overflow: hidden;
- text-overflow: ellipsis;
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 10; /* number of lines to show */
- }
- </style>
- <img class="fan-art-club" src="${this._club.fanArt}" alt="Fan Art">
- <div class="club-info">
- <h2>${this._club.name}</h2>
- <p>${this._club.description}</p>
- </div>`;
- }
- }
- ......
- class ClubItem extends HTMLElement {
- .....
- render() {
- this.shadowDOM.innerHTML = `
- <style>
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
- :host {
- display: block;
- margin-bottom: 18px;
- box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
- border-radius: 10px;
- overflow: hidden;
- }
- .fan-art-club {
- width: 100%;
- max-height: 300px;
- object-fit: cover;
- object-position: center;
- }
- .club-info {
- padding: 24px;
- }
- .club-info > h2 {
- font-weight: lighter;
- }
- .club-info > p {
- margin-top: 10px;
- overflow: hidden;
- text-overflow: ellipsis;
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 10; /* number of lines to show */
- }
- </style>
- <img class="fan-art-club" src="${this._club.fanArt}" alt="Fan Art">
- <div class="club-info">
- <h2>${this._club.name}</h2>
- <p>${this._club.description}</p>
- </div>`;
- }
- }
- ........
- club-list {
- display: block;
- margin-top: 32px;
- width: 100%;
- padding: 16px;
- }
- @import "clublist.css";
- * {
- padding: 0;
- margin: 0;
- box-sizing: border-box;
- }
- body {
- font-family: sans-serif;
- }
- main {
- width: 90%;
- max-width: 800px;
- margin: 32px auto;
- }
- club-list {
- display: block;
- margin-top: 32px;
- width: 100%;
- padding: 16px;
- }