Что такое vue-lit, который You Da разместил на GitHub 3 дня назад?

внешний интерфейс Vue.js
Что такое vue-lit, который You Da разместил на GitHub 3 дня назад?

Без разрешения не может быть воспроизведен, оригинальный адрес:GitHub.com/Axuebian/art…

написать впереди

Днем 18 сентября по пекинскому времени Юда разместил сообщение на Weibo, и было немного людей, которые говорили резко. Увидев это выражение, все поняли, что должно произойти что-то большое. Конечно же, на момент написания этой статьиGitHubЯ посмотрел на это и только что наткнулся на выпуск:

Мы знаем, что общее программное обеспечение с открытым исходным кодомreleaseтолько одинОкончательный версия, взгляните на официальную информацию об этомreleaseВведение версии:

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

больше об этомreleaseДля получения информации о версии выполните следующие действия:GitHub.com/v UE JS/v UE-вы…

Кроме того, я в ЮтеGitHubнашел еще одну вещь наvue-lit, моя интуиция подсказывает мне, что это еще один ххх следующего поколения, ориентированный на будущее, поэтому я щелкнул и посмотрел, что это была за новая игрушка.

Hello World

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

Похоже на отличную попытку проверки концепции, см.custom elementа такжеlit-html, слепая догадка, это программа, которая может рендериться прямо в браузереvueнаписаноWeb ComponentИнструмент.

упоминается здесьlit-html, который будет представлен позже.

По словам ЮдыDemo, давай попробуемHello World:

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

Откройте это напрямую без каких-либо инструментов компиляции и упаковкиindex.html, который выглядит нормально:

!

Как видите, то, что здесь отображается,Web Component,а такжеmountedЖизненный цикл также запускается.

О lit-html и lit-element

Смотретьvue-litПеред этим давайте разбиратьсяlit-htmlа такжеlit-ement, эти две штуки на самом деле уже давно нет, может не все понимают.

lit-html

lit-htmlМногие люди не могут быть знакомы с этим или даже не видели.

Так что же это? ответМеханизм шаблонов HTML.

Если нет ощущения тела, я задаю вопрос,ReactЧто такое основные вещи? Все ответят:jsx,Virtual-DOM,diff, да, это то, что составляетUI = f(data)изReact.

приди и посмотриjsxсинтаксис:

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

посмотри сноваlit-htmlсинтаксис:

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

мы знаемjsxЭто последний слой, который должен быть скомпилирован?createElement … а такжеlit-htmlне то же самое, оно основано наtagged template, заставляя его работать в браузере без компиляции, иHTML TemplateСочетание того, как играть и как играть, расширяет возможности сильнее, не так ли ароматно?

Конечно, будь тоjsxещеlint-html,этоAppвсе нужноrenderк реальномуDOMначальство.

lint-html реализует компонент Button

Перейдите непосредственно к коду (опустите код стиля):

<!DOCTYPE html>
<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) => {
      // 点击事件
      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было бы лучше, чемReactПроизводительность лучше? Я не читал внимательно исходный код здесь и не проводил соответствующих экспериментов, поэтому не могу сделать вывод.

Но возьми дикую догадку,lit-htmlкласс не используетсяdiffВместо этого алгоритм напрямую основан на том жеtemplate, похоже, этот способ будет немного легче.

Тем не менее, вопрос, который мы часто задаем: «Какая польза от ключа при рендеринге списка?», это вlit-htmlНеужели нельзя решить. Если я удалю один из элементов в длинном списке, следуйтеlit-htmlоснованный на том жеtemplateВесь лонг-лист обновится один раз, а производительность сильно ухудшится.

// TODO: зарыть дыру и посмотреть позже

lit-element

lit-elementЧто это?

Ключевые слова: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);

Эффект:

В заключение: класс можно использоватьReactграмматика для написанияWeb Component.

so, lit-elementЯвляется ли созданиеWeb Componentизbase class. Проанализируйте приведенную выше демонстрацию,lit-elementЧто сделал:

  1. static get properties: Могуsetterизstate
  2. constructor: инициализироватьstate
  3. render: пройти черезlit-htmlвизуализирует элемент и создастShadowDOM

Вкратце,lit-elementподчинятьсяWeb Componentsстандарт, этоclass, на основе которого можно быстро создатьWeb Component.

Подробнее о том, как использоватьlit-elementДля развития это не будет обсуждаться здесь.

Web Components

Является ли родная возможность браузера ароматной?

СказатьWeb ComponentsПрежде чем я хочу спросить вас всех, вы все еще помнитеjQueryДа, он запоминается своим удобным селектором. но потомdocument.querySelectorэтоAPIпоявился и широко используется, все, кажется, постепенно забываютjQuery.

родной браузерAPIЭто достаточно хорошо для использования, нам это не нужно для работыDOMпри использованииjQuery.

You Dont Need jQuery

Позже, вы долго не эксплуатировали его напрямую?DOMуже?

Да, из-заReact / VueПоявление рамки (библиотеки) помогло нам сделать много вещей, и мы больше не можем пройти через сложныеDOM APIработатьDOM.

Что я хочу сказать, так это то, что однажды, если собственные возможности браузера будут достаточно хороши для использования,ReactПодождите, будет ли это похожеjQueryЗаменяется ли он родными возможностями браузера?

составной

картинаReact / VueДругие фреймворки (библиотеки) делают то же самое, и нативные возможности браузеров не могли быть реализованы раньше, например, создание многократно используемого компонента, который можно отображать вDOMв любом месте.

что теперь? Кажется, мы можем не использовать произвольные фреймворки и библиотеки или даже упаковывать и компилировать, просто передатьWeb ComponentsТакие нативные возможности браузера позволяют создавать повторно используемые компоненты.Откажемся ли мы сейчас от так называемых фреймворков и библиотек и будем использовать нативные?APIили использовать на основеWeb ComponentsСтандартные фреймворки и библиотеки разрабатывать?

Конечно, будущее неизвестно

Я не безмозглый разоблачитель веб-компонентов, но нам нужно программировать на будущее.

приди и посмотриWeb Componentsнекоторые основные функции.

Пользовательские элементы: пользовательские элементы

Пользовательские элементы, как следует из названия, определяются пользователем.HTMLэлемент, черезCustomElementRegistryизdefineопределить, например:

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

потом напрямую через<my-element />использовал.

Согласно спецификации их два.Custom elements:

  • Autonomous custom elements: независимый элемент, не наследуетHTMLЭлемент, когда используется напрямую<my-element />
  • Customized buld-in elements: унаследовано отHTMLэлементы, такие как через{ extends: 'p' }выявить унаследованное отpэлемент, необходимый при использовании<p is="my-element"></p>

дваCustom elementsТакже есть отличия в реализации:

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

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

Подробнее о пользовательских элементах

Функции жизненного цикла

существуетCustom elementsВ конструкторе можно указать несколько функций обратного вызова, которые будут вызываться при разном времени жизни элемента.

  • connectedCallback: элемент сначала вставляется в документDOMВремя
  • disconnectedCallback: элемент из документаDOMпри удалении в
  • adoptedCallback: когда элемент перемещается в новый документ
  • attributeChangedCallback: Когда элемент добавляет, удаляет или изменяет свои собственные атрибуты

Давайте обратим внимание здесьattributeChangedCallback, заключается в том, что всякий раз, когда атрибуты элемента изменяются, будет выполняться функция обратного вызова, и будет получена соответствующая информация об элементе:

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

Важно помнить, что если вам нужноатрибутПосле изменения запуститеattributeChangedCallback()функция обратного вызова, вы должныконтролировать это свойство:

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

элементальmy-nameПри изменении свойства запускается метод обратного вызова.

Shadow DOM

Web ComponentsОчень важная функция, структура и стиль могут быть инкапсулированы внутри компонента, изолированы от остального кода на странице, эта функция черезShadow DOMвыполнить.

оShadow DOM, тут в основном хочу сказатьCSSОсобенности стилевой изоляции.Shadow DOMвнутри и снаружиselectorОни не могут быть получены друг от друга, поэтому нет возможности использовать внешние стили внутри, и, конечно, внешние не могут получить внутренние стили.

Какая от этого польза? фокус, изоляция стиля,Shadow DOMместнымHTMLа такжеCSS, который решает некоторые проблемы со стилем, напримерvueизscopeЧувство элемента, не заботьтесь о внутренней части элементаselectorа такжеCSS ruleБудет ли он перезаписан другими или случайно перезаписан чужими стилями? Следовательно, элементselectorочень простой:title / itemи т. д., без каких-либо ограничений по инструментам или именам.

Подробнее о Shadow DOM

Шаблоны: Шаблоны

в состоянии пройти<template>добавитьWeb ComponentизShadow DOMвнутреннийHTMLсодержание:

<body>
  <template id="my-paragraph">
    <style>
      p {
        color: white;
        background-color: #666;
        padding: 5px;
      }
    </style>
    <p>My paragraph</p>
  </template>
  <script>
    customElements.define('my-paragraph',
      class extends HTMLElement {
        constructor() {
          super();
          let template = document.getElementById('my-paragraph');
          let templateContent = template.content;

          const shadowRoot = this.attachShadow({mode: 'open'}).appendChild(templateContent.cloneNode(true));
        }
      }
    )
  </script>
  <my-paragraph></my-paragraph>
</body>

Эффект:

мы знаем,<template>не будет отображаться напрямую, поэтому мы можем определить несколько<template>Затем выберите визуализацию различных элементов в соответствии с различными условиями при настройке элементов.<template>? Ответ, конечно же: да.

Подробнее о шаблонах

vue-lit

представилlit-html/elementа такжеWeb Components, вернемся к Йоде этоvue-lit.

Сначала мы видим вVue 3.0изReleaseЕсть такой абзац:

The @vue/reactivity module exports functions that provide direct access to Vue's reactivity system, and can be used as a standalone package. It can be used to pair with other templating solutions (e.g. lit-html) or even in non-UI scenarios.

Я имею в виду, наверное@vue/reactivityМодули и подобноеlit-htmlсо схемой также можно спроектировать прямой доступVueРешения для адаптивных систем.

Случайность не, да, это неvue-lit?

Анализ исходного кода

import { render } from 'https://unpkg.com/lit-html?module'
import {
  shallowReactive,
  effect
} from 'https://unpkg.com/@vue/reactivity/dist/reactivity.esm-browser.js'
  • lit-htmlпредоставить ядроrenderспособность
  • @vue/reactiityпоставкаVueСила отзывчивой системы

Вот небольшое объяснениеshallowReactiveа такжеeffect, без расширения:

shallowReactive: Простое понимание - это «поверхностный ответ», аналогичный «поверхностному копированию», это только первый уровень данных ответа.

const state = shallowReactive({
  a: 1,
  b: {
    c: 2,
  },
})

state.a++ // 响应式
state.b.c++ // 非响应式

effect: Простое пониманиеwatcher

const state = reactive({
  name: "前端试炼",
});
console.log(state); // 这里返回的是Proxy代理后的对象
effect(() => {
  console.log(state.name); // 每当name数据变化将会导致effect重新执行
});

Затем посмотрите вниз:

export function defineComponent(name, propDefs, factory) {
  // propDefs
  // 如果是函数,则直接当作工厂函数
  // 如果是数组,则监听他们,触发 attributeChangedCallback 回调函数
  if (typeof propDefs === 'function') {
    factory = propDefs
    propDefs = []
  }
  // 调用 Web Components 创建 Custom Elements 的函数
  customElements.define(
    name,
    class extends HTMLElement {
      // 监听 propDefs
      static get observedAttributes() {
        return propDefs
      }
      constructor() {
        super()
        // 创建一个浅响应
        const props = (this._props = shallowReactive({}))
        currentInstance = this
        const template = factory.call(this, props)
        currentInstance = null
        // beforeMount 生命周期
        this._bm && this._bm.forEach((cb) => cb())
        // 定义一个 Shadow root,并且内部实现无法被 JavaScript 访问及修改,类似 <video> 标签
        const root = this.attachShadow({ mode: 'closed' })
        let isMounted = false
        // watcher
        effect(() => {
          if (!isMounted) {
            // beforeUpdate 生命周期
            this._bu && this._bu.forEach((cb) => cb())
          }
          // 调用 lit-html 的核心渲染能力,参考上文 lit-html 的 Demo
          render(template(), root)
          if (isMounted) {
            // update 生命周期
            this._u && this._u.forEach((cb) => cb())
          } else {
            // 渲染完成,将 isMounted 置为 true
            isMounted = true
          }
        })
      }
      connectedCallback() {
        // mounted 生命周期
        this._m && this._m.forEach((cb) => cb())
      }
      disconnectedCallback() {
        // unMounted 生命周期
        this._um && this._um.forEach((cb) => cb())
      }
      attributeChangedCallback(name, oldValue, newValue) {
        // 每次修改 propDefs 里的参数都会触发
        this._props[name] = newValue
      }
    }
  )
}

// 挂载生命周期
function createLifecycleMethod(name) {
  return (cb) => {
    if (currentInstance) {
      ;(currentInstance[name] || (currentInstance[name] = [])).push(cb)
    }
  }
}

// 导出生命周期
export const onBeforeMount = createLifecycleMethod('_bm')
export const onMounted = createLifecycleMethod('_m')
export const onBeforeUpdate = createLifecycleMethod('_bu')
export const onUpdated = createLifecycleMethod('_u')
export const onUnmounted = createLifecycleMethod('_um')

// 导出 lit-hteml 和 @vue/reactivity 的所有 API
export * from 'https://unpkg.com/lit-html?module'
export * from 'https://unpkg.com/@vue/reactivity/dist/reactivity.esm-browser.js'

Упрощенная версия полезна для понимания

Глядя в целом, для лучшего понимания, мы можем упростить его, не рассматривая жизненный цикл:

import { render } from 'https://unpkg.com/lit-html?module'
import {
  shallowReactive,
  effect
} from 'https://unpkg.com/@vue/reactivity/dist/reactivity.esm-browser.js'

export function defineComponent(name, factory) {
  customElements.define(
    name,
    class extends HTMLElement {
      constructor() {
        super()
        const root = this.attachShadow({ mode: 'closed' })
        effect(() => {
          render(factory(), root)
        })
      }
    }
  )
}

Только эти процессы:

  1. СоздайтеWeb ComponentsизCustom Elements
  2. СоздаватьShadow DOMизShadowRootузел
  3. будет передан вfactoryи созданный внутриShadowRootПередача узлаlit-htmlизrenderвыносить

Оглядываясь назад на DEMO, предоставленное Youda:

import {
  defineComponent,
  reactive,
  html,
} from 'https://unpkg.com/@vue/lit'

defineComponent('my-component', () => {
  const msg = 'Hello World'
  const state = reactive({
    show: true
  })
  const toggle = () => {
    state.show = !state.show
  }
  
  return () => html`
    <button @click=${toggle}>toggle child</button>
    ${state.show ? html`<my-child msg=${msg}></my-child>` : ``}
  `
})

my-componentприближаетсяname, вторая — функция, т. е. входящаяfactory, по фактуlit-htmlПервый параметр просто вводит@vue/reactivityизreactiveспособность ставитьstateстал отзывчивым.

нет проблем, иVue 3.0 ReleaseСогласованный,@vue/reactivityможет иlit-htmlсотрудничать, чтобыVueа такжеWeb ComponentsИнтересно их собрать.

напиши в конце

Может быть, Youda просто написал эту маленькую игрушку по прихоти, но видно, что это действительно может быть большой тенденцией.

Угадайте, что эти ключевые слова внезапно взорвутся в ближайшем будущем:Unbundled / ES Modules / Web components / Custom Element / Shadow DOM...

Стоит ли ждать?

Мышление может быть относительно поверхностным, а письмо ограничено, и вы можете указать на недостатки.

Прием на работу

Международная команда Alibaba по инфраструктуре набирает внешних специалистов P6/P7, базу в Ханчжоу, строительство инфраструктуры, расширение возможностей бизнеса... Многое можно сделать.

Требуется знакомство с Engineering/Node/React... Вы можете отправить свое резюме прямо наyibin.xb@alibaba-inc.com.