V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
GrapeCityChina
V2EX  ›  推广

Svelte 入门——Web Components 实现跨框架组件复用

  •  
  •   GrapeCityChina · 2021-11-24 10:11:40 +08:00 · 1158 次点击
    这是一个创建于 874 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Svelte 是构建 Web 应用程序的一种新方法,推出后一直不温不火,没有继 Angular 、React 和 VUE 成为第四大框架,但也没有失去热度,无人问津。造成这种情况很重要的一个原因是,Svelte 的核心思想在于 [通过静态编译减少框架运行时的代码量] ,它可以像 React 和 VUE 一样开发,但却没有虚拟 DOM 。,使它可以 Svelte 可以将代码编译为体积小、不依赖于框架的 JS 代码。

    看起来满满优点,但因为过于灵活,导致大家无法写出高度一致的业务代码,以上优点并没有在实际的大项目中得到很好的体现。

    Svelte 这款框架并不完美,却又没有在残酷的市场竞争中死掉,是因为它拥有一本特殊秘籍,一些使它成为其他框架无法替代的一员的功能。。

    而对于 Svelte 来说,这本秘籍的名字就叫做——Web Components 。

    在多团队协同完成的大项目中,各个团队可能使用不同的框架版本,甚至不同的框架,这让不同项目之间的组件复用变得困难。"write one ,run anywhere"就是一句空话。这种情况下 Svelte 就变成了沟通跨越框架鸿沟的桥梁,使用 Svelte 开发的无框架依赖的 Web Components ,可以在各个框架间复用。同时,Svelte 的开发方式也不像写 pure js 那样繁琐。

    下面以 SpreadJS 集成为例,介绍如何用 Svelte 开发一款 spread-sheets Web Component 供其他页面复用。

    1. 创建 Svelte template 工程。 svelte 官方提供了 template 工程,只要 clone 或者下载项目即可。

    https://github.com/sveltejs/component-template

    npx degit sveltejs/component-template my-new-component
    cd my-new-component
    npm install # or yarn
    
    
    1. 修改 rollup.config.js ,添加 customElement: true 配置,输出为 web component 组件。

    添加后的 rollup.config.js 如下。

    import svelte from 'rollup-plugin-svelte';
    import resolve from '@rollup/plugin-node-resolve';
    import pkg from './package.json';
    
    const name = pkg.name
            .replace(/^(@\S+\/)?(svelte-)?(\S+)/, '$3')
            .replace(/^\w/, m => m.toUpperCase())
            .replace(/-\w/g, m => m[1].toUpperCase());
    
    export default {
            input: 'src/index.js',
            output: [
                    { file: pkg.module, 'format': 'es' },
                    { file: pkg.main, 'format': 'umd', name }
            ],
            plugins: [
                    svelte({
                            customElement: true,
                    }),
                    resolve()
            ],
    };
    
    
    1. 更新 src/Component.svelte ,创建 spread-sheets 组件。
    <svelte:options tag="spread-sheets" />
    <script>
        import { createEventDispatcher, onMount } from 'svelte';
        // Event handling
        const dispatch = createEventDispatcher();
        export let value ="";
        $: valueChanged(value);
        function valueChanged(newValue) {
          console.log("value changed", newValue);
          if(spread){
            let sheet = spread.getActiveSheet();
            sheet.setValue(0, 0, value);
          }
        }
    
        let spreadHost;
        let spread;
        function dispatchEvent(name, e) {
          // dispatch(name, e);
          const event = new CustomEvent(name, {
            detail: e,
            bubbles: true,
            cancelable: true,
            composed: true, // this line allows the event to leave the Shadow DOM
          });
          // console.log(event)
          spreadHost.dispatchEvent(event);
        }
          onMount(() => {
              spread = new GC.Spread.Sheets.Workbook(spreadHost);
              let sheet = spread.getActiveSheet();
              sheet.setValue(0, 0, value);
              spread.bind(GC.Spread.Sheets.Events.ValueChanged, function(s, e){
                e.evnetName = "ValueChanged";
                dispatchEvent("changed", e);
              });
              spread.bind(GC.Spread.Sheets.Events.RangeChanged, function(s, e){
                e.evnetName = "RangeChanged";
                dispatchEvent("changed", e);
              });
          });
    
    
    
      </script>
      <style>
          
      </style>
      <div bind:this={ spreadHost} style="width: 100%; height:100%"></div>
    
    

    这样我们的自定义组件就创建好了,只需要调用 npm run build ,就能编译出 spread-sheets 组件了。

    1. 在页面引用组件。 创建 index.html 页面,并引用编译好的 js 文件。同时引入 spreadjs 相关资源。 直接使用 spread-sheets 标签添加 SpreadJS 。
    <!doctype html>
    <html lang="en">
      <head>
        <meta name="spreadjs culture" content="zh-cn" />
        <meta charset="utf-8" />
        <title>My Counter</title>
        <base href="/">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    
        <link rel="stylesheet" type="text/css" href="https://demo.grapecity.com.cn/spreadjs/SpreadJSTutorial/zh/purejs/node_modules/@grapecity/spread-sheets/styles/gc.spread.sheets.excel2013white.css">
      </head>
      <body>
        <!-- <spread-sheets-designer></spread-sheets-designer> -->
        <button onclick="getJSON()">GetJSON</button>
        <spread-sheets value="123" style="display:block; width: 80%; height: 400px;"></spread-sheets>
    
    
        <script src="https://demo.grapecity.com.cn/SpreadJS/WebDesigner/lib/spreadjs/scripts/gc.spread.sheets.all.14.1.3.min.js" type="text/javascript"></script>
    
        <script type="text/javascript" src="/dist/index.js"></script>
        <script type="text/javascript">
    
          document.querySelector("spread-sheets").addEventListener("changed", function(){
            console.log(arguments)
          })
    
          window.onload = function(){
            document.querySelector("spread-sheets").setAttribute("value", "234");
          }
    
        </script>
      </body>
    </html>
    
    

    添加后效果如下图。

    总结

    虽然看起来 Web Component 完美解决了组件之间的复用问题,但是用 Svelte 开发的 Web Component 也存在一些限制:比如,只能传递 string 属性;绑定的 attribute 是单向绑定,想要获取组件内部更新值,需要绑定 event 获取。

    如果大家对 Svelte 有更多兴趣,欢迎留言交流~

    1 条回复    2021-11-24 14:42:34 +08:00
    yamedie
        1
    yamedie  
       2021-11-24 14:42:34 +08:00
    可以,确实是推广,web component 里去 new 一个 spreadjs 出来,拐这个弯有何用。。。(为了秀一下葡萄城和无授权

    我也用 svelte 写过一个表格 web 组件,npm 地址是 https://www.npmjs.com/package/web-spreadsheet

    没有 canvas 和虚拟滚动条,就硬创建 dom ,几百行的时候还能用,超过 1k 行性能直接炸裂。。。

    后来发现有 HandsonTable 这个东西,我造这轮子有何用。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1134 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 22:57 · PVG 06:57 · LAX 15:57 · JFK 18:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.