Pojďme budovat webové komponenty! Část 4:Knihovna polymerů

Uživatelské rozhraní založené na komponentách je v dnešní době v módě. Věděli jste, že web má svůj vlastní modul nativních komponent, který nevyžaduje použití žádných knihoven? Pravdivý příběh! Můžete psát, publikovat a znovu používat jednosouborové komponenty, které budou fungovat v jakémkoli* dobrém prohlížeči a v jakémkoli rámci (pokud je to vaše taška).

V našem posledním příspěvku jsme se naučili psát jednosouborové komponenty s ničím jiným než JavaScriptem a DOM API.

Dnes se ponoříme do původní knihovny webových komponent:Polymer. Zrefaktorujeme <lazy-image> komponent, který jsme vytvořili minule, abychom využili užitečných funkcí Polymeru. Naučíme se také skládat celé aplikace z komponent na bázi polymerů pomocí jejich výrazného systému šablon a obousměrné vazby. Podíváme se na některé fantastické hotové papírové prvky publikované týmem Polymer. A nakonec prozkoumáme některé užitečné nástroje projektu Polymer a zjistíme, jak jsou užitečné pro jakýkoli projekt webových komponent, nejen pro aplikace Polymer.

  • Projekt Polymer
  • Refaktoring <lazy-image>
    • Vlastnosti
    • Šablony datových vazeb
  • Další funkce polymeru
    • Pokročilé vázání dat
    • Pozorovatelé a vypočítané vlastnosti
    • Deskriptory vlastností
    • Pomocné prvky
  • Skládání polymerových aplikací
  • Papírové prvky
  • Polymer Tools
    • prpl-server
    • Polymer CLI
    • WebComponents.org

The Polymer Project

Projekt Polymer začal již v roce 2012/2013 s cílem posunout možnosti webové platformy. Legenda praví, že hluboko v útrobách Googleplexu svolala skupina inženýrů prohlížeče Chrome tajnou seanci se skupinou webových vývojářů, aby zmapovali budoucí směřování webu jako celku.

Inženýři prohlížeče požádali vývojáře webu, aby jim řekli, jak chtějí, aby webový vývoj vypadal za pět let, a pak se pustili do jeho budování. Výsledkem bylo první vydání knihovny Polymer a začátek příběhu moderních webových komponent.

Od té doby se projekt Polymer uzavřel tak, že je nyní možné psát webové komponenty bez použití knihovny Polymer. Ale Polymer Project stále žije. Udržují různé návrhy webových platforem a obhajují typ vývoje webu více založený na standardech, než je v současnosti populární.

Na druhé straně knihovna Polymer se od té doby stala pouze jednou z mnoha alternativ pro faktoring webových komponent a aplikací založených na komponentách.

Nepleťte si tedy dvě věci. Projekt je o platformě obecně, Knihovně je o pomoci vám při sestavování komponent.

Refaktoring <lazy-image>

Pojďme se tedy ponořit! A protože jsme již vyvinuli náš <lazy-image> vanilkovou složkou, použijme ji jako základ také pro zkoumání Polymeru.

Náš první krok při refaktorování <lazy-image> bude instalace a import knihovny Polymer.

npm i -S @polymer/polymer

Také trochu přejmenujeme naši součást, aby nám pomohla udržet hlavu rovně:

import { PolymerElement, html } from '@polymer/polymer'

const tagName = 'polymer-lazy-image';

class PolymerLazyImage extends PolymerElement {
  /* ... */
}

customElements.define(tagName, PolymerLazyImage)

Polymer 3.0 a papírové prvky vyžadují, abychom aplikovali transformaci na všechny specifikátory modulu, buď v kroku sestavení, nebo jako běh serveru. Použijeme polymer serve , který pro nás transformuje holé specifikátory za běhu.

npm i -D polymer-cli
npx polymer serve

Dalším důležitým krokem, který bychom nyní měli udělat, než se pustíme do dalšího machrování, je zavolat super verze všech našich zpětných volání během životního cyklu.

connectedCallback() {
  super.connectedCallback();
  // ...
}

disconnectedCallback() {
  super.disconnectedCallback();
  // ...
}

Pokud tak neučiníte, způsobí to problémy, protože PolymerElement základní třída musí pracovat, když se dějí věci životního cyklu. Práce jako manipulace s polyfilly, kterou už nemusíme dělat ručně...

connectedCallback() {
  super.connectedCallback();
  this.setAttribute('role', 'presentation');
  if ('IntersectionObserver' in window) this.initIntersectionObserver();
  else this.intersecting = true;
}

Můžeme ztratit všechny shadowRoot - a ShadyCSS -související kód nyní, včetně updateShadyStyles , protože Polymer to zvládne za nás. Pěkný! Práce s knihovnami nám vzala jeden stres – podporu polyfillů – z naší mysli.

Vlastnosti

Polymer vám umožňuje deklarovat vlastnosti vašeho prvku staticky, a mám na mysli „staticky“ ve smyslu obou static get a „v době psaní“. Když deklarujete vlastnost v tomto bloku, Polymer se postará o synchronizaci atributů a vlastností za vás. To znamená, že když src je nastaven atribut na našem prvku, Polymer automaticky aktualizuje src vlastnost na instanci prvku.

Nyní tedy můžeme smazat naše attributeChangedCallback , safeSetAttribute a všechny naše gettery a nastavovače a nahraďte je statickou mapou vlastností s některými speciálními deskriptory specifickými pro polymery.

static get properties() {
  return {
    /** Image alt-text. */
    alt: String,

    /**
     * Whether the element is on screen.
     * @type {Boolean}
     */
    intersecting: {
      type: Boolean,
      reflectToAttribute: true,
      notify: true,
    },

    /** Image URI. */
    src: String,
  };
}

Polymer se standardně váže na vlastnosti, nikoli na atributy. To znamená, že pokud se navážete na jednu z vlastností svého prvku v šabloně polymeru hostitelského prvku, nemusí se to nutně zobrazit jako atribut prvku. Nastavení reflectToAttribute boolean na deskriptoru vlastnosti zajišťuje, že kdykoli se vlastnost změní, Polymer také nastaví příslušný atribut prvku. Nemějte však obavy, i když deklarujete vlastnost pomocí konstruktoru jako propName: String , změny atributů vždy aktualizují přidruženou vlastnost, bez ohledu na to, zda nastavíte reflectToAttribute .

Poznámka :Polymer převede názvy vlastností camelCase na názvy atributů malých a velkých písmen a naopak. To je mimochodem důvod, proč knihovna Polymer ve skutečnosti selhává v některých testech „Custom Elements Everywhere“.

notify boolean způsobí, že váš prvek odešle vlastní událost pokaždé, když se vaše vlastnost změní. Událost se bude jmenovat property-name-changed např. intersecting-changed pro intersecting vlastnost a bude mít tak, jak je detail vlastnost objekt obsahující klíč value která ukazuje na novou hodnotu vašeho majetku.

lazyImage.addEventListener('intersecting-changed', event => {
  console.log(event.detail.value) // value of 'intersecting';
})

To je základ dvoucestného systému vázání Polymer. Zde to není nezbytně nutné, ale můžeme tyto události také vystavit pro případ, že by uživatel chtěl svázat intersecting obrázku stav až do uzavírající komponenty.

Nyní tedy můžeme také odstranit setIntersecting metodu, protože s pomocí naší mapy nemovitostí a šablonovacího systému Polymer ji nebudeme potřebovat.

Více o deskriptorech vlastností Polymeru budeme mít později.

Šablony datových vazeb

Šablony prvku Polymer 3 definujeme statickým template getter, který vrací tagovaný literál šablony.

static get template() {
  return html`
    I'm the Template!
  `;
}

Polymerové šablony mají speciální syntaxi připomínající řídítka nebo knír. Jednosměrné (data-down) vazby jsou vytvořeny pomocí double-[[hranaté závorky]] a obousměrné (data-up) vazby jsou vytvořeny pomocí double-{{ složené závorky}} .

<some-input input="{{myInput}}"></some-input>

<some-element
    some-property="[[myInput]]"
    some-attribute$="[[myAttribute]]"
></some-element>

V tomto příkladu vždy, když <some-input> spustí input-changed událost, prvek hostitele aktualizuje someProperty vlastnost na <some-element> . Z hlediska JS je to jednoduché zadání:someElementInstance.someProperty = this.myInput .

Pokud se chcete svázat s atributem, místo vlastnosti připojte $ znak do vazby:kdykoli myOtherProp změny, some-attribute na <some-element> se aktualizuje:someElementInstance.setAttribute('some-attribute', this.myOtherProp) .

Podobně vždy, když input-changed vlastní událost se spustí na <some-input> , myInput vlastnost na hostitelské komponentě bude nastavena na detail.value události vlastnost.

V našem <polymer-lazy-image> šablony, nepoužíváme žádnou obousměrnou vazbu, takže zůstaneme u hranatých závorek.

aria-hidden atribut představuje malou výzvu. Polymer spojuje booleovské hodnoty s atributem s setAttribute(name, '') a removeAttribute(name) . Ale od aria-hidden musí převzít řetězcové literály "true" nebo "false" , nemůžeme to jen svázat s booleovskou hodnotou intersecting . <img/> src je podobně zajímavé. Ve skutečnosti jej chceme nastavit až poté, co se prvek protne. K tomu budeme muset vypočítat vlastnost src na obrázku na základě stavu intersecting vlastnost.

Polymerové šablony mohou obsahovat počítané vazby . Ty jsou vázány na návratovou hodnotu zvolené metody.

<img id="image"
    aria-hidden$="[[computeImageAriaHidden(intersecting)]]"
    src="[[computeSrc(intersecting, src)]]"
    alt$="[[alt]]"
/>

Co je s touto syntaxí podobnou funkci uvnitř našich vazebných výrazů? To říká Polymeru, kterou metodu prvku spustit a kdy. Spustí se pokaždé, když jsou pozorovány změny jeho závislostí (tj. „předané argumenty“ ve výrazu vazby), čímž se vazba aktualizuje o vrácenou hodnotu.

Všimněte si také, že jsme vázáni na src vlastnictví na obrázku, nikoli na atributu . Je to proto, abyste se nepokoušeli načíst obrázek na adrese URL "undefined" .

computeSrc(intersecting, src) {
  // when `intersecting` or `src` change,
  return intersecting ? src : undefined;
}

computeImageAriaHidden(intersecting) {
  // when `intersecting` changes,
  return String(!intersecting);
}

Nenechte se však zmást, nejedná se o výrazy JavaScript, takže nemůžete zadat žádnou hodnotu, kterou chcete:[[computeImageAriaHidden(!intersecting)]] nefunguje, ani [[computeImageAriaHidden(this.getAttribute('aria-hidden'))]]

Nyní jen mírně upravíme naši mapu vlastností a styly, abychom zohlednili změny v API našeho prvku:

static get properties() {
  return {
    // ...

    /** Whether the element is intersecting. */
    intersecting: Boolean,

    /**
     * Whether the image has loaded.
     * @type {Boolean}
     */
    loaded: {
      type: Boolean,
      reflectToAttribute: true,
      value: false,
    },

  };
}
<style>
  /* ... */
  #placeholder ::slotted(*),
  :host([loaded]) #image {
    opacity: 1;
  }

  #image,
  :host([loaded]) #placeholder ::slotted(*) {
    opacity: 0;
  }
</style>

<div id="placeholder" aria-hidden$="[[computePlaceholderAriaHidden(intersecting)]]">
  <slot name="placeholder"></slot>
</div>

<img id="image"
    aria-hidden$="[[computeImageAriaHidden(intersecting)]]"
    src="[[computeSrc(intersecting, src)]]"
    alt$="[[alt]]"
    on-load="onLoad"
/>

Podařilo se nám tedy podstatně snížit standardizovaný obsah v naší komponentě a zkrátit část přebytečné logiky jejím zahrnutím do naší šablony, i když s několika poněkud únavnými výpočetními pomocníky pro vazby.

Zde je náš dokončený <polymer-lazy-image> modul:

import { PolymerElement, html } from '@polymer/polymer';

const isIntersecting = ({isIntersecting}) => isIntersecting;

const tagName = 'polymer-lazy-image';

class PolymerLazyImage extends PolymerElement {
  static get template() {
    return html`
      <style>
        :host {
          position: relative;
        }

        #image,
        #placeholder ::slotted(*) {
          position: absolute;
          top: 0;
          left: 0;
          transition:
            opacity
            var(--lazy-image-fade-duration, 0.3s)
            var(--lazy-image-fade-easing, ease);
          object-fit: var(--lazy-image-fit, contain);
          width: var(--lazy-image-width, 100%);
          height: var(--lazy-image-height, 100%);
        }

        #placeholder ::slotted(*),
        :host([loaded]) #image {
          opacity: 1;
        }

        #image,
        :host([loaded]) #placeholder ::slotted(*) {
          opacity: 0;
        }
      </style>

      <div id="placeholder" aria-hidden$="[[computePlaceholderAriaHidden(intersecting)]]">
        <slot name="placeholder"></slot>
      </div>

      <img id="image"
        aria-hidden$="[[computeImageAriaHidden(intersecting)]]"
        src="[[computeSrc(intersecting, src)]]"
        alt$="[[alt]]"
        on-load="onLoad"
      />
    `;
  }

  static get properties() {
    return {
      /** Image alt-text. */
      alt: String,

      /** Whether the element is on screen. */
      intersecting: Boolean,

      /** Image URI. */
      src: String,

      /**
       * Whether the image has loaded.
       * @type {Boolean}
       */
      loaded: {
        type: Boolean,
        reflectToAttribute: true,
        value: false,
      },

    };
  }

  constructor() {
    super();
    this.observerCallback = this.observerCallback.bind(this);
  }

  connectedCallback() {
    super.connectedCallback();
    // Remove the wrapping `<lazy-image>` element from the a11y tree.
    this.setAttribute('role', 'presentation');
    // if IntersectionObserver is available, initialize it.
    if ('IntersectionObserver' in window) this.initIntersectionObserver();
    // if IntersectionObserver is unavailable, simply load the image.
    else this.intersecting = true;
  }

  disconnectedCallback() {
    super.disconnectedCallback();
    this.disconnectObserver();
  }

  /**
   * Loads the img when IntersectionObserver fires.
   * @param  {Boolean} intersecting
   * @param  {String} src
   * @return {String}
   */
  computeSrc(intersecting, src) {
    return intersecting ? src : undefined;
  }

  /**
   * "true" when intersecting, "false" otherwise.
   * @protected
   */
  computePlaceholderAriaHidden(intersecting) {    
    return String(intersecting);
  }

  /**
   * "false" when intersecting, "true" otherwise.
   * @protected
   */
  computeImageAriaHidden(intersecting) {
    return String(!intersecting);
  }

  /** @protected */
  onLoad() {
    this.loaded = true;
  }

  /**
   * Sets the `intersecting` property when the element is on screen.
   * @param  {[IntersectionObserverEntry]} entries
   * @protected
   */
  observerCallback(entries) {
    if (entries.some(isIntersecting)) this.intersecting = true;
  }

  /**
   * Initializes the IntersectionObserver when the element instantiates.
   * @protected
   */
  initIntersectionObserver() {
    if (this.observer) return;
    // Start loading the image 10px before it appears on screen
    const rootMargin = '10px';
    this.observer = new IntersectionObserver(this.observerCallback, { rootMargin });
    this.observer.observe(this);
  }

  /**
   * Disconnects and unloads the IntersectionObserver.
   * @protected
   */
  disconnectObserver() {
    this.observer.disconnect();
    this.observer = null;
    delete this.observer;
  }
}

customElements.define(tagName, PolymerLazyImage);

Podívejte se na rozdíl mezi vanilkou a polymerovou verzí a podívejte se, jak komponenta funguje:

Další funkce polymeru

Polymer nabízí více, než může náš jednoduchý příklad prvku snadno ukázat. Malým příkladem je způsob, jakým Polymer mapuje všechny id 'd prvků ve vaší šabloně na objekt s názvem $ :

<paper-button id="button">Button!</paper-button>
<paper-input id="input" label="Input!"></paper-input>
connectedCallback() {
  console.log(this.$.button.textContent) // "Button!"
  this.$.input.addEventListener('value-changed', breakTheInternet);
}

Pokročilé vázání dat

Polymer se také může vázat na vlastnosti hostitele z událostí nepolymerních prvků se speciální syntaxí:

<video current-time="{{videoTime::timeupdate}}"/>

To znamená, "když timeupdate událost se spustí, přiřaďte místní videoTime vlastnost na currentTime prvku videa ".

."

V pozdější iteraci <polymer-lazy-image> , můžeme tyto druhy vazeb použít k synchronizaci interního <img> vlastnosti s našimi vlastními.

Chcete-li se dozvědět více o systému vázání dat Polymeru, přečtěte si dokumenty.

Pozorovatelé a vypočítané vlastnosti

Vypočtené vlastnosti a vazby jsou specializovanými případy pozorovatelů Polymeru . Jednoduchý pozorovatel vypadá takto:

static get properties() {
  return {
    observed: {
      type: String,
      observer: 'observedChanged',
    },
  };
}

observedChanged(observed, oldVal) {
  console.log(`${ observed } was ${ oldVal }`);
}

Můžete také definovat komplexní pozorovatele, kteří využívají více závislostí nebo hluboce pozorují objekty nebo pole.

static get properties() {
  return {
    observed: Object,
    message: {
      type: String,
      value: 'A property of observed has changed',
    },
  };
}

static get observers() {
  return [
    // careful: deep observers are performance intensive!
    'observedChanged(message, observed.*)'
  ],
}

observedChanged(message, { path, value, base }) {
  // path: the path through the object where the change occurred
  // value: the new value at that path
  // base: the root object e.g. `observed`
  console.log(message, path + ': ' + value);
}

Můžete také nastavit počítané vlastnosti, podobné počítaným vazbám:

static get properties() {
  return {
    theString: String,
    theLength: {
      type: Number,
      computed: 'computeTheLength(theString)',
    },
  };
}

computeTheLength(theString) {
  return theString.length;
}

V takovém případě theLength se aktualizuje podle computeTheLength kdykoli theString změny.

Tyto vypočítané vlastnosti pak mohou být svázány s vaší šablonou jako každá normální vlastnost.

<span>[[theString]] has [[theLength]] characters</span>

Přečtěte si vše o pozorovatelích polymeru v docs.

Popisy vlastností

Již jsme viděli, jak můžeme nastavit reflectToAttribute a notify ovlivnit vnější svět při aktualizaci našich hodnot a jak nastavit jednoduché pozorovatele pomocí observer deskriptor.

Můžete také nastavit výchozí hodnotu pomocí value , který má buď doslovnou hodnotu, nebo funkci.

static get properties() {
  return {
    prop: {
      type: String,
      value: '🚣‍♂️'
    },

    things: {
      type: Array,
      value: () => [],
    },
  };
}

Buďte opatrní! Když chcete nastavit výchozí hodnotu s typem reference jako Array nebo Object , nezapomeňte předat funkci nebo jinak každou instanci vašeho prvku bude sdílet stejnou referenci.

value přiřazení jsou nastavena jednou při inicializaci komponenty a poté se znovu neaktualizují. Pokud potřebujete po připojení dynamicky nastavit vlastnosti, použijte vypočítané vlastnosti nebo pozorovatele.

Pomocné prvky

Polymer je dodáván s několika pomocnými prvky, které můžete použít ve svých šablonách, abyste snížili množství nezbytného JavaScriptu, který musíte psát. Dva nejčastěji používané jsou <dom-repeat> pro iteraci seznamů a výstup DOM a <dom-if> pro podmíněné vykreslování:

<!-- Will output a new article with h2 and img for each post -->
<dom-repeat items="[[posts]]" as="post">
  <template>
    <article>
      <h2>[[post.title]]</h2>
      <img src$="[[post.picture]]">
    </article>
  </template>
</dom-repeat>

<!-- Will only render it's template if conditionDepending(someProp, another) is truthy -->
<dom-if if="[[conditionDepending(someProp, another)]]">
  <template>
    I'm a very lucky textNode to have [[someProp]] and [[another]] on my side.
  </template>
</dom-if>

Chcete-li tyto pomocníky používat, nezapomeňte je importovat

import '@polymer/polymer/lib/elements/dom-repeat.js';
import '@polymer/polymer/lib/elements/dom-if.js';

Další informace o pomocných prvcích naleznete v dokumentech Polymer.

Skládání aplikací Polymer

Polymer opravdu září, pokud jde o faktoring celých aplikací. Projekt Polymer byl průkopníkem docela progresivního a zjevně speciálního (pardon) druhu deklarativní struktury aplikací postavené převážně na prvcích HTML. Přístup Polymer dělá ze „všeho prvek prvek“ a využívá vestavěnou složitelnost HTML. Například je tu <iron-ajax> prvek, který může načíst zdroje a vystavit je datové vazbě Polymeru.

<iron-ajax auto
    url="/api/posts"
    handle-as="json"
    last-response="{{posts}}"></iron-ajax>

<dom-repeat items="[[posts]]" as="post">
  <template>
    <article>
      <h2>[[post.title]]</h2>
      <img hidden$="[[!post.cover]]" src$="[[post.cover]]">
      [[post.body]]
    </article>
  </template>
</dom-repeat>

Ale podle mého skromného názoru je nejlepším příkladem tohoto přístupu <app-route> prvek a myšlenka zapouzdřeného směrování:

<!-- <app-shell> template -->

<!-- Capture and expose address-bar changes -->
<app-location route="{{route}}"></app-location>

<app-route route="[[route]]"
    data="{{routeData}}"
    tail="{{pageTail}}"
    pattern="/:page"></app-route>

<!-- Composed routing! -->
<app-route route="[[tail]]"
    data="{{itemData}}"
    tail="{{itemTail}}"
    pattern="/:itemId"></app-route>

<iron-pages selected="{{routeData.page}}" attr-for-selected="name">
  <app-master name="master"></app-master>
  <app-detail name="detail"
      item-id="[[itemData.itemId]]"
      route="[[itemTail]]"></app-detail>
</iron-pages>

Pomocí prvků app-route a iron-pages máme kompletní řešení pro směrování, které skryje a zobrazí obsah na základě adresy URL a dokonce těmto komponentám zobrazení předá data související s trasou.

A od <app-route> trvá to route vlastnost jako data, která nejsou přímo svázána s window.location , můžete předat části trasy dolů do podřízených zobrazení a nechat je spravovat svůj vlastní vnitřní stav pomocí vlastního <app-route> děti. Skvělé!

<!-- <app-detail> template -->
<app-route route="[[route]]"
    data="{{routeData}}"
    pattern="/:editing"></app-route>

<item-detail hidden$="[[routeData.editing]]"></item-detail>
<item-editor hidden$="[[!routeData.editing]]"></item-editor>

<paper-checkbox checked="{{routeData.editing}}">Editing</paper-checkbox>

Skvělý koncept!

**Všimněte si**, že kvůli stručnosti se v tomto příkladu vážeme přímo na podvlastnosti `routeData`, ale ve skutečném projektu bychom přidali některé pomocné metody pro výpočet mezilehlé vlastnosti `page` z `routeData '.

Plně realizovaný příklad tohoto typu architektury aplikací najdete v úctyhodném Polymer Starter Kit na GitHubu.

Polymer/polymer-starter-kit

Výchozí bod pro aplikace Polymer

Polymer App Toolbox – Starter Kit

Tato šablona je výchozím bodem pro vytváření aplikací pomocí rozložení založeného na zásuvkách. Rozvržení zajišťuje app-layout prvky.

Tato šablona spolu s polymer-cli toolchain, také demonstruje použití „vzoru PRPL“ Tento vzor umožňuje rychlé první doručení a interakci s obsahem na počáteční trase požadované uživatelem, spolu s rychlou následnou navigací pomocí předběžného ukládání zbývajících komponent požadovaných aplikací do mezipaměti a jejich postupným načítáním na vyžádání. jak uživatel prochází aplikací.

Vzor PRPL, v kostce:

  • Push komponenty požadované pro počáteční trasu
  • Vykreslit počáteční trasa ASAP
  • Předběžné ukládání do mezipaměti komponenty pro zbývající trasy
  • Lazy-load a postupně upgradovat další trasy na vyžádání

Nastavení

Předpoklady

Nainstalujte Polymer CLI pomocí npm (předpokládáme, že máte předinstalovaný node.js).

npm install -g polymer-cli
Inicializovat projekt ze šablony
mkdir my-app
cd my-app
polymer init polymer-3-starter-kit

Spusťte vývojový server

Tento příkaz slouží…

Zobrazit na GitHubu

Papírové prvky

Nebyl by to příspěvek na blogu o Polymeru, kdybychom nezmínili Paper Elements, sadu materiálových designových UI komponent publikovanou Polymer Project. Ale také bychom udělali obrovskou chybu, kdybychom jednu věc nevyjasnili:

PaperElements != Polymer;

Knihovnu polymerů můžete použít bez použití papírových prvků a můžete použít papírové prvky v pohodě bez použití knihovny polymerů!

<head>
  <script type="module" src="https://unpkg.com/@polymer/paper-checkbox/paper-checkbox.js?module"></script>
  <script type="module" src="https://unpkg.com/@polymer/paper-card/paper-card.js?module"></script>
  <script type="module" src="https://unpkg.com/@polymer/paper-button/paper-button.js?module"></script>
</head>  
<body>
  <paper-card heading="Am I Checked?">
    <div class="card-content">
      Output: <span id="output">Not Checked</span>
    </div>
    <div class="card-actions">
      <paper-checkbox id="input">Check me!</paper-checkbox>
      <paper-button raised disabled id="button">Reset</paper-button>
    </div>
  </paper-card>
  <script>
    const onClick = () => input.checked = false;
    const onInput = ({detail: { value }}) => {
      output.textContent = value ? 'Checked' : 'Not Checked';
      button.disabled = !value;
    }

    input.addEventListener('checked-changed', onInput);
    button.addEventListener('click', onClick);
  </script>
</body>

Jediné, co zde ztrácíme, je schopnost používat systém datové vazby Polymeru. Ale - uhodli jste správně - existuje pro to prvek, nazvaný <dom-bind>

Pokud chcete bez problémů zohlednit uživatelské rozhraní založené na materiálovém designu – vyzkoušejte papírové prvky.

Polymer Tools

The Polymer Project – kromě jejich obhajovací práce, JS a knihoven komponent a návrhů standardů – také publikuje řadu nástrojů, které vám pomohou vytvořit, publikovat a poskytovat vaše aplikace a komponenty.

prpl-server

Tým Chrome vyvinul vzor PRPL jako osvědčený postup pro psaní a poskytování výkonných webových aplikací. prpl-server usnadňuje poskytování nejmenšího efektivního balíčku schopným prohlížečům a přitom stále podporuje starší prohlížeče s většími balíčky. K dispozici je hotová binární i expresní middlewarová knihovna. Zkuste to.

Polymer CLI

Vue CLI vám pomáhá vyvíjet aplikace Vue. Angular CLI vám pomáhá vyvíjet aplikace Angular. create-react-app vám pomůže vyvíjet aplikace React.

Polymer CLI vám pomůže vyvinout web aplikace.

Pravda, nabízí šablony pro prvky a aplikace Polymer 3, ale to není vše. polymer build a polymer serve příkazy vytvoří a obslouží všechny aplikace webových komponent. Transpilace je volitelná. Ve skutečnosti v podstatě jediná věc, kterou CLI udělá s vaším kódem, je nahrazení specifikátorů holých modulů jako import { PolymerElement } from '@polymer/polymer'; na relativní adresy URL, které může prohlížeč načíst přímo.

To jo. To je přesně to, o čem mluvím. Až budete mít příště projekt aplikace, zvažte jeho zohlednění pomocí webových komponent a rozhraní Polymer CLI.

Ale pokud chcete transpilovat pro starší prohlížeče (viz prpl-server výše), můžete definovat builds sekce polymer.json :

{
  "root": "~/projects/my-project",
  "entrypoint": "index.html",
  "shell": "src/my-project.js",
  "sources": [
   "src/my-project.js",
   "manifest/**",
   "package.json"
  ],
  "builds": [{
      "name": "es5prod",
      "preset": "es5-bundled",
      "addServiceWorker": true
    }, {
      "name": "es6prod",
      "preset": "es6-unbundled",
      "addServiceWorker": true
    }, {
      "name": "dev",
      "addServiceWorker": false,
      "js": {"minify": false, "compile": false},
      "css": {"minify": false},
      "html": {"minify": false},
      "bundle": false,
      "addPushManifest": false
    }]
}

Poté stačí nakonfigurovat prpl-server aby obsluhoval es6prod do moderních prohlížečů a es5prod do IE a kamarády a vyrazíte na závody.

Přečtěte si dokumenty, doktore!

WebComponents.org

Než odběhnete implementovat to <super-button> máte na mysli, proč nedat hledat na webcomponents.org, největším adresáři webových komponent.
Každý prvek je zobrazen se svou dokumentací, veřejným rozhraním API a způsobem instalace. Najdete zde také odkazy na npm a github.
Pokud jste autor komponent, neváhejte! Publikujte své komponenty, aby z nich měli užitek ostatní.

Závěry

Polymerová knihovna nepopiratelně předběhla dobu. Chtělo to přístup vyžadovat lepší webovou platformu a pak to udělat realitou, namísto pouhého obcházení omezení platformy.

Nyní, když jsou webové komponenty široce podporovány, má knihovna Polymer stále místo v naší sadě nástrojů pro webové vývojáře? Určitě ano! Některé projekty se přirozeně hodí k deklarativnímu stylu Polymeru. Některé týmy zjistí, jak mohou návrháři a autoři dokumentů dělat práci vývojářů s expresivním systémem vazby Polymer.

Není to všechno ☀️ a 🌹🌹 i když. S rozvojem platformy a širší webové komunity se vyvíjely i priority projektu Polymer. Polymer 3 bude pravděpodobně posledním velkým vydáním knihovny a stejně tak série 3.0 bude posledním vydáním papírových prvků.

Pojďme si tedy zopakovat některé výhody a nevýhody knihovny Polymer:

Výhody Nevýhody
Expresivní systém šablon Nelze předat JS přímo do šablon
Pozorovatelé a vypočítané vlastnosti, deklarativní posluchači událostí Velký řetězec závislostí podněcuje větší aplikace pouze s polymerem
Super skvělý a jedinečný přístup k deklarativní struktuře aplikace V dobrém i ve zlém, tento jedinečný deklarativní styl není tak populární jako jiné architektury
Vyspělá knihovna a sada komponent. Vyzkoušeno, otestováno a pravdivé Polymer.js je zcela zastaralý a nebude dostávat nové funkce, dokud nebude rozvětvený

Znamená to tedy pro Web Components konec? Sakra Ne! Polymer není zdaleka jedinou hrou ve městě. Odlehčená, deklarativní knihovna šablon JS s názvem lit-html a základní třídu vlastních prvků, která ji využívá, nazvanou LitElement jsou nové horkost. Dá-li Bůh, probereme je v příštím díle.

Tak se uvidíme 😊

Chtěli byste osobní mentoring na některé z témat, která jsou zde popsána?

Poděkování

Děkuji bez zvláštního pořadí Pascalu Schilpovi a @ruphin za jejich návrhy a opravy.

Podívejte se na další článek ze série