为编辑器制作一个网络组件
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
语法而不是创建脚本标记,但这些库不支持该语法。
以下是关键的移动部分:
- 代表自定义元素逻辑的 ES6 Class
- 您的 HTML 已放置在
<template>
标签中,该标签用于保存自定义元素的 DOM 元素
- 此语句使自定义元素可供使用:
customElements.define('my-editor', MyEditor);
- 将
<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>
我想制作一个网络组件标签,其中包含一个具有一些附加功能的编辑器。我现在正在使用 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
语法而不是创建脚本标记,但这些库不支持该语法。
以下是关键的移动部分:
- 代表自定义元素逻辑的 ES6 Class
- 您的 HTML 已放置在
<template>
标签中,该标签用于保存自定义元素的 DOM 元素 - 此语句使自定义元素可供使用:
customElements.define('my-editor', MyEditor);
- 将
<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>