svelte+vite开发web组件

88 阅读3分钟

Svelte 是用于构建应用程序的绝佳框架,Svelte 组件可以独立于具体的应用程序,因此可以在不同的项目和环境中进行重用。你可以将构建好的组件发布到 npm 上,供其他开发人员使用。这种可重用性提高了开发效率,减少了重复编写相似代码的工作。

在这篇文章中,我们将学习如何创建一个 Svelte 组件,将其导出为自定义元素,并使用它。

开发

让我们开始一个新项目来构建我们的组件。

npm create vite@latest

√ Project name: ... webcomponents
√ Select a framework: » Svelte
√ Select a variant: » TypeScript

cd webcomponents
npm install
npm run dev
  1. 删除 src/App.svelte 文件。
  2. 修改位于 src 目录下的 main.ts 文件
// src/main.ts
export * from './lib/webcomponents.svelte'
  1. src/lib目录下新建一个click.svelte文件。

注意:要想实现自定义组件需在文件顶部添加以下标签 <svelte:options tag="my-button" />详细介绍

// src/lib/click.svelte
<!--这一行是添加你的自定义元素标识-->
<svelte:options tag="my-button" />

<button on:click={increment}>
  Clicks: {count}
</button>

<script lang="ts">
  let count: number = 0
  const increment = () => {
    count += 1
  }
</script>

<style>
  button {
    font-family: inherit;
    font-size: inherit;
    padding: 1em 2em;
    color: #ff3e00;
    background-color: rgba(255, 62, 0, 0.1);
    border-radius: 2em;
    border: 2px solid rgba(255, 62, 0, 0);
    outline: none;
    width: 200px;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
  }

  button:focus {
    border: 2px solid #ff3e00;
  }

  button:active {
    background-color: rgba(255, 62, 0, 0.2);
  }
</style>
  1. index.html文件内我们可以引入以上自定义的<my-button></my-button>标签
<!-- index.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Svelte + TS + Vite App</title>
  </head>
  <body>
    <my-button></my-button>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>
  1. 删除 <div id="app">, 因为我们不会使用它。然后,将自定义元素标签添加到网站正文中。
  2. 让我们运行我们的应用程序 npm run dev,您应该能够看到我们的 Web 组件在运行。 image.png

转到 vite.config.js 并更新它,如下所示:

import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    svelte({
      compilerOptions: {
        customElement: true,
      },
    }),
  ],
});

构建

运行npm run build打包程序

构建多个自定义组件

src/lib目录下创建time.svelte文件,代码如下

<svelte:options tag="my-time" />

<script lang="ts">
  import { onMount, onDestroy } from 'svelte';
  let date = new Date().toLocaleTimeString();
  let interval;

  onMount(() => {
    interval = setInterval(() => {
      date = new Date().toLocaleTimeString();
    }, 1000);
  });

  onDestroy(() => {
    clearInterval(interval);
  });
</script>

<span>{date || ''}</span>

<style>
  span {
    font-family: inherit;
    font-size: inherit;
    padding: 1em 2em;
    color: #ff3e00;
    background-color: rgba(255, 62, 0, 0.1);
    border-radius: 2em;
    border: 2px solid rgba(255, 62, 0, 0);
    outline: none;
    width: 200px;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
  }

  span:active {
    background-color: rgba(255, 62, 0, 0.2);
  }
</style>

更新 main.ts 文件

export * from './lib/click.svelte'
export * from './lib/time.svelte'

index.html里面添加<my-time></my-time>

image.png

注意事项

我们的组件需要提供给第三方使用,所以禁用html输出。

使用者可用通过不同的引入方式使用组件

完整代码如下:

// vite.config.ts 
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import pkg from './package.json';

const footer = `
if(typeof window !== 'undefined') {
  window._Dry_VERSION_ = '${pkg.version}'
}`;

// https://vitejs.dev/config/
export default defineConfig({
  base: './',
  build: {
    outDir: 'components',
    assetsDir: 'static',
    rollupOptions: {
      input: {
        main: 'src/main.ts',
      },
      output: [
        {
          dir: 'components',
          format: 'umd',
          name: '...',
          entryFileNames: pkg.name + '.mjs',
          footer,
        },
        {
          dir: 'components',
          format: 'cjs',
          name: '...',
          entryFileNames: pkg.name + '.js',
          footer,
        },
      ],
    },
  },
  plugins: [
    svelte({
      compilerOptions: {
        customElement: true,
      },
    }),
  ],
});

组件传参

定义props

src/lib/click.svelte文件内定义props 参数如下

<svelte:options
  customElement={{
    tag: 'my-click',
    shadow: 'none',
    props: {
      name: { reflect: true, type: 'String', attribute: 'element-index' },
    },
  }}
/>

然后确定需要传递的参数

export let value = { name: 'test' };

html内传参

<body>
  <my-click></my-click>
  <my-time></my-time>

  <!-- <div id="app"></div> -->
  <script type="module" src="/src/main.ts"></script>
</body>
<script>
  let myClick = document.getElementsByTagName('my-click')
  console.log(myClick);
  let data = 0
  setInterval(() => {
    data++;
    console.log(data);
    myClick[0].value = { name: '测试' + data };
    // myClick.setAttribute("value", "234")
  }, 1000);


</script>

image.png