珠海微信网站宝钢建设工程有限公司网站
web/
2025/9/29 18:29:43/
文章来源:
珠海微信网站,宝钢建设工程有限公司网站,广东工厂网站建设,有限责任公司与有限公司的区别为了提供一致的编辑体验#xff0c;您需要一致的数据和可预测的行为。不幸的是#xff0c;DOM缺乏这两个特性。现代编辑器的解决方案是维护自己的文档模型来表示它们的内容。对于Quill来说#xff0c;Parchment就是这样的解决方案。它在自己的代码库中组织#xff0c;并拥有…
为了提供一致的编辑体验您需要一致的数据和可预测的行为。不幸的是DOM缺乏这两个特性。现代编辑器的解决方案是维护自己的文档模型来表示它们的内容。对于Quill来说Parchment就是这样的解决方案。它在自己的代码库中组织并拥有自己的API层。通过Parchment您可以定制Quill识别的内容和格式或者添加全新的内容和格式。 在本指南中我们将使用Parchment和Quill提供的基本构建块来复制媒体上的编辑器。我们将从没有任何主题、额外模块或格式的Quill的骨架开始。在这个基本层面上Quill只理解纯文本。但通过本指南的结尾链接、视频甚至推文都将被理解。 基础工作 让我们从甚至不使用Quill开始只用一个textarea和一个按钮连接到一个虚拟事件监听器。我们将在整个指南中为了方便使用jQuery但Quill或Parchment并不依赖于此。我们还将添加一些基本样式借助Google Fonts和Font Awesome。这些与Quill或Parchment无关所以我们将快速通过。 index.html link href/styles.css relstylesheetdiv idtooltip-controlsbutton idbold-buttoni classfa fa-bold/i/buttonbutton iditalic-buttoni classfa fa-italic/i/buttonbutton idlink-buttoni classfa fa-link/i/buttonbutton idblockquote-buttoni classfa fa-quote-right/i/buttonbutton idheader-1-buttoni classfa fa-headersub1/sub/i/buttonbutton idheader-2-buttoni classfa fa-headersub2/sub/i/button
/div
div idsidebar-controlsbutton idimage-buttoni classfa fa-camera/i/buttonbutton idvideo-buttoni classfa fa-play/i/buttonbutton idtweet-buttoni classfa fa-twitter/i/buttonbutton iddivider-buttoni classfa fa-minus/i/button
/divtextarea ideditorTell your story.../textareascript typemodule src/index.js/script
styles.css #editor {display: block;font-family: Open Sans, Helvetica, sans-serif;font-size: 1.2em;height: 180px;margin: 0 auto;width: 450px;
}#tooltip-controls, #sidebar-controls {text-align: center;
}button {background: transparent;border: none;cursor: pointer;display: inline-block;font-size: 18px;padding: 0;height: 32px;width: 32px;text-align: center;
}
button:active, button:focus {outline: none;
} index.js document.querySelectorAll(button).forEach((button) {button.addEventListener(click, () {alert(Click!);});
}); 添加Quill核心 接下来我们将用没有主题、格式和额外模块的Quill核心替换textarea。打开您的开发者控制台在您输入编辑器时检查演示。您可以看到Parchment文档的基本构建块在工作。 index.html link hrefhttps://cdn.jsdelivr.net/npm/quill2.0.0-rc.4/dist/quill.core.css relstylesheet /
script srchttps://cdn.jsdelivr.net/npm/quill2.0.0-rc.4/dist/quill.core.js/scriptlink href/styles.css relstylesheetdiv idtooltip-controlsbutton idbold-buttoni classfa fa-bold/i/buttonbutton iditalic-buttoni classfa fa-italic/i/buttonbutton idlink-buttoni classfa fa-link/i/buttonbutton idblockquote-buttoni classfa fa-quote-right/i/buttonbutton idheader-1-buttoni classfa fa-headersub1/sub/i/buttonbutton idheader-2-buttoni classfa fa-headersub2/sub/i/button
/div
div idsidebar-controlsbutton idimage-buttoni classfa fa-camera/i/buttonbutton idvideo-buttoni classfa fa-play/i/buttonbutton idtweet-buttoni classfa fa-twitter/i/buttonbutton iddivider-buttoni classfa fa-minus/i/button
/divdiv ideditorTell your story.../divscript typemodule src/index.js/script styles.css #editor {border: 1px solid #ccc;font-family: Open Sans, Helvetica, sans-serif;font-size: 1.2em;height: 180px;margin: 0 auto;width: 450px;
}#tooltip-controls, #sidebar-controls {text-align: center;
}button {background: transparent;border: none;cursor: pointer;display: inline-block;font-size: 18px;padding: 0;height: 32px;width: 32px;text-align: center;
}
button:active, button:focus {outline: none;
} index.js document.querySelectorAll(button).forEach((button) {button.addEventListener(click, () {alert(Click!);});
});const quill new Quill(#editor); 与DOM类似Parchment文档是一个树形结构。它的节点称为Blots是对DOM节点的抽象。对于我们来说已经定义了一些基本的BlotsScroll滚动、Block块、Inline内联、Text文本和Break断点。当您输入时Text blot会与对应的DOM Text节点同步按下回车键则通过创建一个新的Block blot来处理。在Parchment中能够拥有子节点的Blots至少必须有一个子节点因此空的Blocks会填充一个Break blot。这使得处理叶子节点变得简单且可预测。所有这些都组织在一个根Scroll blot下。 在这个阶段您无法仅通过打字来观察Inline blot因为它不会对文档产生有意义的结构或格式。一个有效的Quill文档必须是规范且紧凑的。能够表示给定文档的只有一个有效的DOM树而这个DOM树包含最小数量的节点。 由于pspanText/span/p和pText/p表示相同的内容前者是无效的解包span是Quill优化过程的一部分。类似地一旦我们添加了格式pemTe/ememst/em/p和pememTest/em/em/p也是无效的因为它们不是最紧凑的表示形式。 由于这些限制Quill不能支持任意的DOM树和HTML更改。但正如我们将看到的这种结构提供的一致性和可预测性使我们能够轻松构建丰富的编辑体验。 基本格式 我们之前提到内联Inline不贡献格式。这是基本情况的例外而不是规则为基本的内联类而设。基本的块级BlockBlot与块级元素的工作方式相同。 为了实现加粗和斜体我们只需要从Inline继承设置blotName和tagName并将其注册到Quill。有关继承和静态方法和变量签名的完整参考请查看Parchment。 const Inline Quill.import(blots/inline);class BoldBlot extends Inline {static blotName bold;static tagName strong;
}class ItalicBlot extends Inline {static blotName italic;static tagName em;
}Quill.register(BoldBlot);
Quill.register(ItalicBlot); 我们在这里遵循Medium的示例使用strong和em标签但您也可以使用b和i标签。Blot的名称将被用作Quill的格式名称。通过注册我们的Blot我们现在可以使用Quill的完整API在我们的新格式上
在Quill富文本编辑器中Blot是构建编辑器内容的基本单位。每个Blot代表文档中的一个可编辑元素比如一个段落、一个图片或一个文本格式例如加粗或斜体。Quill利用一个富文本模型Parchment来定义和管理这些Blots它们共同构成了编辑器的文档模型。 Blot名称和格式名称 当定义一个自定义Blot时该Blot的名称非常重要因为它直接关联到Quill的格式名称。这意味着 Blot名称的定义在创建一个自定义Blot时你需要为它指定一个唯一的名称。这个名称在Quill编辑器中用于引用该格式。作为格式名称使用在编辑器中应用格式时使用的格式名称实际上就是定义Blot时所指定的名称。例如如果你创建了一个自定义Blot命名为myCustomFormat那么在通过API应用这个格式到选中的文本时将使用这个名称quill.format(myCustomFormat, true);
这条命令会应用myCustomFormat格式到当前选中的文本或插入点。在实际效果中这意味着Quill会创建一个MyCustomBlot的实例并将其插入到文档中从而将选中的文本包裹或标记为myCustomFormat格式。 Quill.register(BoldBlot);
Quill.register(ItalicBlot);const quill new Quill(#editor);quill.insertText(0, Test, { bold: true });
quill.formatText(0, 4, italic, true);
// 如果我们将斜体Blot命名为myitalic我们将调用
// quill.formatText(0, 4, myitalic, true); 让我们摆脱我们的虚拟按钮处理程序并将加粗和斜体按钮连接到Quill的format()。为了简单起见我们将硬编码为true始终添加格式。在您的应用程序中您可以使用getFormat()来检索任意范围的当前格式以决定是否添加或删除格式。工具栏模块为Quill实现了这一点我们将在这里重新实现它。 链接 链接稍微复杂一些因为我们存储链接url需要不仅仅是一个布尔值。这在两个方面影响我们的链接Blot创建和格式检索。我们将url表示为字符串值但我们也可以以其他方式表示例如具有url键的对象允许设置其他键/值对来定义链接。我们将在稍后使用图像演示这一点。 class LinkBlot extends Inline {static blotName link;static tagName a;static create(value) {const node super.create();// 如果需要对url值进行消毒node.setAttribute(href, value);// 可以设置其他非格式相关属性// 这些对Parchment是不可见的所以必须是静态的node.setAttribute(target, _blank);return node;}static formats(node) {// 我们只会被调用使用已经// 确定为链接Blot的节点所以我们// 不需要检查自己return node.getAttribute(href);}
}Quill.register(LinkBlot); 现在我们可以将我们的链接按钮连接到一个花哨的提示再次为了保持简单然后传递给Quill的format()。 引用和标题 引用Blockquotes的实现方式与加粗Blot相同只不过我们将从块级Block基础Blot继承。虽然内联InlineBlot可以嵌套但块级Blot不能。当应用于相同的文本范围时块级Blot不会包裹而是相互替换。 const Block Quill.import(blots/block);class BlockquoteBlot extends Block {static blotName blockquote;static tagName blockquote;
} 标题的实现方式完全相同只有一个区别它可以由多个DOM元素表示。格式的值默认成为tagName而不仅仅是true。我们可以通过扩展formats()来自定义这一点就像我们对链接所做的那样。 class HeaderBlot extends Block {static blotName header;// Medium只支持两个标题大小所以我们只演示两个// 但我们很容易就在这个数组中添加更多的标签static tagName [H1, H2];static formats(node) {return HeaderBlot.tagName.indexOf(node.tagName) 1;}
} 让我们将这些新的Blot连接到它们各自的按钮并为blockquote标签添加一些CSS。 分隔线 现在让我们实现我们的第一个叶子Blot。虽然我们之前的Blot示例贡献了格式formatting并实现了format()但叶子Blot贡献了内容并实现了value()。叶子Blot可以是文本或嵌入EmbedBlot所以我们的章节分隔线将是一个嵌入。一旦创建嵌入Blot的值就是不可变的需要删除和重新插入来改变该位置的内容。 我们的方法与之前类似只不过我们从块级嵌入BlockEmbed继承。嵌入Embed也存在于blots/embed下但那是为内联级Blot设计的。我们希望对分隔线使用块级实现。 const BlockEmbed Quill.import(blots/block/embed);class DividerBlot extends BlockEmbed {static blotName divider;static tagName hr;
} 我们的点击处理程序调用insertEmbed()它不像format()那样方便地确定、保存和恢复用户选择所以我们不得不做更多的工作来自己保留选择。此外当我们尝试在块中间插入一个块级嵌入时Quill会为我们分割块。为了使这种行为更清晰我们将通过在插入分隔线之前插入一个新行来明确地分割块。 index.html
link hrefhttps://cdn.jsdelivr.net/npm/quill2.0.0-rc.4/dist/quill.core.css relstylesheet /
script srchttps://cdn.jsdelivr.net/npm/quill2.0.0-rc.4/dist/quill.core.js/scriptlink href/styles.css relstylesheetdiv idtooltip-controlsbutton idbold-buttoni classfa fa-bold/i/buttonbutton iditalic-buttoni classfa fa-italic/i/buttonbutton idlink-buttoni classfa fa-link/i/buttonbutton idblockquote-buttoni classfa fa-quote-right/i/buttonbutton idheader-1-buttoni classfa fa-headersub1/sub/i/buttonbutton idheader-2-buttoni classfa fa-headersub2/sub/i/button
/div
div idsidebar-controlsbutton idimage-buttoni classfa fa-camera/i/buttonbutton idvideo-buttoni classfa fa-play/i/buttonbutton idtweet-buttoni classfa fa-twitter/i/buttonbutton iddivider-buttoni classfa fa-minus/i/button
/divdiv ideditorTell your story.../divscript typemodule src/index.js/script dividerBlot.js const BlockEmbed Quill.import(blots/block/embed);class DividerBlot extends BlockEmbed {static blotName divider;static tagName hr;
}Quill.register(DividerBlot); index.js import ./formats/boldBlot.js;
import ./formats/italicBlot.js;
import ./formats/linkBlot.js;
import ./formats/blockquoteBlot.js;
import ./formats/headerBlot.js;
import ./formats/dividerBlot.js;const onClick (selector, callback) {document.querySelector(selector).addEventListener(click, callback);
};onClick(#bold-button, () {quill.format(bold, true);
});onClick(#italic-button, () {quill.format(italic, true);
});onClick(#link-button, () {const value prompt(Enter link URL);quill.format(link, value);
});onClick(#blockquote-button, () {quill.format(blockquote, true);
});onClick(#header-1-button, () {quill.format(header, 1);
});onClick(#header-2-button, () {quill.format(header, 2);
});onClick(#divider-button, () {const range quill.getSelection(true);quill.insertText(range.index, \n, Quill.sources.USER);quill.insertEmbed(range.index 1, divider, true, Quill.sources.USER);quill.setSelection(range.index 2, Quill.sources.SILENT);
});const quill new Quill(#editor); 图片 图片可以使用我们在构建链接和分隔线Blot时学到的知识添加。我们将使用一个对象来表示值以展示这种支持。我们插入图片的按钮处理程序将使用一个静态值因此我们不会被与Parchment无关的提示UI代码分散注意力Parchment是本指南的重点。 const BlockEmbed Quill.import(blots/block/embed);class ImageBlot extends BlockEmbed {static blotName image;static tagName img;static create(value) {const node super.create();node.setAttribute(alt, value.alt);node.setAttribute(src, value.url);return node;}static value(node) {return {alt: node.getAttribute(alt),url: node.getAttribute(src)};}
}
Quill.register(ImageBlot); button idimage-buttoni classfa fa-camera/i/buttondiv ideditorTell your story.../divscriptonClick(#image-button, () {const range quill.getSelection(true);quill.insertText(range.index, \n, Quill.sources.USER);quill.insertEmbed(range.index 1, image, {alt: Quill Cloud,url: https://quilljs.com/0.20/assets/images/cloud.png}, Quill.sources.USER);quill.setSelection(range.index 2, Quill.sources.SILENT);
});const quill new Quill(#editor);
/script
视频 我们将以与图片类似的方式实现视频。我们可以使用HTML5的video标签但我们不能用这种方式播放YouTube视频由于这可能是更常见和相关的用例我们将使用iframe来支持这一点。我们在这里不需要这样做但如果您希望多个Blot使用相同的标签(tag)您可以在下一个推文示例中使用className以及tagName。 此外我们将添加对宽度和高度的支持作为未注册的格式。特定于嵌入的格式不需要单独注册只要没有与注册格式的命名空间冲突即可。这之所以有效是因为Blot只是将未知格式传递给它的子元素最终到达叶子。这也允许不同的嵌入以不同的方式处理未注册格式。例如我们之前的image嵌入可以以与此处的video不同的方式识别和处理宽度格式。 class VideoBlot extends BlockEmbed {static blotName video;static tagName iframe;static create(url) {const node super.create();node.setAttribute(src, url);// 使用静态值设置非格式相关属性node.setAttribute(frameborder, 0);node.setAttribute(allowfullscreen, true);return node;}static formats(node) {// 我们仍然需要报告未注册的嵌入格式const format {};if (node.hasAttribute(height)) {format.height node.getAttribute(height);}if (node.hasAttribute(width)) {format.width node.getAttribute(width);}return format;}static value(node) {return node.getAttribute(src);}format(name, value) {// 处理未注册的嵌入格式if (name height || name width) {if (value) {this.domNode.setAttribute(name, value);} else {this.domNode.removeAttribute(name, value);}} else {super.format(name, value);}}
}Quill.register(VideoBlot); 请注意如果您打开控制台并调用getContentsQuill将报告视频如下 {ops: [{insert: {video: https://www.youtube.com/embed/QHH3iSeDBLo?showinfo0},attributes: {height: 170,width: 400}}]
} button idvideo-buttoni classfa fa-play/i/buttondiv ideditorTell your story.../divscriptonClick(#video-button, () {let range quill.getSelection(true);quill.insertText(range.index, \n, Quill.sources.USER);let url https://www.youtube.com/embed/QHH3iSeDBLo?showinfo0;quill.insertEmbed(range.index 1, video, url, Quill.sources.USER);quill.formatText(range.index 1, 1, { height: 170, width: 400 });quill.setSelection(range.index 2, Quill.sources.SILENT);
});const quill new Quill(#editor);
/script
推特 Medium支持许多嵌入类型但我们将只关注本指南中的推文。推文Blot几乎与图片完全相同实现。我们利用了嵌入Blot不必对应一个空节点的事实。它可以是任何任意节点Quill将其视为空节点不会遍历其子元素或后代。这使我们能够使用div和原生Twitter JavaScript库在指定的div容器内做它想做的事情。 由于我们的根滚动Blot也使用div我们还指定了一个className来消除歧义。请注意内联Blot默认使用span块级Blot默认使用p所以如果您想为您的自定义Blot使用这些标签您必须指定className以及tagName。 我们使用推文id作为定义我们Blot的值。再次我们的点击处理程序使用一个静态值以避免分散注意力到无关的UI代码上。 class TweetBlot extends BlockEmbed {static blotName tweet;static tagName div;static className tweet;static create(id) {const node super.create();node.dataset.id id;// 允许twitter库修改我们的内容twttr.widgets.createTweet(id, node);return node;}static value(domNode) {return domNode.dataset.id;}
}Quill.register(TweetBlot); button idtweet-buttoni classfa fa-twitter/i/button
div ideditorTell your story.../divscriptonClick(#tweet-button, () {const range quill.getSelection(true);const id 464454167226904576;quill.insertText(range.index, \n, Quill.sources.USER);quill.insertEmbed(range.index 1, tweet, id, Quill.sources.USER);quill.setSelection(range.index 2, Quill.sources.SILENT);
});const quill new Quill(#editor);
/script
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/84043.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!