为编辑器制作一个网络组件

Make a web componenet for an editor

我想制作一个网络组件标签,其中包含一个具有一些附加功能的编辑器。我现在正在使用 ACE-JSON 编辑器。

主要代码是这个,我还有一些其他的js文件。

<!DOCTYPE HTML>
<html>

<head>
  <title>JSONEditor</title>
  <meta charset="utf-8">
  <link href="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/5.32.5/jsoneditor.css" rel="stylesheet" type="text/css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/5.32.5/jsoneditor.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2014-11-29/FileSaver.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
  <script src="app.js"></script>
  <!-- <script src="worker.js"></script> -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">

  <style>
    html,
    body {
      font: 11pt sans-serif;
    }

    #jsoneditor {
      width: 700px;
      height: 600px;
    }

    #paste,
    #link,
    #file {
      margin-top: 25px;
      align-content: center;

    }
  </style>
</head>

<body>
  <div class="container-fluid">
    <h1 align="center">Load and save JSON documents</h1>
    <br><br><br>
    <div class="row">
      <div class="col">
        <div id="jsoneditor"></div>
      </div>
      <div class="col col-centered">
        <div class="row">
          <div class="col">
            <select id="test" name="form_select" onchange="showDiv(this)">
              <option value="paste">paste json</option>
              <option value="file">Upload file</option>
              <option value="link">use link</option>
            </select>
          </div>
          <div class="col">
            <p>
              Save a JSON document: <input type="button" id="saveDocument" value="Save" />
            </p>
          </div>
        </div>
        <div class="row">
          <div class="col">
            <div id="file" style="display: none;" class="col-sm col-centered">
              Load a JSON document: <input type="file" id="loadDocument" value="Load" />
              <button class="button" onclick="readFile()">LOAD JSON</button>
            </div>
            <div id="paste" style="display: none;" class="col-sm col-centered">
              <h3>Paste JSON data </h3>
              <textarea id="myText" rows="4" cols="50"></textarea>
              <button class="button" onclick="loadText()">LOAD JSON</button>
            </div>
            <div id="link" style="display: none;" class="col-sm col-centered">
              <h3>URL</h3>
              <input type="text" id="url">
              <button class="button" onclick="urlOnclick()">LOAD JSON</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>

<script>
  var options = {
    mode: 'tree',
    modes: ['code', 'form', 'text', 'tree', 'view'], // allowed modes
    onError: function (err) {
      alert(err.toString());
    },
    onModeChange: function (newMode, oldMode) {
      console.log('Mode switched from', oldMode, 'to', newMode);
    }
  };
  // create the editor
  var editor = new JSONEditor(document.getElementById('jsoneditor'), options);

  // Save a JSON document
  document.getElementById('saveDocument').onclick = function () {
    // Save Dialog
    fname = window.prompt("Save as...");

    // Check json extension in file name
    if (fname.indexOf(".") == -1) {
      fname = fname + ".json";
    } else {
      if (fname.split('.').pop().toLowerCase() == "json") {
        // Nothing to do
      } else {
        fname = fname.split('.')[0] + ".json";
      }
    }
    var blob = new Blob([editor.getText()], { type: 'application/json;charset=utf-8' });
    saveAs(blob, fname);
  };
</script>

</html>

我如何将其包装在网络组件中? 我用 JS 尝试过,但大多数教程都给出了一个简单标签的小例子。大多数网站都指向聚合物,但我没有找到任何关于我想做什么的适当参考。 请您指导我或提供一些参考。

第三方库通常不是为与 Web 组件一起使用而设计的。

您要 运行 解决的问题是 jQuery 和 jQuery 插件的使用。创建 Web 组件时,您是在 shadowDOM 中的 #shadowRoot 组件中创建 #document-fragment。这意味着我们用于 select 元素 (document.getElementById(...)) 的标准 DOM 语句不适用于 shadowDOM 中的 select 元素。那是因为 shadowDOM 与根文档是隔离的。这就是为什么你只找到简单标签的例子。

JSONEditor,例如,uses document.createElement() extensively.

我已将您的 HTML/JS 转换为 Web 组件 ,由于上述原因,该组件无法正常工作。这至少会向您展示如何处理更复杂的示例。

正如您在下面的示例中看到的,外部脚本和样式表很容易加载到组件中。可以使用模块 import 语法而不是创建脚本标记,但这些库不支持该语法。

以下是关键的移动部分:

  1. 代表自定义元素逻辑的 ES6 Class
  2. 您的 HTML 已放置在 <template> 标签中,该标签用于保存自定义元素的 DOM 元素
  3. 此语句使自定义元素可供使用:
    • customElements.define('my-editor', MyEditor);
  4. <my-editor></my-editor>放入HTML文件

详见源码注释

class MyEditor extends HTMLElement {
  constructor () {
    super();
    this.requiredScripts = [
      'https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js',
      'https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js',
      'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js',
      'https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/5.32.5/jsoneditor.js',
      'https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2014-11-29/FileSaver.min.js',
    ];
    // Grab a reference to the custom element
    let template = document.getElementById('my-custom-editor');
    // Get the #document-fragment
    let templateContent = template.content;
    // Place the template from the Web Component in to the active DOM
    this.attachShadow({ mode: 'open' }).appendChild(templateContent.cloneNode(true));
  }
  // lifecycle hook that fires when custom element is placed into DOM
  connectedCallback () {
    // load required external resources
    this.loadScripts(0);
  }
  
  loadScripts (idx) {
    const tag = document.createElement('script');
    tag.src = this.requiredScripts[idx];
    tag.onload = () => {
      if (idx < this.requiredScripts.length - 1) {
        // when a script has finished, go get the next one
        this.loadScripts(++idx);
      } else {
        // Once all the script files are loaded, initialize the working parts of the component
        this.initEditor();
      }
    }
    tag.onload.bind(this);
    document.head.appendChild(tag);
  }
  
  initEditor () {
    // Need a reference to the #document-fragment
    // Every instance of "document" in this method has been replaced with "component"
    const component = document.getElementById('my-custom-editor').content;
    const options = {
      mode: 'tree',
      modes: ['code', 'form', 'text', 'tree', 'view'], // allowed modes
      onError: function (err) {
        alert(err.toString());
      },
      onModeChange: function (newMode, oldMode) {
        console.log('Mode switched from', oldMode, 'to', newMode);
      }
    };
    // create the editor IN THE compoent (rathar than the DOM)
    var editor = new JSONEditor(component.getElementById('jsoneditor'), options);
    component.getElementById('saveDocument').onclick = function () {
      fname = window.prompt("Save as...");
      if (fname.indexOf(".") == -1) {
        fname = fname + ".json";
      } else {
        if (fname.split('.').pop().toLowerCase() == "json") {
        } else {
          fname = fname.split('.')[0] + ".json";
        }
      }
      var blob = new Blob([editor.getText()], {
        type: 'application/json;charset=utf-8'
      });
      saveAs(blob, fname);
    };
    
  }
}

customElements.define('my-editor', MyEditor);
html,
body {
    font: 11pt sans-serif;
}
<!DOCTYPE HTML>
<html>

<head>
    <title>JSONEditor</title>
    <meta charset="utf-8">
    <link href="styles.css" rel="stylesheet">
    <script defer src="lib/MyEditor.js"></script>
    <!-- <script src="app.js"></script> -->
    <!-- <script src="worker.js"></script> -->

</head>

<body>

<my-editor></my-editor>


<template id="my-custom-editor">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/5.32.5/jsoneditor.css" rel="stylesheet" type="text/css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">

    <style>
        #jsoneditor {
            width: 700px;
            height: 600px;
        }

        #paste,
        #link,
        #file {
            margin-top: 25px;
            align-content: center;
        }
    </style>
    <div class="container-fluid">
        <h1 align="center">Load and save JSON documents</h1>
        <br><br><br>
        <div class="row">
            <div class="col">
                <div id="jsoneditor"></div>
            </div>
            <div class="col col-centered">
                <div class="row">
                    <div class="col">
                        <select id="test" name="form_select" onchange="showDiv(this)">
                            <option value="paste">paste json</option>
                            <option value="file">Upload file</option>
                            <option value="link">use link</option>
                        </select>
                    </div>
                    <div class="col">
                        <p>
                            Save a JSON document: <input type="button" id="saveDocument" value="Save"/>
                        </p>
                    </div>
                </div>
                <div class="row">
                    <div class="col">
                        <div id="file" style="display: none;" class="col-sm col-centered">
                            Load a JSON document: <input type="file" id="loadDocument" value="Load"/>
                            <button class="button" onclick="readFile()">LOAD JSON</button>
                        </div>
                        <div id="paste" style="display: none;" class="col-sm col-centered">
                            <h3>Paste JSON data </h3>
                            <textarea id="myText" rows="4" cols="50"></textarea>
                            <button class="button" onclick="loadText()">LOAD JSON</button>
                        </div>
                        <div id="link" style="display: none;" class="col-sm col-centered">
                            <h3>URL</h3>
                            <input type="text" id="url">
                            <button class="button" onclick="urlOnclick()">LOAD JSON</button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>
</body>
</html>