Web Bileşeninden Edebiyat Öğesine

1. Giriş

Son Güncelleme: 2021-08-10

Web Bileşenleri

Web bileşenleri, web sayfalarında ve web uygulamalarında kullanmak üzere yeni özel, yeniden kullanılabilir, kapsüllenmiş HTML etiketleri oluşturmanıza olanak tanıyan bir grup web platformu API'sidir. Web bileşeni standartlarına göre oluşturulan özel bileşenler ve widget'lar modern tarayıcılarda çalışır ve HTML ile çalışan herhangi bir JavaScript kitaplığı veya çerçevesiyle kullanılabilir.

Lit nedir?

Lit, herhangi bir çerçevede veya çerçeve olmadan çalışan hızlı ve hafif web bileşenleri oluşturmak için kullanılan basit bir kitaplıktır. Lit ile paylaşılabilir bileşenler, uygulamalar, tasarım sistemleri ve daha fazlasını oluşturabilirsiniz.

Lit, özellikleri ve özellikleri yönetme, oluşturma gibi yaygın Web Bileşenleri görevlerini basitleştirmek için API'ler sağlar.

Neler öğreneceksiniz?

  • Web bileşeni nedir?
  • Web bileşenleri kavramları
  • Web bileşeni oluşturma
  • lit-html ve LitElement nedir?
  • Lit'in web bileşeninin üzerinde yaptığı işlemler

Ne oluşturacaksınız?

  • Vanilla beğenme / beğenmeme Web Bileşeni
  • Beğenme / beğenmeme Lit tabanlı web bileşeni

Gerekenler

  • Güncellenmiş herhangi bir modern tarayıcı (Chrome, Safari, Firefox, Chromium Edge). Web bileşenleri tüm modern tarayıcılarda çalışır. Microsoft Internet Explorer 11 ve Chromium olmayan Microsoft Edge için polyfill'ler mevcuttur.
  • HTML, CSS, JavaScript ve Chrome Geliştirici Araçları hakkında bilgi sahibi olmak

2. Playground'u kurma ve keşfetme

Koda erişme

Bu kod laboratuvarı boyunca Lit Playground'a yönlendiren bağlantılar göreceksiniz. Örneğin:

Playground, tamamen tarayıcınızda çalışan bir kod korumalı alanıdır. TypeScript ve JavaScript dosyalarını derleyip çalıştırabilir ve içe aktarmaları otomatik olarak düğüm modüllerine çözümleyebilir. Örneğin:

// before
import './my-file.js';
import 'lit';

// after
import './my-file.js';
import 'https://unpkg.com/lit?module';

Bu kontrol noktalarını başlangıç noktası olarak kullanarak eğitimin tamamını Lit Playground'da yapabilirsiniz. VS Code kullanıyorsanız bu kontrol noktalarını kullanarak herhangi bir adımın başlangıç kodunu indirebilir ve çalışmanızı kontrol edebilirsiniz.

Exploring the lit playground UI

Dosya seçici sekme çubuğu 1. Bölüm, kod düzenleme bölümü 2. Bölüm, çıkış önizlemesi 3. Bölüm ve önizlemeyi yeniden yükleme düğmesi 4. Bölüm olarak etiketlenir.

Lit playground kullanıcı arayüzü ekran görüntüsünde, bu codelab'de kullanacağınız bölümler vurgulanmıştır.

  1. Dosya seçici. Artı düğmesini bulun...
  2. Dosya düzenleyici.
  3. Kod önizlemesi.
  4. Yeniden yükle düğmesi.
  5. İndir düğmesi.

VS Code kurulumu (Gelişmiş)

Bu VS Code kurulumunu kullanmanın avantajları şunlardır:

  • Şablon türü kontrolü
  • Şablon intellisense ve otomatik tamamlama

NPM, VS Code (lit-plugin eklentisiyle birlikte) zaten yüklüyse ve bu ortamı nasıl kullanacağınızı biliyorsanız aşağıdaki adımları uygulayarak bu projeleri indirip başlatabilirsiniz:

  • İndir düğmesine basın.
  • Tar dosyasının içeriğini bir dizine çıkarın.
  • Çıplak modül tanımlayıcılarını çözümleyebilen bir geliştirme sunucusu yükleyin (Lit ekibi @web/dev-server'ı önerir)
  • Geliştirme sunucusunu çalıştırın ve tarayıcınızı açın (@web/dev-server kullanıyorsanız npx web-dev-server --node-resolve --watch --open kullanabilirsiniz)
    • Örnekteki package.json karakterini kullanıyorsanız npm run serve karakterini kullanın.

3. Özel öğe tanımlama

Özel Öğeler

Web Components, 4 yerel web API'sinden oluşan bir koleksiyondur. Bunları şöyle sıralayabiliriz:

  • ES Modülleri
  • Özel Öğeler
  • Shadow DOM
  • HTML Şablonları

Sayfaya <script type="module"> ile yüklenen içe aktarma ve dışa aktarma işlemlerine sahip JavaScript modülleri oluşturmanıza olanak tanıyan ES modülleri spesifikasyonunu zaten kullanmışsınızdır.

Özel öğe tanımlama

Özel Öğeler spesifikasyonu, kullanıcıların JavaScript kullanarak kendi HTML öğelerini tanımlamasına olanak tanır. Adlar, yerel tarayıcı öğelerinden ayırt edilebilmeleri için tire (-) içermelidir. index.js dosyasını temizleyin ve özel bir öğe sınıfı tanımlayın:

index.js

class RatingElement extends HTMLElement {}

customElements.define('rating-element', RatingElement);

Özel öğe, HTMLElement öğesini genişleten bir sınıfın tireli bir etiket adıyla ilişkilendirilmesiyle tanımlanır. customElements.define çağrısı, tarayıcıya RatingElement sınıfını ‘rating-element' tagName'i ile ilişkilendirmesini söyler. Bu durumda, dokümanınızdaki <rating-element> adlı her öğe bu sınıfla ilişkilendirilir.

Doküman gövdesine bir <rating-element> yerleştirin ve neyin oluşturulduğunu görün.

index.html

<body>
 <rating-element></rating-element>
</body>

Çıkışa baktığınızda hiçbir şeyin oluşturulmadığını görürsünüz. Tarayıcıya <rating-element> öğesinin nasıl oluşturulacağını söylemediğiniz için bu beklenen bir durumdur. Chrome Dev Araçları'ndaki <rating-element> öğe seçiciyi belirleyip konsolda şu kodu çağırarak özel öğe tanımının başarılı olduğunu doğrulayabilirsiniz:

$0.constructor

Bu komutun çıkışı şu şekilde olmalıdır:

class RatingElement extends HTMLElement {}

Özel Öğelerin Yaşam Döngüsü

Özel öğeler, bir dizi yaşam döngüsü kancasıyla birlikte gelir. Bunları şöyle sıralayabiliriz:

  • constructor
  • connectedCallback
  • disconnectedCallback
  • attributeChangedCallback
  • adoptedCallback

constructor, öğe ilk oluşturulduğunda (ör. document.createElement(‘rating-element') veya new RatingElement() çağrılarak) çağrılır. Oluşturucu, öğenizi ayarlamak için iyi bir yerdir ancak öğe "başlatma" performansıyla ilgili nedenlerden dolayı oluşturucuda DOM manipülasyonları yapmak genellikle kötü bir uygulama olarak kabul edilir.

Özel öğe DOM'ye eklendiğinde connectedCallback çağrılır. Genellikle ilk DOM manipülasyonları burada gerçekleşir.

disconnectedCallback, özel öğe DOM'dan kaldırıldıktan sonra çağrılır.

Kullanıcı tarafından belirtilen özelliklerden herhangi biri değiştiğinde attributeChangedCallback(attrName, oldValue, newValue) çağrılır.

adoptedCallback, özel öğe başka bir documentFragment öğesinden adoptNode aracılığıyla ana dokümana aktarıldığında (ör. HTMLTemplateElement) çağrılır.

DOM'u oluştur

Şimdi özel öğeye dönün ve bununla bazı DOM'ları ilişkilendirin. Öğe DOM'a eklendiğinde içeriğini ayarlayın:

index.js

class RatingElement extends HTMLElement {
 constructor() {
   super();
   this.rating = 0;
 }
 connectedCallback() {
   this.innerHTML = `
     <style>
       rating-element {
         display: inline-flex;
         align-items: center;
       }
       rating-element button {
         background: transparent;
         border: none;
         cursor: pointer;
       }
     </style>
     <button class="thumb_down" >
       <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v2c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"/></svg>
     </button>
     <span class="rating">${this.rating}</span>
     <button class="thumb_up">
       <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2z"/></svg>
     </button>
   `;
 }
}

customElements.define('rating-element', RatingElement);

constructor içinde, öğede rating adlı bir örnek özelliği depolarsınız. connectedCallback içinde, mevcut puanı göstermek için <rating-element> öğesine DOM alt öğeleri ekleyerek beğenme ve beğenmeme düğmelerini kullanırsınız.

4. Shadow DOM

Neden gölge DOM?

Önceki adımda, eklediğiniz stil etiketindeki seçicilerin sayfadaki tüm derecelendirme öğelerini ve tüm düğmeleri seçtiğini fark edeceksiniz. Bu durum, stillerin öğeden sızmasına ve stil vermek istemediğiniz diğer düğümlerin seçilmesine neden olabilir. Ayrıca, bu özel öğenin dışındaki diğer stiller, özel öğenizin içindeki düğümleri istemeden şekillendirebilir. Örneğin, ana belgenin baş kısmına bir stil etiketi yerleştirmeyi deneyin:

index.html

<!DOCTYPE html>
<html>
 <head>
   <script src="./index.js" type="module"></script>
   <style>
     span {
       border: 1px solid red;
     }
   </style>
 </head>
 <body>
   <rating-element></rating-element>
 </body>
</html>

Çıkışınızda, derecelendirme aralığının etrafında kırmızı bir kenarlık kutusu olmalıdır. Bu önemsiz bir durumdur ancak DOM kapsüllemenin olmaması, daha karmaşık uygulamalarda daha büyük sorunlara yol açabilir. Bu noktada gölge DOM devreye girer.

Gölge kökü ekleme

Öğeye bir gölge kökü ekleyin ve DOM'u bu kök içinde oluşturun:

index.js

class RatingElement extends HTMLElement {
 constructor() {
   super();
   this.rating = 0;
 }
 connectedCallback() {
   const shadowRoot = this.attachShadow({mode: 'open'});

   shadowRoot.innerHTML = `
     <style>
       :host {
         display: inline-flex;
         align-items: center;
       }
       button {
         background: transparent;
         border: none;
         cursor: pointer;
       }
     </style>
     <button class="thumb_down" >
       <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v2c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"/></svg>
     </button>
     <span class="rating">${this.rating}</span>
     <button class="thumb_up">
       <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2z"/></svg>
     </button>
   `;
 }
}

customElements.define('rating-element', RatingElement);

Sayfayı yenilediğinizde, ana belgedeki stillerin artık gölge kökünün içindeki düğümleri seçemediğini fark edeceksiniz.

Bunu nasıl yaptınız? connectedCallback içinde this.attachShadow işlevini çağırarak bir öğeye gölge kökü ekleyin. open modu, gölge içeriğinin incelenebilir olduğu ve gölge kökünün this.shadowRoot üzerinden de erişilebilir olduğu anlamına gelir. Chrome inceleme aracında web bileşenine de göz atın:

Chrome denetleyicisindeki DOM ağacı. Alt öğesi olarak #shadow-root (open) olan bir <rating-element> ve bu shadowroot&#39;un içinde önceki DOM&#39;dan gelen bir DOM var.

Artık içerikleri barındıran genişletilebilir bir gölge kökü görmelisiniz. Bu gölge kökünün içindeki her şeye gölge DOM denir. Chrome Dev Araçları'nda derecelendirme öğesini seçip $0.children işlevini çağırdığınızda, işlevin herhangi bir alt öğe döndürmediğini görürsünüz. Bunun nedeni, gölge DOM'un doğrudan alt öğelerle aynı DOM ağacının bir parçası olarak değil, gölge ağacı olarak kabul edilmesidir.

Light DOM

Bir deneme: <rating-element> öğesinin doğrudan alt öğesi olarak bir düğüm ekleyin:

index.html

<rating-element>
 <div>
   This is the light DOM!
 </div>
</rating-element>

Sayfayı yenilediğinizde, bu özel öğenin Light DOM'undaki yeni DOM düğümünün sayfada görünmediğini görürsünüz. Bunun nedeni, gölge DOM'un <slot> öğeleri aracılığıyla ışık DOM düğümlerinin gölge DOM'a nasıl yansıtılacağını kontrol etmeye yönelik özelliklere sahip olmasıdır.

5. HTML Şablonları

Şablonları neden kullanmalısınız?

innerHTML ve temizlenmemiş şablon hazır dizelerini kullanmak, komut dosyası yerleştirme ile ilgili güvenlik sorunlarına neden olabilir. Geçmişte kullanılan yöntemler arasında DocumentFragment kullanmak da vardı ancak bu yöntemler, şablonlar tanımlandığında resimlerin yüklenmesi ve komut dosyalarının çalıştırılması gibi başka sorunlara da yol açıyor ve yeniden kullanılabilirlik açısından engeller oluşturuyordu. Bu noktada <template> öğesi devreye girer. Şablonlar, inert DOM, düğümleri klonlamak için yüksek performanslı bir yöntem ve yeniden kullanılabilir şablon oluşturma sağlar.

Şablonları kullanma

Ardından, bileşeni HTML şablonlarını kullanacak şekilde geçirin:

index.html

<body>
 <template id="rating-element-template">
   <style>
     :host {
       display: inline-flex;
       align-items: center;
     }
     button {
       background: transparent;
       border: none;
       cursor: pointer;
     }
   </style>
   <button class="thumb_down" >
     <svg xmlns="http://www.w3.org/2000/svg" height="24" viewbox="0 0 24 24" width="24"><path d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v2c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"/></svg>
   </button>
   <span class="rating"></span>
   <button class="thumb_up">
     <svg xmlns="http://www.w3.org/2000/svg" height="24" viewbox="0 0 24 24" width="24"><path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2z"/></svg>
   </button>
 </template>

 <rating-element>
   <div>
     This is the light DOM!
   </div>
 </rating-element>
</body>

Burada, DOM içeriğini ana dokümanın DOM'undaki bir şablon etiketine taşıdınız. Şimdi özel öğe tanımını yeniden düzenleyin:

index.js

class RatingElement extends HTMLElement {
 constructor() {
   super();
   this.rating = 0;
 }
 connectedCallback() {
   const shadowRoot = this.attachShadow({mode: 'open'});
   const templateContent = document.getElementById('rating-element-template').content;
   const clonedContent = templateContent.cloneNode(true);
   shadowRoot.appendChild(clonedContent);

   this.shadowRoot.querySelector('.rating').innerText = this.rating;
 }
}

customElements.define('rating-element', RatingElement);

Bu şablon öğesini kullanmak için şablonu sorgular, içeriğini alır ve templateContent.cloneNode ile bu düğümleri klonlarsınız. Burada true bağımsız değişkeni derin bir klonlama işlemi gerçekleştirir. Ardından, DOM'u verilerle başlatırsınız.

Tebrikler, artık bir web bileşeniniz var. Maalesef henüz hiçbir şey yapmıyor. Bu nedenle, sonraki adımda biraz işlevsellik ekleyin.

6. İşlev Ekleme

Mülk Bağlamaları

Şu anda, derecelendirme öğesindeki derecelendirmeyi ayarlamanın tek yolu öğeyi oluşturmak, nesnede rating özelliğini ayarlamak ve ardından sayfaya yerleştirmektir. Ancak yerel HTML öğeleri genellikle bu şekilde çalışmaz. Yerel HTML öğeleri, hem özellik hem de özellik değişiklikleriyle güncellenir.

Aşağıdaki satırları ekleyerek özel öğenin, rating özelliği değiştiğinde görünümü güncellemesini sağlayın:

index.js

constructor() {
  super();
  this._rating = 0;
}

set rating(value) {
  this._rating = value;
  if (!this.shadowRoot) {
    return;
  }

  const ratingEl = this.shadowRoot.querySelector('.rating');
  if (ratingEl) {
    ratingEl.innerText = this._rating;
  }
}

get rating() {
  return this._rating;
}

Puan özelliği için bir belirleyici ve alıcı ekleyip varsa puan öğesinin metnini güncellersiniz. Yani, öğede derecelendirme özelliğini ayarlarsanız görünüm güncellenir. Geliştirici Araçları konsolunuzda hızlı bir test yapın.

Özellik Bağlamaları

Şimdi, özellik değiştiğinde görünümü güncelleyin. Bu, <input value="newValue"> ayarlandığında görünümünü güncelleyen bir girişe benzer. Neyse ki Web Bileşeni yaşam döngüsü attributeChangedCallback içerir. Aşağıdaki satırları ekleyerek derecelendirmeyi güncelleyin:

index.js

static get observedAttributes() {
 return ['rating'];
}

attributeChangedCallback(attributeName, oldValue, newValue) {
 if (attributeName === 'rating') {
   const newRating = Number(newValue);
   this.rating = newRating;
 }
}

attributeChangedCallback tetiklenmesi için RatingElement.observedAttributes which defines the attributes to be observed for changes için statik bir alıcı ayarlamanız gerekir. Ardından, derecelendirmeyi DOM'da bildirimsel olarak ayarlarsınız. Deneyin:

index.html

<rating-element rating="5"></rating-element>

Derecelendirme artık bildirimli olarak güncellenmelidir.

Düğme İşlevselliği

Şimdi tek eksik düğme işlevselliği. Bu bileşenin davranışı, kullanıcının tek bir olumlu veya olumsuz oy değerlendirmesi vermesine ve kullanıcıya görsel geri bildirimde bulunmasına olanak tanımalıdır. Bunu bazı etkinlik dinleyicileri ve yansıtıcı bir özellik ile uygulayabilirsiniz. Ancak öncelikle aşağıdaki satırları ekleyerek stilleri güncelleyin ve görsel geri bildirim sağlayın:

index.html

<style>
...

 :host([vote=up]) .thumb_up {
   fill: green;
 }
  :host([vote=down]) .thumb_down {
   fill: red;
 }
</style>

Gölge DOM'da :host seçici, gölge kökünün bağlı olduğu düğümü veya özel öğeyi ifade eder. Bu durumda, vote özelliği "up" ise beğeni düğmesi yeşile döner ancak vote özelliği "down", then it will turn the thumb-down button red ise düğme yeşile dönmez. Şimdi, rating özelliğini uyguladığınız şekilde vote için yansıtıcı bir özellik / nitelik oluşturarak bu mantığı uygulayın. Özellik ayarlayıcı ve alıcı ile başlayın:

index.js

constructor() {
  super();
  this._rating = 0;
  this._vote = null;
}

set vote(newValue) {
  const oldValue = this._vote;
  if (newValue === oldValue) {
    return;
  }
  if (newValue === 'up') {
    if (oldValue === 'down') {
      this.rating += 2;
    } else {
      this.rating += 1;
    }
  } else if (newValue === 'down') {
    if (oldValue === 'up') {
      this.rating -= 2;
    } else {
      this.rating -= 1;
    }
  }
  this._vote = newValue;
  this.setAttribute('vote', newValue);
}

get vote() {
  return this._vote;
}

_vote örnek özelliğini constructor içinde null ile başlatır ve ayarlayıcıda yeni değerin farklı olup olmadığını kontrol edersiniz. Bu durumda, derecelendirmeyi buna göre ayarlarsınız ve en önemlisi, vote özelliğini this.setAttribute ile birlikte ana makineye geri yansıtırsınız.

Ardından, özellik bağlamayı ayarlayın:

index.js

static get observedAttributes() {
  return ['rating', 'vote'];
}

attributeChangedCallback(attributeName, oldValue, newValue) {
  if (attributeName === 'rating') {
    const newRating = Number(newValue);

    this.rating = newRating;
  } else if (attributeName === 'vote') {
    this.vote = newValue;
  }
}

Bu işlem, rating özelliği bağlamada uyguladığınız işlemin aynısıdır. vote özelliğini observedAttributes özelliğine ekler ve vote özelliğini attributeChangedCallback içinde ayarlarsınız. Son olarak, düğmelere işlevsellik kazandırmak için bazı tıklama etkinliği dinleyicileri ekleyin.

index.js

constructor() {
 super();
 this._rating = 0;
 this._vote = null;
 this._boundOnUpClick = this._onUpClick.bind(this);
 this._boundOnDownClick = this._onDownClick.bind(this);
}

connectedCallback() {
  ...
  this.shadowRoot.querySelector('.thumb_up')
    .addEventListener('click', this._boundOnUpClick);
  this.shadowRoot.querySelector('.thumb_down')
    .addEventListener('click', this._boundOnDownClick);
}

disconnectedCallback() {
  this.shadowRoot.querySelector('.thumb_up')
    .removeEventListener('click', this._boundOnUpClick);
  this.shadowRoot.querySelector('.thumb_down')
    .removeEventListener('click', this._boundOnDownClick);
}

_onUpClick() {
  this.vote = 'up';
}

_onDownClick() {
  this.vote = 'down';
}

constructor içinde, öğeye bazı tıklama dinleyicileri bağlar ve referansları saklarsınız. connectedCallback içinde düğmelerdeki tıklama etkinliklerini dinlersiniz. disconnectedCallback içinde bu dinleyicileri temizler ve dinleyicilerin kendilerini tıklayarak vote değerini uygun şekilde ayarlarsınız.

Tebrikler, artık tam özellikli bir web bileşeniniz var. Bazı düğmeleri tıklamayı deneyin. Şu anda JS dosyam 96 satıra, HTML dosyam ise 43 satıra ulaşıyor. Kod, bu kadar basit bir bileşen için oldukça ayrıntılı ve zorunlu. Google'ın Lit projesi tam da bu noktada devreye girer.

7. Lit-html

Kod Kontrol Noktası

Neden lit-html?

Öncelikle <template> etiketi kullanışlı ve yüksek performanslıdır ancak bileşenin mantığıyla birlikte paketlenmediği için şablonun mantığın geri kalanıyla birlikte dağıtılması zordur. Ayrıca, şablon öğelerinin kullanılma şekli zorunlu kodlamaya yol açar. Bu da çoğu durumda, bildirimsel kodlama kalıplarına kıyasla daha az okunabilir kodlara neden olur.

Bu noktada lit-html devreye girer. Lit HTML, Lit'in oluşturma sistemidir. Bu sistem, JavaScript'te HTML şablonları yazmanıza, ardından DOM'u oluşturmak ve güncellemek için bu şablonları verilerle birlikte etkili bir şekilde oluşturup yeniden oluşturmanıza olanak tanır. Bu kitaplık, popüler JSX ve VDOM kitaplıklarına benzer ancak tarayıcıda yerel olarak ve birçok durumda çok daha verimli çalışır.

Lit HTML'yi kullanma

Ardından, Tagged Template Literals kullanan Lit şablonunu kullanmak için yerel Web Component rating-element öğesini taşıyın. Bu öğe, şablon dizelerini özel söz dizimiyle bağımsız değişken olarak alan işlevlerdir. Lit, hızlı oluşturma sağlamak ve güvenlik için bazı temizleme özellikleri sunmak üzere arka planda şablon öğelerini kullanır. index.html içindeki <template> öğesini, web bileşenine render() yöntemi ekleyerek Lit şablonuna taşıyarak başlayın:

index.js

// Dont forget to import from Lit!
import {render, html} from 'lit';

class RatingElement extends HTMLElement {
  ...
  render() {
    if (!this.shadowRoot) {
      return;
    }

    const template = html`
      <style>
        :host {
          display: inline-flex;
          align-items: center;
        }
        button {
          background: transparent;
          border: none;
          cursor: pointer;
        }

       :host([vote=up]) .thumb_up {
         fill: green;
       }

       :host([vote=down]) .thumb_down {
         fill: red;
       }
      </style>
      <button class="thumb_down">
        <svg xmlns="http://www.w3.org/2000/svg" height="24" viewbox="0 0 24 24" width="24"><path d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v2c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"/></svg>
      </button>
      <span class="rating">${this.rating}</span>
      <button class="thumb_up">
        <svg xmlns="http://www.w3.org/2000/svg" height="24" viewbox="0 0 24 24" width="24"><path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2z"/></svg>
      </button>`;

    render(template, this.shadowRoot);
  }
}

Şablonunuzu index.html bölümünden de silebilirsiniz. Bu oluşturma yönteminde template adlı bir değişken tanımlar ve html etiketli şablon değişmez işlevini çağırırsınız. Ayrıca, ${...} öğesinin şablon değişmez değer interpolasyon söz dizimini kullanarak span.rating öğesinde basit bir veri bağlama işlemi gerçekleştirdiğinizi de fark edeceksiniz. Bu durumda, söz konusu düğümü zorunlu olarak güncellemeniz gerekmez. Ayrıca, şablonu gölge köküne eşzamanlı olarak işleyen lit render yöntemini çağırırsınız.

Bildirim Temelli Söz Dizimine Geçiş

<template> öğesini kaldırdığınıza göre, kodu yeniden düzenleyerek yeni tanımlanan render yöntemini çağırın. Dinleyici kodunu temizlemek için Lit'in etkinlik işleyici bağlamasını kullanarak başlayabilirsiniz:

index.js

<button
    class="thumb_down"
    @click=${() => {this.vote = 'down'}}>
...
<button
    class="thumb_up"
    @click=${() => {this.vote = 'up'}}>

Lit şablonları, @EVENT_NAME bağlama söz dizimiyle bir düğüme etkinlik dinleyicisi ekleyebilir. Bu durumda, bu düğmeler her tıklandığında vote özelliğini güncellersiniz.

Ardından, constructor ve connectedCallback ile disconnectedCallback içindeki etkinlik işleyici başlatma kodunu temizleyin:

index.js

constructor() {
  super();
  this._rating = 0;
  this._vote = null;
}

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

// remove disonnectedCallback and _onUpClick and _onDownClick

Tıklama işleyici mantığını üç geri çağırmanın tümünden kaldırabildiniz ve hatta disconnectedCallback öğesini tamamen kaldırabildiniz. Ayrıca, connectedCallback üzerindeki tüm DOM başlatma kodunu kaldırarak çok daha zarif görünmesini sağladınız. Bu, _onUpClick ve _onDownClick dinleyici yöntemlerinden de kurtulabileceğiniz anlamına gelir.

Son olarak, mülkler veya özellikler değiştiğinde DOM'un güncellenebilmesi için mülk ayarlayıcıları render yöntemini kullanacak şekilde güncelleyin:

index.js

set rating(value) {
  this._rating = value;
  this.render();
}

...

set vote(newValue) {
  const oldValue = this._vote;
  if (newValue === oldValue) {
    return;
  }

  if (newValue === 'up') {
    if (oldValue === 'down') {
      this.rating += 2;
    } else {
      this.rating += 1;
    }
  } else if (newValue === 'down') {
    if (oldValue === 'up') {
      this.rating -= 2;
    } else {
      this.rating -= 1;
    }
  }

  this._vote = newValue;
  this.setAttribute('vote', newValue);
  // add render method
  this.render();
}

Burada, DOM güncelleme mantığını rating belirleyiciden kaldırdınız ve vote belirleyiciden render belirleyicisine bir çağrı eklediniz. Artık bağlamaların ve etkinlik işleyicilerinin nereye uygulandığını görebildiğiniz için şablon çok daha okunabilir.

Sayfayı yenilediğinizde, beğenme düğmesi çalışır duruma gelir. Bu düğmeye basıldığında aşağıdaki gibi görünür.

6 değeriyle beğenme ve beğenmeme derecelendirme kaydırıcısı ve yeşil renkte beğenme simgesi

8. LitElement

Neden LitElement?

Kodla ilgili bazı sorunlar devam ediyor. İlk olarak, vote özelliğini veya özelliğini değiştirirseniz rating özelliği değişebilir. Bu da render işlevinin iki kez çağrılmasına neden olur. Render işlevinin tekrar tekrar çağrılması esasen işlemsiz ve verimli olmasına rağmen, JavaScript sanal makinesi bu işlevi iki kez eşzamanlı olarak çağırmak için zaman harcamaya devam ediyor. İkincisi, çok fazla standart kod gerektirdiğinden yeni özellikler ve nitelikler eklemek sıkıcıdır. Bu noktada LitElement devreye girer.

LitElement, çerçeveler ve ortamlar arasında kullanılabilen hızlı ve hafif web bileşenleri oluşturmak için Lit'in temel sınıfıdır. Ardından, uygulamayı değiştirerek LitElement'nın rating-element'da bizim için neler yapabileceğine göz atın.

LitElement'i kullanma

LitElement temel sınıfını lit paketinden içe aktarıp alt sınıf oluşturarak başlayın:

index.js

import {LitElement, html, css} from 'lit';

class RatingElement extends LitElement {
// remove connectedCallback()
...

rating-element için yeni temel sınıf olan LitElement sınıfını içe aktarırsınız. Ardından html içe aktarma işlemini yaparsınız ve son olarak css ile CSS matematik, şablon oluşturma ve diğer özellikler için CSS etiketli şablon değişmezlerini tanımlayabiliriz.

Ardından, stilleri oluşturma yönteminden Lit'in statik stil sayfasına taşıyın:

index.js

class RatingElement extends LitElement {
  static get styles() {
    return css`
      :host {
        display: inline-flex;
        align-items: center;
      }
      button {
        background: transparent;
        border: none;
        cursor: pointer;
      }

      :host([vote=up]) .thumb_up {
        fill: green;
      }

      :host([vote=down]) .thumb_down {
        fill: red;
      }
    `;
  }
 ...

Lit'teki çoğu stil burada yer alır. Lit, bu stilleri alır ve daha hızlı oluşturma süreleri sağlamak için Constructable Stylesheets gibi tarayıcı özelliklerini kullanır. Gerekirse eski tarayıcılarda Web Components polyfill'i de kullanır.

Yaşam döngüsü

Lit, yerel Web Bileşeni geri çağırmalarının üzerinde bir dizi oluşturma yaşam döngüsü geri çağırma yöntemi sunar. Bu geri çağırmalar, bildirilen Lit özellikleri değiştirildiğinde tetiklenir.

Bu özelliği kullanmak için hangi özelliklerin oluşturma yaşam döngüsünü tetikleyeceğini statik olarak bildirmeniz gerekir.

index.js

static get properties() {
  return {
    rating: {
      type: Number,
    },
    vote: {
      type: String,
      reflect: true,
    }
  };
}

// remove observedAttributes() and attributeChangedCallback()
// remove set rating() get rating()

Burada, rating ve vote özelliklerinin LitElement oluşturma yaşam döngüsünü tetikleyeceğini ve dize özelliklerini özelliklere dönüştürmek için kullanılacak türleri tanımlarsınız.

<user-profile .name=${this.user.name} .age=${this.user.age}>
  ${this.user.family.map(member => html`
        <family-member
             .name=${member.name}
             .relation=${member.relation}>
        </family-member>`)}
</user-profile>

Ayrıca, reflect özelliğindeki vote işareti, vote belirleyicide manuel olarak tetiklediğiniz ana makine öğesinin vote özelliğini otomatik olarak günceller.

Artık statik özellikler bloğunuz olduğuna göre, tüm özellik ve mülk oluşturma güncelleme mantığını kaldırabilirsiniz. Bu, aşağıdaki yöntemleri kaldırabileceğiniz anlamına gelir:

  • connectedCallback
  • observedAttributes
  • attributeChangedCallback
  • rating (setter ve getter)
  • vote (belirleyiciler ve alıcılar ancak belirleyicideki değişiklik mantığını korur)

Aşağıdakileri koruyabilir ve yeni bir willUpdate yaşam döngüsü yöntemi ekleyebilirsiniz:constructor

index.js

constructor() {
  super();
  this.rating = 0;
  this.vote = null;
}

willUpdate(changedProps) {
  if (changedProps.has('vote')) {
    const newValue = this.vote;
    const oldValue = changedProps.get('vote');

    if (newValue === 'up') {
      if (oldValue === 'down') {
        this.rating += 2;
      } else {
        this.rating += 1;
      }
    } else if (newValue === 'down') {
      if (oldValue === 'up') {
        this.rating -= 2;
      } else {
        this.rating -= 1;
      }
    }
  }
}

// remove set vote() and get vote()

Burada, rating ve vote öğelerini başlatmanız ve vote belirleyici mantığını willUpdate yaşam döngüsü yöntemine taşımanız yeterlidir. LitElement, özellik değişikliklerini toplu olarak işleyip oluşturmayı eşzamansız hale getirdiğinden, güncellenen herhangi bir özellik her değiştirildiğinde willUpdate yöntemi render'den önce çağrılır. willUpdate içindeki tepkisel özelliklerde (ör. this.rating) yapılan değişiklikler gereksiz render yaşam döngüsü çağrılarını tetiklemez.

Son olarak, render, Lit şablonu döndürmemizi gerektiren bir LitElement yaşam döngüsü yöntemidir:

index.js

render() {
  return html`
    <button
        class="thumb_down"
        @click=${() => {this.vote = 'down'}}>
      <svg xmlns="http://www.w3.org/2000/svg" height="24" viewbox="0 0 24 24" width="24"><path d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v2c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"/></svg>
    </button>
    <span class="rating">${this.rating}</span>
    <button
        class="thumb_up"
        @click=${() => {this.vote = 'up'}}>
      <svg xmlns="http://www.w3.org/2000/svg" height="24" viewbox="0 0 24 24" width="24"><path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2z"/></svg>
    </button>`;
}

Artık gölge kökünü kontrol etmeniz ve daha önce 'lit' paketinden içe aktarılan render fonksiyonunu çağırmanız gerekmez.

Öğeniz artık önizlemede oluşturulmalıdır. Öğeyi tıklayın.

9. Tebrikler

Tebrikler! Sıfırdan bir web bileşeni oluşturup LitElement'e dönüştürmeyi başardınız.

Lit, çok küçük (< 5 kb küçültülmüş + gzip'lenmiş), çok hızlı ve kodlaması gerçekten eğlenceli bir kütüphanedir. Diğer çerçeveler tarafından kullanılacak bileşenler oluşturabilir veya bu çerçeveyle tam teşekküllü uygulamalar geliştirebilirsiniz.

Artık web bileşeninin ne olduğunu, nasıl oluşturulacağını ve Lit'in bunları oluşturmayı nasıl kolaylaştırdığını biliyorsunuz.

Kod Kontrol Noktası

Son kodunuzu bizimkiyle karşılaştırmak ister misiniz? Karşılaştırmayı buradan yapabilirsiniz.

Yapabilecekleriniz

Diğer codelab'lere göz atın.

Daha fazla bilgi

Topluluk