<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          尤大 3 天前發(fā)在 GitHub 上的 vue-lit 是啥?

          共 11917字,需瀏覽 24分鐘

           ·

          2020-10-05 18:18


          寫在前面

          尤大北京時(shí)間 9月18日 下午的時(shí)候發(fā)了一個(gè)微博,人狠話不多??吹竭@個(gè)表情,大家都知道有大事要發(fā)生。果然,在寫這篇文章的時(shí)候,上 GitHub 上看了一眼,剛好碰上發(fā)布:

          我們知道,一般開源軟件的 release 就是一個(gè) 最終版本,看一下官方關(guān)于這個(gè) release 版本的介紹:

          Today we are proud to announce the official release of Vue.js 3.0 "One Piece".

          更多關(guān)于這個(gè) release 版本的信息可以關(guān)注:https://github.com/vuejs/vue-next/releases/tag/v3.0.0[1]

          除此之外,我在尤大的 GitHub 上發(fā)現(xiàn)了另一個(gè)東西 vue-lit[2],直覺告訴我這又是一個(gè)啥面向未來的下一代 xxx,所以我就點(diǎn)進(jìn)去看了一眼是啥新玩具。

          這篇文章就圍繞?vue-lit 展開說說。

          Hello World

          Proof of concept mini custom elements framework powered by @vue/reactivity and lit-html.

          首先,vue-lit 看上去是尤大的一個(gè)驗(yàn)證性的嘗試,看到 custom elementlit-html,盲猜一把,是一個(gè)可以直接在瀏覽器中渲染 vue 寫法的 Web Component 的工具。

          這里提到了 lit-html,后面會(huì)專門介紹一下。

          按照尤大給的 Demo,我們來試一下 Hello World


          <html?lang="en">
          ??<head>
          ????<script?type="module">
          ??????import?{
          ????????defineComponent,
          ????????reactive,
          ????????html,
          ????????onMounted
          ??????}?from?'https://unpkg.com/@vue/[email protected]';
          ??
          ??????defineComponent('my-component',?()?=>?{
          ????????const?state?=?reactive({
          ??????????text:?'Hello?World',
          ????????});
          ????????
          ????????function?onClick()?{
          ??????????alert('cliked!');
          ????????}
          ??
          ????????onMounted(()?=>?{
          ??????????console.log('mounted');
          ????????});
          ??
          ????????return?()?=>?html`
          ??????????<p>
          ????????????<button?@click=
          ${onClick}>Click?mebutton>
          ????????????
          ${state.text}
          ??????????p>

          ????????`;
          ??????})
          ????script>
          ??head>
          ??<body>
          ????<my-component?/>
          ??body>
          html>

          不用任何編譯打包工具,直接打開這個(gè) index.html,看上去沒毛?。?/p>

          可以看到,這里渲染出來的是一個(gè) Web Component,并且 mounted 生命周期也觸發(fā)了。

          介紹?vue-lit 之前,我們需要先有一些前置知識(shí)。

          關(guān)于 lit-html 和 lit-element

          vue-lit 之前,我們先了解一下 lit-htmllit-ement,這兩個(gè)東西其實(shí)已經(jīng)出來很久了,可能并不是所有人都了解。

          lit-html

          lit-html[3] 可能很多人并不熟悉,甚至沒有見過。

          所以是啥?答案是 HTML 模板引擎。

          如果沒有體感,我問一個(gè)問題,React 核心的東西有哪些?大家都會(huì)回答:jsx、Virtual-DOM、diff,沒錯(cuò),就是這些東西構(gòu)成了 UI = f(data)React。

          來看看 jsx 的語(yǔ)法:

          function?App()?{
          ??const?msg?=?'Hello?World';
          ??return?<div>${msg}div>;
          }

          再看看 lit-html 的語(yǔ)法:

          function?App()?{
          ??const?msg?=?'Hello?World';
          ??return?html`
          ????<div>
          ${msg}div>
          ??`;
          }

          我們知道 jsx 是需要編譯的它的底層最終還是 createElement....。而 lit-html 就不一樣了,它是基于 tagged template 的,使得它不用編譯就可以在瀏覽器上運(yùn)行,并且和 HTML Template 結(jié)合想怎么玩怎么玩,擴(kuò)展能力更強(qiáng),不香嗎?

          當(dāng)然,無論是 jsx 還是 lint-html,這個(gè) App 都是需要 render 到真實(shí) DOM 上。

          lint-html 實(shí)現(xiàn)一個(gè) Button 組件

          直接上代碼(省略樣式代碼):


          <html?lang="en">
          <head>
          ??<script?type="module">
          ????import?{?html,?render?}?from?'https://unpkg.com/lit-html?module';

          ????const?Button?=?(text,?props?=?{
          ??????type:?'default',
          ??????borderRadius:?'2px'
          ????},?onClick)?=>?{
          ??????//?點(diǎn)擊事件
          ??????const?clickHandler?=?{
          ????????handleEvent(e)?{?
          ??????????alert('inner?clicked!');
          ??????????if?(onClick)?{
          ????????????onClick();
          ??????????}
          ????????},
          ????????capture:?true,
          ??????};

          ??????return?html`
          ????????<div?class="btn?btn-
          ${props.type}"?@click=${clickHandler}>
          ??????????
          ${text}
          ????????div>

          ??????`

          ????};
          ????render(Button('Defualt'),?document.getElementById('button1'));
          ????render(Button('Primary',?{?type:?'primary'?},?()?=>?alert('outer?clicked!')),?document.getElementById('button2'));
          ????render(Button('Error',?{?type:?'error'?}),?document.getElementById('button3'));
          ??script>
          head>
          <body>
          ??<div?id="button1">div>
          ??<div?id="button2">div>
          ??<div?id="button3">div>
          body>
          html>

          效果:

          性能

          lit-html 會(huì)比 React 性能更好嗎?這里我沒仔細(xì)看過源碼,也沒進(jìn)行過相關(guān)實(shí)驗(yàn),無法下定論。

          但是可以大膽猜測(cè)一下,lit-html 沒有使用類 diff 算法而是直接基于相同 template 的更新,看上去這種方式會(huì)更輕量一點(diǎn)。

          但是,我們常問的一個(gè)問題 “在渲染列表的時(shí)候,key 有什么用?”,這個(gè)在 lit-html 是不是沒法解決了。我如果刪除了長(zhǎng)列表中的其中一項(xiàng),按照 lit-html 的基于相同 template 的更新,整個(gè)長(zhǎng)列表都會(huì)更新一次,這個(gè)性能就差很多了啊。

          // TODO:埋個(gè)坑,以后看

          lit-element

          lit-element[4] 這又是啥呢?

          關(guān)鍵詞:web components。

          例子

          import?{?LitElement,?html?}?from?'lit-element';

          class?MyElement?extends?LitElement?{
          ??static?get?properties()?{
          ????return?{
          ??????msg:?{?type:?String?},
          ????};
          ??}
          ??constructor()?{
          ????super();
          ????this.msg?=?'Hello?World';
          ??}
          ??render()?{
          ????return?html`
          ??????<p>
          ${this.msg}p>
          ????`;
          ??}
          }

          customElements.define('my-element',?MyElement);

          效果

          結(jié)論:可以用類 React 的語(yǔ)法寫 Web Component

          so, lit-element 是一個(gè)可以創(chuàng)建 Web Componentbase class。分析一下上面的 Demo,lit-element 做了什么事情:

          1. static get properties: 可以 setterstate
          2. constructor: 初始化 state
          3. render: 通過 lit-html 渲染元素,并且會(huì)創(chuàng)建 ShadowDOM

          總之,lit-element 遵守 Web Components 標(biāo)準(zhǔn),它是一個(gè) class,基于它可以快速創(chuàng)建 Web Component

          更多關(guān)于如何使用 lit-element 進(jìn)行開發(fā),在這里就不展開說了。

          Web Components

          瀏覽器原生能力香嗎?

          Web Components 之前我想先問問大家,大家還記得 jQuery 嗎,它方便的選擇器讓人難忘。但是后來 document.querySelector 這個(gè) API 的出現(xiàn)并且廣泛使用,大家似乎就慢慢地淡忘了 jQuery

          瀏覽器原生 API 已經(jīng)足夠好用,我們并不需要為了操作 DOM 而使用 jQuery。

          You Dont Need jQuery[5]

          再后來,是不是很久沒有直接操作過 DOM 了?

          是的,由于 React / Vue 等框架(庫(kù))的出現(xiàn),幫我們做了很多事情,我們可以不用再通過復(fù)雜的 DOM API 來操作 DOM。

          我想表達(dá)的是,是不是有一天,如果瀏覽器原生能力足夠好用的時(shí)候,React 等是不是也會(huì)像 jQuery 一樣被瀏覽器原生能力替代?

          組件化

          React / Vue 等框架(庫(kù))都做了同樣的事情,在之前瀏覽器的原生能力是實(shí)現(xiàn)不了的,比如創(chuàng)建一個(gè)可復(fù)用的組件,可以渲染在 DOM 中的任意位置。

          現(xiàn)在呢?我們似乎可以不使用任意的框架和庫(kù),甚至不用打包編譯,僅是通過 Web Components 這樣的瀏覽器原生能力就可以創(chuàng)建可復(fù)用的組件,是不是未來的某一天我們就拋棄了現(xiàn)在所謂的框架和庫(kù),直接使用原生 API 或者是使用基于 Web Components 標(biāo)準(zhǔn)的框架和庫(kù)來開發(fā)了?

          當(dāng)然,未來是不可知的

          我不是一個(gè) Web Components 的無腦吹,只不過,我們需要面向未來編程。

          來看看 Web Components 的一些主要功能吧。

          Custom elements: 自定義元素

          自定義元素顧名思義就是用戶可以自定義 HTML 元素,通過 CustomElementRegistrydefine 來定義,比如:

          window.customElements.define('my-element',?MyElement);

          然后就可以直接通過 使用了。

          根據(jù)規(guī)范,有兩種 Custom elements

          • Autonomous custom elements: 獨(dú)立的元素,不繼承任何 HTML 元素,使用時(shí)可以直接
          • Customized buld-in elements: 繼承自 HTML 元素,比如通過 { extends: 'p' } 來標(biāo)識(shí)繼承自 p 元素,使用時(shí)需要

          兩種 Custom elements 在實(shí)現(xiàn)的時(shí)候也有所區(qū)別:

          //?Autonomous?custom?elements
          class?MyElement?extends?HTMLElement?{
          ??constructor()?{
          ????super();
          ??}
          }

          // Customized buld-in elements:繼承自 p 元素
          class?MyElement?extends?HTMLParagraphElement?{
          ??constructor()?{
          ????super();
          ??}
          }

          更多關(guān)于 Custom elements[6]

          生命周期函數(shù)

          Custom elements 的構(gòu)造函數(shù)中,可以指定多個(gè)回調(diào)函數(shù),它們將會(huì)在元素的不同生命時(shí)期被調(diào)用。

          • connectedCallback:元素首次被插入文檔 DOM 時(shí)
          • disconnectedCallback:元素從文檔 DOM 中刪除時(shí)
          • adoptedCallback:元素被移動(dòng)到新的文檔時(shí)
          • attributeChangedCallback: 元素增加、刪除、修改自身屬性時(shí)

          我們這里留意一下 attributeChangedCallback,是每當(dāng)元素的屬性發(fā)生變化時(shí),就會(huì)執(zhí)行這個(gè)回調(diào)函數(shù),并且獲得元素的相關(guān)信息:

          attributeChangedCallback(name,?oldValue,?newValue)?{
          ??//?TODO
          }

          需要特別注意的是,如果需要在元素某個(gè)屬性變化后,觸發(fā) attributeChangedCallback() 回調(diào)函數(shù),你必須監(jiān)聽這個(gè)屬性

          class?MyElement?extends?HTMLElement?{
          ??static?get?observedAttributes()?{
          ????return?['my-name'];
          ??}
          ??constructor()?{
          ????super();
          ??}
          }

          元素的 my-name 屬性發(fā)生變化時(shí),就會(huì)觸發(fā)回調(diào)方法。

          Shadow DOM

          Web Components 一個(gè)非常重要的特性,可以將結(jié)構(gòu)、樣式封裝在組件內(nèi)部,與頁(yè)面上其它代碼隔離,這個(gè)特性就是通過 Shadow DOM 實(shí)現(xiàn)。

          關(guān)于 Shadow DOM,這里主要想說一下 CSS 樣式隔離的特性。Shadow DOM 里外的 selector 是相互獲取不到的,所以也沒辦法在內(nèi)部使用外部定義的樣式,當(dāng)然外部也沒法獲取到內(nèi)部定義的樣式。

          這樣有什么好處呢?劃重點(diǎn),樣式隔離,Shadow DOM 通過局部的 HTMLCSS,解決了樣式上的一些問題,類似 vuescope 的感覺,元素內(nèi)部不用關(guān)心 selectorCSS rule 會(huì)不會(huì)被別人覆蓋了,會(huì)不會(huì)不小心把別人的樣式給覆蓋了。所以,元素的 selector 非常簡(jiǎn)單:title / item 等,不需要任何的工具或者命名的約束。

          更多關(guān)于 Shadow DOM[7]

          Templates: 模板

          可以通過