Web Bileşeninden Edebiyat Öğesine

1. Giriş

Son Güncelleme: 10.08.2021

Web Bileşenleri

Web Bileşenleri, web sayfaları ve web uygulamalarında kullanılacak yeni özel, yeniden kullanılabilir, kapsüllenmiş HTML etiketleri oluşturmanızı sağlayan web platformu API'leri kümesidir. Web Bileşeni standartlarını temel alan ö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.

Edebiyat nedir?

Lit, herhangi bir çerçevede çalışan veya hiçbir çerçeve olmadan çalışan hızlı ve hafif web bileşenleri oluşturmaya yönelik basit bir kitaplıktır. Lit'i kullanarak paylaşılabilir bileşenler, uygulamalar, tasarım sistemleri ve daha fazlasını oluşturabilirsiniz.

Lit; mülkleri, özellikleri ve oluşturma gibi yaygın Web Bileşenleri görevlerini basitleştirmek için API'ler sunar.

Neler öğreneceksiniz?

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

Oluşturacaklarınız

  • vanilya, 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 ve çoklu dolgular Microsoft Internet Explorer 11 ve Chrome olmayan Microsoft Edge için kullanılabilir.
  • HTML, CSS, JavaScript ve Chrome Geliştirici Araçları hakkında bilgi sahibi olmak.

2. Kurulum ve Playground'u keşfediyor

Koda erişme

Codelab boyunca Edebiyat oyun alanına şu şekilde bağlantılar verilecektir:

Oyun alanı, tamamen tarayıcınızda çalışan bir kod korumalı alanıdır. TypeScript ve JavaScript dosyalarını derleyip çalıştırabilir, ayrıca düğüm modüllerine yapılan içe aktarmaları otomatik olarak çözümleyebilir. ör.

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

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

Bu kontrol noktalarını başlangıç noktaları olarak kullanarak eğitici içeriğin tamamını Edebiyat oyun alanında uygulayabilirsiniz. VS Code kullanıyorsanız bu kontrol noktalarını herhangi bir adımın başlangıç kodunu indirmek için kullanabilir ve ayrıca bunları çalışmanızı kontrol etmek için de kullanabilirsiniz.

Işıklı oyun alanının kullanıcı arayüzünü keşfetmek

Dosya seçici sekme çubuğu Bölüm 1, Kod düzenleme bölümü Bölüm 2, çıkış önizlemesi Bölüm 3 ve önizleme yeniden yükle düğmesi Bölüm 4 olarak etiketlenmiştir

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

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

VS Kod kurulumu (Gelişmiş)

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

  • Şablon türü kontrolü
  • Şablon zekası ve otomatik tamamlama

NPM, VS Code (lit-plugin eklentisiyle) yüklüyse ve bu ortamı nasıl kullanacağınızı biliyorsanız, aşağıdakileri yaparak bu projeleri indirip başlatmanız yeterlidir:

  • İndir düğmesine basın
  • tar dosyasının içeriğini bir dizine çıkarın
  • Yalın modül tanımlayıcıları çözümleyebilen bir geliştirici sunucusu yükleyin (Lit ekibi @web/dev-server'ı önerir)
  • Geliştirici 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)
    • package.json örneğini kullanıyorsanız npm run serve kullanın.

3. Özel Öğe Tanımlayın

Özel Öğeler

Web Bileşenleri, 4 yerel web API'sinden oluşan bir koleksiyondur. Bunlar:

  • ES Modülleri
  • Özel Öğeler
  • Gölge DOM
  • HTML Şablonları

İçe ve dışa aktarma işlemlerine sahip, <script type="module"> ile sayfaya yüklenen JavaScript modülleri oluşturmanıza olanak tanıyan ES modülleri spesifikasyonunu daha önce kullandınız.

Özel Öğe Tanımlama

Custom Elements spesifikasyonu, kullanıcıların JavaScript kullanarak kendi HTML öğelerini tanımlamalarına olanak tanır. Adlar, yerel tarayıcı öğelerinden ayırt edilebilmeleri için kısa çizgi (-) içermelidir. index.js dosyasını temizleyin ve bir özel öğ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 kısa çizgili bir etiket adıyla ilişkilendirilmesiyle tanımlanır. customElements.define çağrısı, tarayıcıya RatingElement sınıfını tagName ‘rating-element' ile ilişkilendirmesini bildirir. Bu durum, dokümanınızda <rating-element> adlı her öğenin bu sınıfla ilişkilendirileceği anlamına gelir.

Doküman gövdesine <rating-element> yerleştirin ve nelerin 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ı bildirmediğiniz için bu, beklenen bir durumdur. Chrome Geliştirici Araçları'nda <rating-element> öğesini seçerek özel öğe tanımının başarılı olduğunu onaylayabilirsiniz öğe seçicide çalışır ve konsolda şunları çağırır:

$0.constructor

Bu kod aşağıdaki sonucu verir:

class RatingElement extends HTMLElement {}

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

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

  • constructor
  • connectedCallback
  • disconnectedCallback
  • attributeChangedCallback
  • adoptedCallback

constructor, öğe ilk oluşturulduğunda (örneğin, document.createElement(‘rating-element') veya new RatingElement()) çağrılır. Oluşturucu, öğenizi ayarlamak için iyi bir yerdir ancak "boot-up" öğesi için oluşturucuda DOM değiştirmeleri yapmak genellikle kötü bir uygulama olarak kabul edilir performansa neden olabilir.

Özel öğe DOM'ye eklendiğinde connectedCallback çağrılır. İlk DOM manipülasyonları genellikle bu aşamada gerçekleşir.

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

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

Özel öğe, adoptNode aracılığıyla ana dokümana (ör. HTMLTemplateElement içinde) başka bir documentFragment öğesi uygulandığında adoptedCallback çağrılır.

DOM oluşturma

Şimdi özel öğeye geri dönün ve bununla bir DOM ilişkilendirin. DOM'ye eklendiğinde öğenin 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 öğesinde, öğe üzerinde rating adlı bir örnek özelliği depoluyorsunuz. connectedCallback içinde, beğenme ve beğenmeme düğmeleriyle birlikte geçerli puanı görüntülemek için <rating-element> öğesine DOM alt öğeleri eklersiniz.

4. Gölge DOM

Neden Gölge DOM?

Önceki adımda, eklediğiniz stil etiketindeki seçicilerin sayfadaki herhangi bir derecelendirme öğesini ve herhangi bir düğmeyi seçtiğini göreceksiniz. Bu, stillerin öğenin dışına sızmasına ve stilini belirlemeyi düşünmediğiniz başka düğümler seçmesine neden olabilir. Ayrıca, bu özel öğenin dışındaki diğer stiller yanlışlıkla özel öğenizin içindeki düğümlerin stilini belirleyebilir. Örneğin, ana dokümanın başına 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ızın, derecelendirme aralığının çevresinde kırmızı bir kenarlık kutusu olması gerekir. Bu sıradan bir durum olsa da DOM kapsüllemenin eksik olması, daha karmaşık uygulamalarda daha büyük sorunlara yol açabilir. İşte Gölge DOM burada devreye girer.

Gölge Kökü Ekleme

Öğeye bir Gölge Kökü ekleyin ve DOM'yi bu kökün 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 dokümandaki stillerin artık Gölge Kökü içindeki düğümleri seçemediğini fark edeceksiniz.

Bunu nasıl yaptınız? connectedCallback öğesinde, bir öğeye gölge kökü ekleyen this.attachShadow adını verdiniz. open modu, gölge içeriğinin incelenebileceği anlamına gelir ve gölge kökünün this.shadowRoot üzerinden de erişilebilir olmasını sağlar. Chrome denetleyicisindeki Web Bileşeni'ne de bakın:

Chrome denetleyicisindeki dom ağacı. Bir <rating-element> alt öğesi a#shadow-root (open) ile ve bu shadowroot içindeki DOM&#39;yle.

Şimdi, içeriği barındıran genişletilebilir bir gölge kökü görmeniz gerekir. Gölge kökünün içindeki her şeye Gölge DOM denir. Chrome Geliştirici Araçları'nda derecelendirme öğesini seçer ve $0.children yöntemini çağırırsanız alt öğe döndürmediğini fark edersiniz. Bunun nedeni, Gölge DOM'nin doğrudan alt yayıncılarla aynı DOM ağacının bir parçası olarak değil, Gölge Ağacı'nın bir parçası olarak kabul edilmesidir.

Hafif DOM

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'sindeki bu yeni DOM düğümünün sayfada görünmediğini görürsünüz. Bunun nedeni Gölge DOM'un, Işık DOM düğümlerinin <slot> öğeleri aracılığıyla gölge alanına nasıl yansıtılacağını kontrol eden özelliklere sahip olmasıdır.

5. HTML Şablonları

Neden Şablonlar?

innerHTML ve şablon sabit değer dizelerinin temizleme yapılmadan kullanılması, komut dosyası yerleştirmeyle ilgili güvenlik sorunlarına neden olabilir. Geçmişteki yöntemler DocumentFragment'ların kullanılmasını içeriyordu. Ancak bu yöntemler arasında resimlerin yüklenmesi, şablonların tanımlanması sırasında çalıştırılması ve yeniden kullanılabilirliğin önünde engellerin oluşması gibi başka sorunlar da yer alıyordu. <template> öğesi burada devreye girer. Şablonlar, düğümleri klonlamak için yüksek performanslı bir yöntem olan inert DOM ve yeniden kullanılabilir şablon oluşturur.

Şablonları kullanma

Daha sonra, bileşeni HTML Şablonlarını kullanacak şekilde değiştirin:

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'sindeki 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 sorgulayıp içeriğini almanız ve bu düğümleri templateContent.cloneNode ile klonlamanız gerekir. Burada true bağımsız değişkeni derin bir klonlama gerçekleştirir. Daha sonra dom'u verilerle ilk kullanıma hazırlarsınız.

Tebrikler, artık bir Web Bileşeniniz var! Maalesef henüz hiçbir şey yapmıyor. Bu yüzden, biraz daha işlevsellik ekleyin.

6. İşlev Ekleme

Mülk Bağlantıları

Şu anda, derecelendirme öğesinde derecelendirmeyi ayarlamanın tek yolu öğeyi oluşturmak, nesnede rating özelliğini ayarlamak ve ardından sayfaya yerleştirmektir. Maalesef yerel HTML öğelerinin çalışma biçimi bu değildir. Yerel HTML öğeleri, hem özellik hem de özellik değişiklikleriyle güncellenme eğilimindedir.

Aşağıdaki satırları ekleyerek, rating özelliği değiştiğinde özel öğenin 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;
}

Derecelendirme özelliği için bir belirleyici ve alıcı eklersiniz, ardından varsa derecelendirme öğesinin metnini güncellersiniz. Bu, öğede derecelendirme özelliğini ayarlarsanız görünümün güncelleneceği anlamına gelir; Geliştirici Araçları konsolunuzda kısa bir test yapın.

Özellik Bağlamaları

Şimdi, özellik değiştiğinde görünümü güncelleyin; bu, <input value="newValue"> olarak ayarlandığında görünümü 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 puanı güncelleyin:

index.js

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

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

attributeChangedCallback öğesinin tetiklenmesi amacıyla RatingElement.observedAttributes which defines the attributes to be observed for changes için statik alıcı ayarlamanız gerekir. Daha sonra, derecelendirmeyi DOM'de bildirimli şekilde ayarlarsınız. Bir deneyin:

index.html

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

Puan artık beyan verecek şekilde güncellenecek.

Düğme İşlevselliği

Eksik olan tek şey düğme işlevi. Bu bileşenin davranışı, kullanıcının tek bir olumlu veya olumsuz oy puanı vermesine ve kullanıcıya görsel geri bildirim sağlamasına izin vermelidir. Bunu bazı etkinlik işleyiciler ve yansıtma özelliği ile uygulayabilirsiniz, ancak önce aşağıdaki satırları ekleyerek stilleri görsel geri bildirim verecek şekilde güncelleyin:

index.html

<style>
...

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

Gölge DOM'da :host seçicisi, 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ğenme düğmesi yeşile döner, vote ise "down", then it will turn the thumb-down button red değerine ayarlanır. Şimdi, vote için rating uyguladığınıza benzer bir yansıtma özelliği / özellik oluşturarak bunun mantığını uygulayın. Özellik belirleyici ve alıcıyla 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ırsınız ve belirleyicide yeni değerin farklı olup olmadığını kontrol edersiniz. Bu durumda, puanı uygun şekilde ayarlar ve daha da önemlisi vote özelliğini, this.setAttribute ile 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, rating özellik bağlamasıyla uyguladığınız sürecin aynısıdır; observedAttributes öğesine vote ekler ve vote özelliğini attributeChangedCallback içinde ayarlarsınız. Şimdi son olarak, düğmelere işlev katmak için birkaç tıklama etkinliği işleyicisi 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 bazı tıklama işleyicileri öğeye bağlar ve referansları başka bir yerde tutarsınız. connectedCallback içinde düğmelerdeki tıklama etkinliklerini dinlersiniz. disconnectedCallback içinde bu işleyicileri temizlersiniz ve tıklama işleyiciler üzerinde de vote öğesini uygun bir şekilde ayarlarsınız.

Tebrikler, artık tam özellikli bir Web Bileşeniniz var; bazı düğmeleri tıklamayı deneyin! Şimdi sorun, JS dosyamın 96 satıra, HTML dosyamın ise 43 satıra ulaşması ve kodun çok ayrıntılı ve böyle basit bir bileşen için şart olması. Google'ın Edebiyat projesi de bu noktada devreye giriyor.

7. Edebi HTML

Kod Kontrol Noktası

Neden lit-html?

Her şeyden önce, <template> etiketi kullanışlı ve etkilidir, ancak bileşenin mantığına uygun bir şekilde paketlenmemiştir. Bu nedenle, şablonun mantığın geri kalanıyla dağıtılmasını zorlaştırır. Ayrıca, şablon öğelerinin kullanım biçimi, doğası gereği zorunlu koda da katkıda bulunur. Bu durum, çoğu durumda, bildirim temelli kodlama kalıplarına kıyasla kodların daha az okunmasına yol açar.

İşte burada devreye "lit-html" girilir. Lit html, JavaScript'te HTML şablonları yazmanıza, ardından DOM'yi oluşturmak ve güncellemek için bu şablonları verilerle birlikte verimli bir şekilde oluşturup yeniden oluşturmanıza olanak tanıyan, Lit'in oluşturma sistemidir. Popüler JSX ve VDOM kitaplıklarına benzer, ancak tarayıcıda yerel olarak ve çoğu durumda çok daha verimli bir şekilde çalışır.

Edebi HTML kullanma

Ardından, özel bir söz dizimiyle bağımsız değişken olarak şablon dizeleri alan işlevler olan Etiketli Şablon Değişmez Değerlerini kullanan Lit şablonunu kullanmak için yerel Web Bileşeni rating-element'ni taşıyın. Ardından Lit, hızlı oluşturma ve güvenlik amacıyla bazı temizlik özellikleri sağlamak için arka planda şablon öğelerini kullanıyor. Web bileşenine render() yöntemi ekleyerek index.html içindeki <template> öğesini bir 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 üzerinden de silebilirsiniz. Bu oluşturma yönteminde, template adında bir değişken tanımlar ve html etiketli şablon değişmez değer işlevini çağırırsınız. Ayrıca, ${...} şablonun düz interpolasyon söz dizimini kullanarak span.rating öğesi içinde basit bir veri bağlama gerçekleştirdiğinizi fark edeceksiniz. Bu, artık söz konusu düğümü zorunlu olarak güncellemeniz gerekmeyeceği anlamına gelir. Ayrıca, şablonu eşzamanlı olarak gölge kökünde oluşturan ışıklandırılmış render yöntemini çağırırsınız.

Bildirim Temelli Söz Dizmine Geçiş

<template> öğesini kaldırdığınıza göre, artık yeni tanımlanan render yöntemini çağırmak için kodu yeniden düzenleyin. Dinleyici kodunu temizlemek için Lit'in etkinlik işleyici bağlamasından yararlanarak 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 dizimine sahip bir düğüme etkinlik işleyici ekleyebilir. Bu durumda, düğmeler her tıklandığında vote özelliğini güncellersiniz.

Daha sonra, constructor, connectedCallback ve disconnectedCallback alanlarındaki 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 tamamından kaldırabildiniz, hatta disconnectedCallback öğesini tamamen kaldırdınız! Ayrıca, DOM başlatma kodunun tamamını connectedCallback içinden kaldırarak çok daha zarif bir görünüme kavuştunuz. Bu sayede _onUpClick ve _onDownClick işleyici yöntemlerinden de kurtulabilirsiniz.

Son olarak, özellikler veya özellikler değiştiğinde dom'un güncellenebilmesi için özellik belirleyicileri 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, rating seter'ından dom güncelleme mantığını kaldırdınız ve vote setter'dan render çağrısına eklediniz. Bağlamaların ve etkinlik işleyicilerin nerede uygulandığını artık görebildiğiniz için şablon artık çok daha okunaklı.

Sayfayı yenilediğinizde, olumlu oya basıldığında bunun gibi çalışan bir derecelendirme düğmeniz olacaktır!

Beğenme ve beğenmeme derecelendirme kaydırma çubuğu 6 değerinde ve baş parmak rengi yeşil

8. LitElement

Neden LitElement?

Kodla ilgili bazı sorunlar devam ediyor. Öncelikle, vote özelliğini veya özelliğini değiştirirseniz rating özelliği de değişebilir. Bu da render özelliğinin iki kez çağrılmasına neden olur. Tekrarlanan oluşturma çağrılarının aslında işlemsiz ve verimli olmasına rağmen, JavaScript sanal makinesi hâlâ bu işlevi iki kez eşzamanlı olarak çağırmak için zaman harcıyor. İkinci olarak, çok fazla standart kod gerektirdiğinden yeni özellik ve özellikler eklemek yorucudur. İşte LitElement burada devreye giriyor.

LitElement, Lit'in çerçeveler ve ortamlarda kullanılabilecek hızlı ve hafif Web Bileşenleri oluşturmaya yönelik temel sınıfıdır. Ardından, uygulamayı kullanacak şekilde değiştirerek LitElement uygulamasının rating-element içinde bizim için neler yapabileceğine bir göz atın.

LitElement'ı kullanma

lit paketindeki LitElement temel sınıfını içe veya alt sınıfa aktararak 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 içe aktarılsın. Ardından html içe aktarmanızı saklar ve son olarak da css. Bu işlem, CSS matematiği, şablon oluşturma ve arka planda bulunan diğer özellikler için css etiketli şablon değişmez değerlerini tanımlamamıza olanak tanır.

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;
      }
    `;
  }
 ...

Edebiyatta stillerin çoğu burada bulunur. Bu stilleri alıp daha hızlı oluşturma süreleri sağlamak ve gerekirse eski tarayıcılardaki Web Bileşenleri çoklu dolgusundan geçirmek için Oluşturulabilir Stil Sayfaları gibi tarayıcı özelliklerini kullanır.

Yaşam döngüsü

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

Bu özelliği kullanmak için oluşturma yaşam döngüsünü hangi özelliklerin 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 öğelerinin 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ımlayacağını 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>

Buna ek olarak, vote mülkündeki reflect işareti, vote belirleyicide manuel olarak tetiklediğiniz barındırma öğesinin vote özelliğini otomatik olarak günceller.

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

  • connectedCallback
  • observedAttributes
  • attributeChangedCallback
  • rating (belirleyiciler ve alıcılar)
  • vote (belirleyiciler ve alıcılar ancak değişim mantığını belirleyiciden uzak tutun)

constructor ve yeni bir willUpdate yaşam döngüsü yöntemi eklersiniz:

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 uygulamalarını ilk kullanıma hazırlar ve vote belirleyici mantığını willUpdate yaşam döngüsü yöntemine taşırsınız. LitElement, özellik değişikliklerini toplu hale getirdiği ve oluşturmayı eşzamansız hale getirdiği için, herhangi bir güncelleme özelliği değiştirildiğinde willUpdate yöntemi render öncesinde çağrılır. willUpdate ürününde reaktif ö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 işlevini çağırmanız gerekmez.

Öğeniz şimdi önizlemede oluşturulur; bir tıkla!

9. Tebrikler

Tebrikler, sıfırdan bir Web Bileşeni oluşturdunuz ve bunu bir LitElement öğesine dönüştürdünüz.

Edebiyat çok küçük (< 5 kb küçültülmüş + gzip ile sıkıştırılmış), çok hızlı ve kodlamak gerçekten eğlenceli. Bileşenlerin başka çerçeveler tarafından tüketilmesini sağlayabilir veya bunlarla tam teşekküllü uygulamalar geliştirebilirsiniz.

Artık Web Bileşeni'nin ne olduğunu, nasıl oluşturulacağını ve Lit'in bunları oluşturmayı nasıl kolaylaştırdığını biliyorsunuz.

Kod Kontrol Noktası

Nihai kodunuzu bizim kodumuzla karşılaştırarak kontrol etmek ister misiniz? Buradan karşılaştırabilirsiniz.

Sırada ne var?

Diğer codelab'lerden bazılarına göz atın.

Daha fazla bilgi

Topluluk