Mulai cepat dengan WebComponents

Komponen web adalah seperangkat standar yang mendefinisikan antarmuka perangkat lunak untuk mengatur arsitektur komponen. Semuanya diimplementasikan dalam versi browser modern, mis. mereka tidak memerlukan menghubungkan pustaka atau transponder kode, namun, jika Anda memerlukan kompatibilitas, misalnya, dengan Internet Explorer 11, maka Anda mungkin masih perlu menggunakan perpustakaan dan transponder.

Artikel ini ditujukan untuk pelatihan tingkat awal dan pengembang yang memiliki pengalaman dengan satu atau beberapa kerangka kerja front-end, tetapi mungkin, berkat beberapa trik, ini akan menarik bagi para ahli yang berpengalaman.

Semua percobaan yang dikutip di bawah ini diuji di Chrome dan Firefox bahkan mungkin bukan versi terbaru.

Jadi mari kita mulai.

Pertama, buat direktori untuk proyek dan pergi ke sana.

mkdir mywebcomp cd mywebcomp 

Jalankan:

 npm init 

dalam direktori ini dengan menjawab semua pertanyaan secara default.

Buat file index.html dengan konten paling sederhana di direktori.

 <html lang="en"> <body> </body> </html> 

Tambahkan tag untuk elemen, nama harus berisi tanda hubung, ini adalah sinyal untuk subsistem CusomElements untuk mencoba mendefinisikan elemen ini sebagai bangunan di atas yang standar.

 <html lang="en"> <body> <my-webcomp></my-webcomp> </body> </html> 

Tambahkan kelas penangan ke tag skrip .

 <script type="module"> class MyWebComp extends HTMLElement { connectedCallback() { this.insertAdjacentHTML('beforeEnd', `<div>Hello</div>`) } } customElements.define('my-webcomp', MyWebComp); </script> 

Dalam tag skrip modular, kami mendefinisikan kelas baru yang, menggunakan metode customElements.define () , mendefinisikannya di belakang tag my-webcomp . Dan dengan menambahkan kode ke metode connectedCallback () , kami memberikan panggilan ketika menambahkan implementasi komponen ke struktur pohon. Hasilnya sudah bisa dilihat di browser:



Namun, menempatkan tata letak html langsung dalam kode, jika nyaman untuk potongan kecil, umumnya tidak benar, yang terutama benar ketika potongan tumbuh ke ukuran yang layak. Misalnya, pada formulir dengan 20 elemen, yang dikalahkan pada subkomponen juga mungkin tidak selalu nyaman. Oleh karena itu, sebagai permulaan, kami akan meletakkan tata letak dalam templat, yang akan berlokasi di html yang sama, meskipun tidak ada yang mencegah kami memuatnya dari file terpisah jika perlu.

 <html lang="en"> <body> <template id="myWebCompTemplate"> <div>Hello</div> </template> <my-webcomp></my-webcomp> <script type="module"> class MyWebComp extends HTMLElement { connectedCallback() { let tplEl = document.querySelector('#myWebCompTemplate'); let html = document.importNode(tplEl.content, true); this.appendChild(html); } } customElements.define('my-webcomp', MyWebComp); </script> </body> </html> 

Dalam kode komponen, kami mengganti penyisipan string dengan html dengan menerima elemen template oleh id. Impor yaitu membuat salinan elemen ini dan menautkan ke konten yang sekarang.

id dinamai dalam notasi camelCase sejak itu semua pengidentifikasi elemen dilemparkan ke namespace global saat menggunakan tanda hubung atau spesial lainnya. akses karakter mereka mungkin kurang elegan. Yaitu sebaliknya kita bisa:

  let tplEl = document.querySelector('#myWebCompTemplate'); let html = document.importNode(tplEl.content, true); 

tulis dalam satu baris:

 let html = document.importNode(myWebCompTemplate.content, true); 

dan kode ini akan bekerja dengan cara yang sama, tetapi dianggap tidak terlalu aman. Selain itu, jika kami menetapkan id ke elemen kami, kami dapat mengaksesnya dari mana saja dalam konteks sebagai instance dari namespace global dengan memanggil metode dan mendapatkan nilai properti.
Misalnya, seperti ini:

 <my-webcomp id="myWebComp"></my-webcomp> <script type="module"> class MyWebComp extends HTMLElement { connectedCallback() { let html = document.importNode(myWebCompTemplate.content, true); this.appendChild(html); } } customElements.define('my-webcomp', MyWebComp); </script> <script type="module"> myWebComp.showMessage(); </script> 

Dalam skenario ini, peringatan akan segera ditampilkan ketika halaman dimuat.

Sekarang kita akan menggantung handler klik mouse untuk komponen kita yang akan menampilkan pesan peringatan.

 <my-webcomp id="myWebComp" onclick="this.showMessage(event)"></my-webcomp> <script type="module"> class MyWebComp extends HTMLElement { connectedCallback() { let html = document.importNode(myWebCompTemplate.content, true); this.appendChild(html); } showMessage(event) { alert("This is the message"); console.log(event); } } customElements.define('my-webcomp', MyWebComp); </script> 

Sekarang, ketika Anda mengklik pesan, kami akan bereaksi terhadap tindakan pengguna.



Argumen ke metode showMessage () juga menyatakan objek acara yang menyimpan data acara, seperti koordinat klik atau tautan ke elemen itu sendiri.

Seringkali, setiap elemen tertentu harus dikonfigurasi dengan cara yang unik untuk itu, ini dapat dilakukan dengan menggunakan atribut.

Tambahkan instance kedua elemen dan tentukan untuk masing-masing dari mereka properti nama-salam berbeda yang nilainya akan ditampilkan ketika elemen diklik.

 <my-webcomp id="myWebComp" greet-name="John" onclick="this.showMessage(event)"></my-webcomp> <my-webcomp id="myWebComp2" greet-name="Josh" onclick="this.showMessage(event)"></my-webcomp> <script type="module"> class MyWebComp extends HTMLElement { connectedCallback() { let html = document.importNode(myWebCompTemplate.content, true); this.appendChild(html); } showMessage(event) { alert("This is the message " + this.getAttribute('greet-name')); console.log(event); } } customElements.define('my-webcomp', MyWebComp); </script> 

Sekarang, ketika Anda mengklik yang pertama, "Ini adalah pesan untuk John" akan ditampilkan, dan yang kedua, "Ini adalah pesan untuk Josh".

Mungkin saja atribut tersebut harus digunakan bukan dalam pemrosesan acara, tetapi langsung dirender ke dalam templat, untuk ini kami akan menambahkan id ke elemen target dan mengganti nilai dari api segera setelah merender salinan objek templat.

 <template id="myWebCompTemplate"> <div id="helloLabel">Hello</div> </template> <my-webcomp id="myWebComp" greet-name="John" onclick="this.showMessage(event)"></my-webcomp> <my-webcomp id="myWebComp2" greet-name="Josh" onclick="this.showMessage(event)"></my-webcomp> <script type="module"> class MyWebComp extends HTMLElement { connectedCallback() { let html = document.importNode(myWebCompTemplate.content, true); this.appendChild(html); this.querySelector('#helloLabel').textContent += ' ' + this.getAttribute('greet-name'); } showMessage(event) { alert("This is the message " + this.getAttribute('greet-name')); console.log(event); } } customElements.define('my-webcomp', MyWebComp); </script> 

Ternyata seperti ini:



Alih-alih .textContent bisa berupa .innerHTML atau Anda dapat memanggil metode .insertAdjacentHTML () yang sama pada objek dari pemilih yang kami lakukan di awal.

Untuk waktu yang lama, menggunakan ID dianggap sebagai bentuk yang buruk, karena pada sejumlah besar kode mereka dapat diduplikasi, yang menyebabkan benturan. Namun, dengan munculnya teknologi pohon bayangan, Anda dapat mengisolasi konten internal suatu elemen menggunakan pengidentifikasi, gaya, dan sumber daya lainnya tanpa rasa takut. Untuk komponen web, pohon bayangan diaktifkan sebagai berikut:

  this.attachShadow({mode: 'open'}); 

Sekarang kebenarannya adalah bahwa semua panggilan DOM untuk ini harus diganti dengan this.shadowRoot, karena jumlahnya tidak begitu banyak.

 <script type="module"> class MyWebComp extends HTMLElement { connectedCallback() { let html = document.importNode(myWebCompTemplate.content, true); this.attachShadow({mode: 'open'}); this.shadowRoot.appendChild(html); this.shadowRoot.querySelector('#helloLabel').textContent += ' ' + this.getAttribute('greet-name'); } showMessage(event) { alert("This is the message " + this.getAttribute('greet-name')); console.log(event); } } customElements.define('my-webcomp', MyWebComp); </script> 

Secara visual, pekerjaan kode ini tidak akan berubah lagi dengan cara apa pun, tetapi sekarang tidak akan ada helloLabel di namespace global, dan halaman tersebut sudah memiliki 2 elemen dengan pengenal ini. Dan Anda dapat mengaksesnya, misalnya, seperti ini:

 myWebComp.shadowRoot.getElementById('helloLabel'); 

dan kemudian jika Anda tidak menutup pohon dengan meneruskan atribut yang sesuai dalam metode .attachShadow () .

Kami mendapat cukup banyak kode dan menempatkannya langsung di file html juga tidak terlalu benar. Oleh karena itu, kami akan membuat file my-webcomp.js dan mentransfer kelas kami ke sana dengan pernyataan ekspor, dan menambahkan impor kelas ini dalam tag skrip untuk mendapatkan ini:

 <script type="module"> import { MyWebComp } from "./my-webcomp.js"; customElements.define('my-webcomp', MyWebComp); myWebComp.shadowRoot.getElementById('helloLabel'); </script> 

Ini tidak akan memengaruhi kinerja, tetapi sekarang semua logika bisnis kami terpisah dalam .js, konfigurasi dilakukan dalam atribut html, dan sistem peramban komponen dan modular menangani inisialisasi asinkron modular.

Namun, mulai sekarang, membuka index.html sebagai lokal untuk pengembangan akan gagal, karena browser akan memblokir unduhan skrip dari sistem file. Jika Anda memiliki nodejs, Anda dapat menempatkan server web paling sederhana:

 npm i http-server -g 

dan jalankan dengan perintah http-server di direktori proyek, saat startup itu akan memberi tahu host dan port dari mana Anda dapat membuka halaman

 http://127.0.0.1:8080 

Yang sekarang akan menjadi alamat halaman debug dengan elemen kami.

Tes menulis juga penting untuk pengembangan, mereka membantu menjaga kode bisa berfungsi selama pengembangan komponennya. Untuk menguji komponen web, Anda dapat menggunakan moka dalam mode peluncuran dari browser.

Tambahkan paket.

 npm i mocha chai wct-mocha --save-dev 

Untuk melakukan ini, buat direktori pengujian dan tambahkan file all.html berikut ke dalamnya:

 <!doctype html> <html> <head> <meta charset="utf-8"> <script src="../node_modules/mocha/mocha.js"></script> <script src="../node_modules/chai/chai.js"></script> <script src="../node_modules/wct-mocha/wct-mocha.js"></script> </head> <body> <script> WCT.loadSuites([ 'my-webcomp.tests.html', ]); </script> </body> </html> 

Salin index.html kami untuk menguji / memberinya nama my-webcomp.tests.html dan menambahkan konten kepala yang sama seperti di all.html .

Namun, kita sekarang perlu mengganti inisialisasi dan manipulasi yang biasa dengan yang dilakukan sebagai bagian dari uji coba:

 <script type="module"> import { MyWebComp } from "../my-webcomp.js"; customElements.define('my-webcomp', MyWebComp); suite('MyWebComp', () => { test('is MyWebComp', () => { const element = document.getElementById('myWebComp'); chai.assert.instanceOf(element, MyWebComp); }); }); </script> 

Sekarang saat masuk

 http://127.0.0.1:8080/test/all.html 

Laporan pengujian akan ditampilkan.



Tetapi Anda mungkin perlu menjalankan tes secara otomatis dan di berbagai browser Anda perlu menginstal utilitas khusus:

 sudo npm install --global web-component-tester --unsafe-perm 

dan jalankan seperti ini:

 wct --npm 

Baris ini dapat ditambahkan ke bagian uji file package.json dan jalankan sebagai:

 npm test 



Dianjurkan untuk menguji setiap metode kelas yang signifikan sebagai bagian dari tes terpisah. Jika perlu untuk membuat inisialisasi umum untuk masing-masing, itu harus didefinisikan dalam metode suiteSetup () :

 suiteSetup(() => { }); 

di dalam suite.

Ini mungkin cukup untuk pertama kalinya, kami mendapat beberapa proyek minimal bahwa jika ia menyelesaikan tugas tertentu, ia tidak akan malu melakukannya.

 npm publish 

atau setidaknya

 git push 

Belum ada banyak buku tentang topik ini, tetapi semua dokumentasi yang luas mudah ditemukan sesuai dengan Komponen Web, CustomElements, ShadowDOM, Tag Template Asli, Acara Kustom.

Anda dapat memverifikasi kode Anda dengan repositori: https://bitbucket.org/techminded/mywebcomp

Kelanjutan dari topik yang menunjukkan bagaimana berinteraksi antara komponen melalui penggunaan acara dapat ditemukan di sini.

Source: https://habr.com/ru/post/id460397/


All Articles