全ての記事

Polymer 3.0を見てみる

2019-01-05 @sunderls

js polymer

还记得 polymer 么?

嗯,很久以前听过后来就没有后来了,前段时间的 Chrome Dev 大会又提到了 polymer 貌似,然后就想说 polymer 怎么样了。 今天再来看看。

start guide: https://polymer-library.polymer-project.org/3.0/docs/first-element/intro

install

> npm install -g polymer-cli
> git clone https://github.com/PolymerLabs/polymer-3-first-element.git
> cd polymer-3-first-element
> npm i
> polymer serve --open

然后本地默认 8081 会启动服务器

index.html

这是 index html

<!DOCTYPE html>
<html>
  <head>
    <script src="../node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
    <script type="module" src="demo-element.js"></script>
  </head>
  <body>
    <demo-element></demo-element>
  </body>
</html>

webcomponents-loader.js ? 是 polyfill?待会儿再看。

<script type="module" src="demo-element.js"></script> 这个看来是定义了<demo-element>

首先了解一下 custom element

打开 dev console,输入以下代码

class MyComponent extends HTMLElement {
  constructor() {
    super();

    const shadow = this.attachShadow({ mode: "open" });
    const style = document.createElement("style");
    style.textContent = `button {color: red}`;
    const button = document.createElement("button");
    button.textContent = "click me";

    shadow.appendChild(style);
    shadow.appendChild(button);
  }
}

customElements.define("my-component", MyComponent);

其中我们创建了一个 custom element,这个 element 继承自 HTMLElement。

然后 element 显示的内容,包裹在一个 shadow dom 中。shadow dom 中可以包含 css 和 html,并且他们和外部不互相干扰。

customElements.define之后,这个 element 就可以使用了。我们试试直接在 console 左边添加<my-component></my-component>可以发现,button 被正确显示了出来。

polymer 中的实现。

我们看看 polymer 中的代码

// Polymer封装好的element库
import { PolymerElement, html } from "@polymer/polymer/polymer-element.js";
// Polymer的UI组件
import "@polymer/iron-icons/iron-icons.js";
// 这是另外一个element
import "../icon-toggle.js";

// 和extend HTMLElement有点类似
class DemoElement extends PolymerElement {
  static get template() {
    return html`
      <style>
        :host {
          font-family: sans-serif;
        }
      </style>

      <h3>Statically-configured icon-toggles</h3>
      <icon-toggle toggle-icon="star"></icon-toggle>
      <icon-toggle toggle-icon="star" pressed></icon-toggle>

      <h3>Data-bound icon-toggle</h3>
      <!-- use a computed binding to generate the message -->
      <div><span>[[_message(isFav)]]</span></div>
      <!-- curly brackets ({{}}} allow two-way binding -->
      <icon-toggle toggle-icon="favorite" pressed="{{isFav}}"></icon-toggle>
    `;
  }
  _message(fav) {
    if (fav) {
      return "You really like me!";
    } else {
      return "Do you like me?";
    }
  }
}
customElements.define("demo-element", DemoElement);

不懂的有以下几个地方:

  1. PolymerElement 的template()
  2. PolymerElement 的_message
  3. htmlxxx
  4. <icon-toggle>

一个一个来看。

template()

PolymerElement 是一个 wrapper,将 custom element 变的更方便来使用。 template 只是用来定义 custom element 模版的方法。

个人觉得是通过this.constructor来调用的。比如可以这么实现。

class MyPolymerElement {
  constructor() {
    const tmpl = this.constructor.template;
    // do something with tmpl
    console.log(tmpl);
  }
}

class SomeElement extends MyPolymerElement {
  static get template() {
    return "this is template";
  }
}

// new 一个
new SomeElement();

在 console 里面执行上述代码可以看到打印出了 this is template

_message()自定义 method

我们可以看到模版中有这么一段代码

<div><span>[[_message(isFav)]]</span></div>

好像以前用过的 handlebars?嘛,总之[[]]是用来作为占位符的。

这么一来 _message也就意味着,可以定义任何自己想要的名字。

html\``

这是用[tagged templates]写的一个模版解释器。返回一个处理 dom 的对象(或者方法) 具体没有研究其是如何处理 dom 更新的。

如果按照简单的想法,其内部是按照 react 的思想来的也说不定,但是感觉不太像。

总之 html``像是 polymer 中最核心的部分。解释调 template 过后,模版就和 element 的数据同步起来了。

这个以后我再研究研究。

<icon-toggle>

这是 element 中使用其他 element 的例子。

首先要 import:

import "../icon-toggle.js";

这里有点奇怪的就是 虽然是 import,但是实际上在 icon-toggle 中已经完成了 element 的定义了?

所以 import 像是全局的 polyfill。

总结

只是看了下 polymer 的例子。感觉如下:

  1. 基于 web component,也许是个未来,但是相比 react 其实需要理解的内容更多,并不简单。总之个人不喜欢
  2. 核心的概念还是 custom element,shadow dom 等 + 模版解释器。
  3. Polymer 貌似是 Chrome 团队的项目?虽然并不看好,但是加上 Chrome 本身的加持,Polymer 的某些概念还是代表了未来,至少最近的 Chrome 已经让我们看到浏览器对于 js library 的支持会带来巨大的影响。