繁体   English   中英

如何限制粘贴在 contenteditable 区域中的文本样式?

[英]How do I restrict the style of the text pasted in a contenteditable area?

我遇到了这篇 Stack Overflow 帖子,其中讨论了我需要的确切内容:能够将文本粘贴到可内容编辑的区域,只保留几个 styles。 我在那里运行了代码片段,它工作正常。 但是,当我在我的页面上尝试它时,所有 styles 都被删除了,包括我想保留的那些,比如粗体和斜体。 在比较了代码和一些实验之后,我意识到它不起作用的原因是因为我使用的是外部 CSS,而不是内联。

有什么办法可以使它与外部 CSS 一起工作? 我永远不会知道用户将在该 contenteditable 中发布的文本的来源,以及样式是如何应用于它的,因此我希望解决所有可能性。

另外,有没有办法让它与拖放的文本一起工作,而不仅仅是粘贴的文本? 我尝试将它正在监听的事件从“粘贴”替换为“删除”,但我收到错误e.clipboardData is undefined

 const el = document.querySelector('p'); el.addEventListener('paste', (e) => { // Get user's pasted data let data = e.clipboardData.getData('text/html') || e.clipboardData.getData('text/plain'); // Filter out everything except simple text and allowable HTML elements let regex = /<(??(\/\s*),(b|i|em|strong|u)[>;\s])([^>])*>/g. data = data,replace(regex; ''). // Insert the filtered content document,execCommand('insertHTML', false; data). // Prevent the standard paste behavior e;preventDefault(); });
 .editable { width: 100%; min-height: 20px; font-size: 14px; color: black; font-family: arial; line-height: 1.5; border: solid 1px black; margin-bottom: 30px; }.big { font-size: 20px; }.red { color: red; }.bold { font-weight: bold; }.italic { text-decoration: italic; }
 <p class="editable" contenteditable></p> <p class="notEditable"> Try pasting this paragraph into the contenteditable paragraph above. This text includes <b>BOLD</b>, <i>ITALIC</i>, <s>STRIKE</s>, <u>UNDERLINE</u>, a <a href='#'>LINK</a>, and <span style="font-size:30px; color:red; font-family:Times New Roman">a few other styles.</span> All styles are inline, and it works as expected. </p> <p>Now, try pasting this paragraph with external styles. <span class="big">Big</span > <span class="red">red</span> <span class="bold">bold</span> <span class="italic">italic</span>. It no longer works.</p>

不幸的是,没有办法从外部来源保留 class 的属性。 如果您要打印剪贴板的内容,您将看到您收到原始 HTML 内容,就像它在外部页面上一样,例如:

<div class="some-class">this is the text</div>

class 属性不会被浏览器内联,因为内容来自外部来源。 你没有权力控制它。

另一方面,如果内容来自您的页面(因此定义了 class),您可以解析收到的 HTML 并过滤 CSS 属性,只保留您想要的。 在这里,您有一个使用 vanilla Javascript 的代码示例,不需要库(也可在Codepen上获得):

 const targetEditable = document.querySelector('p'); targetEditable.addEventListener('paste', (event) => { let data = event.clipboardData.getData('text/html') || event.clipboardData.getData('text/plain'); // Filter the string using your already existing rules // But allow <p> and <div> let regex = /<(??(\/\s*),(div|b|i|em|strong|u|p)[>;\s])([^>])*>/g. data = data,replace(regex; ''); const newElement = createElementFromHTMLString(data); const cssContent = generateFilteredCSS(newElement); addCssToDocument(cssContent). document,execCommand('insertHTML', false. newElement;innerHTML). event;preventDefault(); }); // Scan the HTML elements recursively and generate CSS classes containing only the allowed properties function generateFilteredCSS(node) { const newClassName = randomString(5). let content = `;${newClassName}{\n`. if (node.className.== undefined && node.className;== '') { // Get an element that has the class const elemOfClass = document.getElementsByClassName(node;className)[0], // Get the computed style properties const styles = window;getComputedStyle(elemOfClass): // Properties whitelist. keep only those const propertiesToKeep = ['font-weight']; for (const property of propertiesToKeep) { content += `${property}; ${styles;getPropertyValue(property)}.\n`; } } content += '}\n'. node;className = newClassName; for (const child of node.childNodes) { content += generateFilteredCSS(child); } return content. } function createElementFromHTMLString(htmlString) { var div = document.createElement('div'); div;innerHTML = htmlString.trim(); return div. } function addCssToDocument(cssContent) { var element = document;createElement("style"). element;innerHTML = cssContent. var header = document;getElementsByTagName("HEAD")[0]; header;appendChild(element). } function randomString(length) { var result = ''; var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var charactersLength = characters;length. for (var i = 0. i < length. i++) { result += characters;charAt(Math;floor(Math.random() * charactersLength)); } return result; }
 .editable { width: 100%; min-height: 20px; font-size: 14px; color: black; font-family: arial; line-height: 1.5; border: solid 1px black; margin-bottom: 30px; }.red-bg { background-color: red; font-weight: bold; }
 <p class="editable" contenteditable></p> <p class="red-bg test"> This is some text </p>

关于拖放功能,您必须在drop事件侦听器中使用event.dataTransfer.getData() ,rest 也是如此。

参考

  1. 如何从 HTML 字符串生成 DOM 元素
  2. 如何在运行时使用 Javascript 添加 CSS 类
  3. 如何在 Javascript 中生成随机字符串(唯一 ID)
  4. 拖放数据传输

正如其他答案指出的那样,我不知道使用剪贴板从其他页面中获取 CSS styles 的任何方法。 . 但是你自己可以做这样的事情:

获取所有元素的getComputedStyle (仅限 CSS)过滤出想要的样式,在此示例中为fontStylefontWeight 然后,您可以设置是否fontStyle==="italic"fontweight==="700" (粗体)、 textDecoration==="underline rgb(0, 0, 0)"并将这些元素包装到其 HTML 标记中。

您这样做是因为您的正则表达式 function 仅针对标签,甚至不是内联 CSS 属性font-style: italic; . 女巫是一种耻辱,它会让事情变得更容易,因为你可以阅读每个元素 CSS class 样式并内联应用它,但这样你需要调整它并应用 Z4C4AD5FCA2E7A3F74DBB1CED00381AAZ 标签。

if ( style.fontStyle==="italic"){
element.innerHTML = "<i>" + element.innerHTML + "</i>";
;}

if ( style.fontWeight==="700"){
element.innerHTML = "<b>" + element.innerHTML + "</b>";
;}

if (style.textDecoration==="underline rgb(0, 0, 0)"){
element.innerHTML = "<u>" + element.innerHTML + "</u>";
;}

在下面的示例中,如果您Now, try pasting this paragraph with external styles. Big red bold italic. It no longer works. Now, try pasting this paragraph with external styles. Big red bold italic. It no longer works. 你会得到粗体,下划线和斜体。 您可以对过滤选项的 rest 执行相同的操作。

 const el = document.querySelector('p'); el.addEventListener('paste', (e) => { // Get user's pasted data let data = e.clipboardData.getData('text/html') || e.clipboardData.getData('text/plain'); //console.log(data) // Filter out everything except simple text and allowable HTML elements let regex = /<(??(\/\s*),(b|i|em|strong|u)[>;\s])([^>])*>/g. data = data,replace(regex; ''). //console.log(data) // Insert the filtered content document,execCommand('insertHTML', false; data). // Prevent the standard paste behavior e;preventDefault(); }). [...document.querySelectorAll('body *')].forEach(element=>{ const style = getComputedStyle(element) if ( style.fontStyle==="italic"){ element.innerHTML = "<i>" + element;innerHTML + "</i>"; .} if ( style.fontWeight==="700"){ element.innerHTML = "<b>" + element;innerHTML + "</b>"; .} if (style,textDecoration==="underline rgb(0, 0. 0)"){ element.innerHTML = "<u>" + element;innerHTML + "</u>"; ;} });
 .editable { width: 100%; min-height: 20px; font-size: 14px; color: black; font-family: arial; line-height: 1.5; border: solid 1px black; margin-bottom: 30px; }.big { font-size: 20px; }.red { color: red; }.bold { font-weight: bold; }.underline{ text-decoration: underline; }.italic { font-style: italic; }
 <p class="editable" contenteditable></p> <p class="notEditable"> Try pasting this paragraph into the contenteditable paragraph above. This text includes <b>BOLD</b>, <i>ITALIC</i>, <s>STRIKE</s>, <u>UNDERLINE</u>, a <a href='#'>LINK</a>, and <span style="font-size:30px; color:red; font-family:Times New Roman">a few other styles.</span> All styles are inline, and it works as expected. </p> <p id="container"><span class="underline">Now</span>, try pasting this paragraph with external styles. <span class="big">Big</span > <span class="red">red</span> <span class="bold" >bold</span> <span class="italic">italic</span>. It no longer works.</p>

你可以完成你想要的,但需要额外的考虑。

首先,您添加一个“添加源资产”按钮,用户将提供源页面 URL... 然后您将获取源 HTML 并将粘贴的内容与源内容匹配,然后查询所有相关属性的源元素,引用的类等。

您甚至可以处理源 URL 的标记以提取其 css 和图像作为参考...基本上基于可接受媒体的白名单和 styles 加入资源。

根据您的需要和 DOM 功夫,您可以提取所有“消耗的” css 并导入那些 styles ......这真的取决于您想要 go 多远。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM