前端笔记

分享前端开发思考与感悟

如何在Svelte中创建Web组件

在本文中,我们将看到如何使用Svelte框架创建Web组件。
在开始编写代码之前,我们首先来看一下Web组件是什么。

Web组件简介

Web组件是一组Web平台API,使您可以创建新的自定义,可重用和封装的HTML标记以用于网页和Web应用程序。自定义组件和窗口小部件基于Web组件标准,可在现代浏览器上运行,并且可以与任何HTML兼容的JavaScript库或框架一起使用。

Web组件基于四个主要规范:

自定义元素

自定义元素提供了一种构建自己的功能齐全的DOM元素的方法。通过定义自定义元素,作者可以通知解析器如何正确构造元素以及该类的元素应如何对更改做出反应。自定义元素包含它们自己的语义,行为,标记,并且可以在框架和浏览器之间共享。

影子DOM

影子DOM规范定义了如何在Web组件中使用封装的样式和标记。能够使标记的结构,样式和行为保持隐藏状态,并与页面上的其他代码分开,以使不同部分不会发生冲突。

ES模块

ES模块规范以基于标准,模块化,高效的方式定义了JS文档的包含和重用。JavaScript规范定义了模块的语法,以及模块处理模型中与主机无关的部分。该规范定义了其余的处理模型:如何通过类型属性设置为“ module”的script元素引导模块系统,以及如何获取,解析和执行模块

HTML模板

HTML模板元素规范定义了如何声明标记的片段,这些片段在页面加载时未使用,但可以稍后在运行时实例化。

Web组件技术可以独立使用,也可以共同使用。

如何使用网络组件?

使用Web组件非常简单。例如,可以使用从聚合物释放的网状组件库中存在的组件,例如以下组件:

https://www.webcomponents.org/element/@polymer/paper-button

从一个简单的网页开始:

<!doctype html>
<html>
  <head>
    <title>This is the title of the webpage!</title>
  </head>
  <body>
      <h1>Test Page</h1>
      <p>This is an example paragraph.</p>
  </body>
</html>

可以导入包含Web组件的脚本来开始使用库组件,就好像这是一个简单的html元素一样。

<html>
  <head>
    <title>This is the title of the webpage!</title>
    <script type="module" src="https://npm-demos.appspot.com/@polymer/[email protected]/[email protected]/[email protected]"></script>
  </head>
  <body>
      <h1>Test Page</h1>
      <p>This is an example paragraph.</p>
      <paper-button raised class="indigo">button</paper-button>
  </body>
</html>

什么是斯维尔特?

Svelte是Rich Harris编写的JavaScript框架。Svelte应用程序不包含框架引用。
传统的框架(如React,Vue或Angular)会在浏览器中完成大部分工作,而Svelte会将其转变为在构建应用程序时发生的编译步骤。
Svelte生成用于处理DOM的代码,这可能会提供更好的客户端运行时性能。

Svelte不会使用虚拟DOM差异之类的技术,而是编写可在您的应用程序状态更改时通过外科方式更新DOM的代码。

TodoMVC的Svelte实现压缩后为3.6kb。为了进行比较,没有任何应用程序代码的React plus ReactDOM压缩后约为45kb。与使用交互式TodoMVC启动并运行Svelte一样,浏览器评估React所需的时间大约是其10倍。

  • Svelte简介:没有框架的框架

如何制作一个简单的Web应用程序

要创建一个新的svelte项目,我们可以从官方模板https://github.com/sveltejs/template开始

要在my-svelte-project目录中创建一个新项目,安装其依赖项,并启动服务器,您可以键入以下命令:

npx degit sveltejs/template my-svelte-project
cd my-svelte-project
npm install
npm run dev

通过访问URL http:// localhost:5000,您将看到hello-world网络应用程序。

在此示例中,我们将创建一个时钟组件,您可以从以下链接复制文件app.svelte的内容:https ://svelte.dev/examples#clock 。

编译为自定义元素(又称Web组件)

Svelte组件也可以使用customElement:true编译器选项编译为自定义元素(即Web组件)。您应该使用svelte:options元素为组件指定标签名称。

<svelte:options tag="my-element">

默认情况下,自定义元素使用访问器编译:true,这意味着任何道具都将作为DOM元素的属性公开。为了防止这种情况,请将accessors = {false}添加到svelte:options

要构建自定义元素,我们必须:

  • 将customElement:true添加到rollup.config.js文件中:
    plugins: [
        svelte({
            customElement: true,
  • 在App.svelte中添加
<svelte:options tag="svelte-clock">

如果您没有定义这个svelte:option,编译器将通过以下消息警告您

svelte plugin: No custom element 'tag' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. <svelte:options tag="my-thing"/>. To hide this warning, use <svelte:options tag={null}/
  • 运行“ npm运行构建”

在开发期间(npm run dev),将启用实时重载。这意味着您对自定义元素或HTML所做的任何更改都会立即反映在浏览器中。

一旦Web组件准备就绪,我们就可以运行“ npm run build”,它将在public / bundle.js文件中编译您的自定义元素的缩小版本,并且可以投入生产。
编译器将负责创建Shadow DOM,应用属性/属性以及定义自定义元素。

为了测试创建的Web组件,我们可以利用http服务器。
要安装,我们可以执行以下命令:

npm install http-server -g

然后,我们可以在公共目录中创建index.html,导入bundle.js并声明自定义元素“ svelte-clock”:

<!doctype html>
<html>
  <head>
    <title>This is the title of the webpage!</title>
    <script src="bundle.js"></script>
  </head>
  <body>
      <h1>Test Page</h1>
      <p>This is an example paragraph.</p>
      <svelte-clock/>
  </body>
</html>

执行以下命令,我们可以看到正在运行的组件:

> http-server -p 8080 -c-1 public/
Starting up http-server, serving public/
Available on:
  http://127.0.0.1:8080

Svelte Web组件:结论

性质

您的自定义元素接受的所有道具都会在编译时自动转换为元素属性。建议使用小写的属性名称,因为诸如camelCase或PascalCase之类的命名约定在HTML中不起作用。

为了测试,我们可以向自定义元素添加一个简单的属性。

<script>
    ...
    export let clocktitle = "Svelte Clock"
    ...
</script>
...
<h1>{clocktitle}</h1>
...

现在我们可以在index.html中设置值

<svelte-clock clocktitle="My Clock"></svelte-clock>

大事记

从包装为Web组件的Svelte 3内部发出的自定义事件不会像正常的DOM事件一样冒泡到Web组件本身(默认情况下,该自定义事件不会超出shadowDom的边界)并且无法在其中处理模板中的常规方式。

<svelte-clock custom-event="handler()">    

《如何在Svelte中创建Web组件》 不会从编译为自定义元素的组件中发出事件 #3119

《如何在Svelte中创建Web组件》

vogloblinsky  2019 6月26日发表评论

监听事件on:mycustomevent的本地Svelte语法不适用于由导出到自定义元素的Svelte组件调度的事件。

可能与此有关?https://github.com/sveltejs/svelte/blob/a0e0f0125aa554b3f79b0980922744ee11857069/src/runtime/internal/Component.ts#L162-L171

这是一个复制存储库:

https://github.com/vogloblinsky/svelte-3-wc-debug

svelte3-raw

仅使用Svelte语法的示例。内部组件调度自定义事件“消息”。应用程序组件使用on:message收听

有用 !

//Inner.svelte
<script>
    import { createEventDispatcher } from 'svelte';

    const dispatch = createEventDispatcher();

    function sayHello() {
        console.log('sayHello in child: ', 'Hello!');
        dispatch('message', {
            text: 'Hello!'
        });
    }
</script>

<button on:click={sayHello}>
    Click to say hello
</button>
//App.svelte
<script>
    import Inner from './Inner.svelte';

    function handleMessage(event) {
        console.log('handleMessage in parent: ', event.detail.text);
    }
</script>

<Inner on:message={handleMessage}/>

svelte3-wc

仅使用Svelte语法并将组件导出到Web组件的示例。内部组件调度自定义事件“消息”。应用程序组件使用on:message收听

相同的语法不起作用。

//Inner.svelte
<svelte:options tag="inner-btn"/>
<script>
    import { createEventDispatcher } from 'svelte';

    const dispatch = createEventDispatcher();

    function sayHello() {
        console.log('sayHello in child: ', 'Hello!');
        dispatch('message', {
            text: 'Hello!'
        });
    }
</script>

<button on:click={sayHello}>
    Click to say hello
</button>
//App.svelte
<svelte:options tag="my-app" />
<script>
    import Inner from './Inner.svelte';

    function handleMessage(event) {
        console.log('handleMessage in parent: ', event.detail.text);
    }
</script>

<inner-btn on:message={handleMessage}/>

Vanilla JS在public / index.html中工作正常

const button = document
                    .querySelector('my-app')
                    .shadowRoot.querySelector('inner-btn');

                button.$on('message', e => {
                    console.log('handleMessage in page');
                });

为了使其跨越shadowDom的边界,我们必须创建一个自定义事件,如v2文档中提到的svelte。可以使用CustomEvent api在Svelte组件中创建自定义事件。定义自定义事件后,可以通过响应组件中的更改而调用this.dispatchEvent(event)来调度该事件。
自定义事件不能响应生命周期方法而分派。例如,如果您尝试在onMount生命周期方法中调度自定义事件,则不会调度事件。

要添加事件,我们可以添加一个按钮:

<button on:click="{dispatchSavedDateEvent}">Save Date</button>

单击时,我们可以发出一个自定义事件:

function dispatchSavedDateEvent(e) {
   console.log("[dispatchSecondIsElapsedEvent] time: ", time);
   // 1. Create the custom event.
   const event = new CustomEvent("savedData", {
     detail: time,
     bubbles: true,
     cancelable: true,
     composed: true // makes the event jump shadow DOM boundary
   });

   // 2. Dispatch the custom event.
   this.dispatchEvent(event);
 }

Event接口的只读composition属性返回一个布尔值,该布尔值指示事件是否将跨阴影DOM边界传播到标准DOM中。

另一种方法是利用createEventDispatcher

import { createEventDispatcher } from 'svelte'; 
const dispatch = createEventDispatcher();
...
dispatch('second', {
       text: '10 seconds elapsed!'
     });
...

在index.html中,我们必须通过以下方式预订新事件:

document.querySelector('svelte-clock')
    .$on('second', (e) => { console.log("[index.html][second]", e)})

进口货

要导入Svelte组件,我们必须使用标签声明每个嵌套元素

<svelte:option tag="my-nested-element”>

将子组件声明为自定义元素,这些元素也可供消费者使用。
嵌套元素使用与父元素相同的Shadow DOM,无法将嵌套元素的Shadow DOM模式设置为“ closed”。

使用Svelte.js创建Web组件的主要优点是最终组件的尺寸非常小。在我们的小示例中,bundle.js中打包的Web组件仅重7170字节,与其他框架创建的Web组件相比,这些尺寸使我们的Web组件更小,更快速地被浏览器执行了数十倍。

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注