如何使用 Vanilla JS 构建自己的 WYSIWYG 编辑器 (RTE)

问题描述

我不想使用 Jquery。我想在 vanilla JS 中解决这个问题。 请帮帮我!

描述:如何在 JavaScript 中点击按钮时使选中的文本变为粗体/斜体/下划线?

这是我的 HTML。

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <Meta charset="UTF-8" />
        <Meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <Meta name="viewport" content="width=device-width,initial-scale=1.0" />
        <link rel="stylesheet" href="./style/style.css" />
        <link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" 
        integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" 
        crossorigin="anonymous" />
        <title>TextEditor</title>
    </head>
    
    <body>
        <header>
          <h1>Text Editor</h1>
        </header>
        <main>
            <div class="functionality">
                <div class="container">
                    <button class="btn" id="bold"><i class="fas fa-bold"></i></button>
                    <button class="btn" id="italic"><i class="fas fa-italic"></i></button>
                    <button class="btn" id="underline"><i class="fas fa-underline"></i></button>
                    <button class="btn" id="align-left"><i class="fas fa-align-left"></i></button>
                    <button class="btn" id="justify"><i class="fas fa-align-justify"></i></button>
                    <button class="btn" id="align-right"><i class="fas fa-align-right"></i></button>
                </div>
            </div>
            <div class="input-container">
                <textarea contenteditable="true" name="text-input-c1" id="text-input" rows="3"> 
                </textarea>
            </div>
        </main>
    </body>
    <script src="./script.js"></script>
    
    </html>

解决方法

我认为这是一个可能的解决方案。

  • 我编写了一个不复制代码的函数。
  • 您可以修改它以适应您的问题,我也将该功能应用于斜体、粗体和下划线的 css 样式。对齐按钮不起作用,您必须实现逻辑但它与此功能非常相似
  • 再次单击按钮时,您可以尝试应用另一个功能来删除样式。

如前所述,textarea 不允许修改文本某些部分的样式,所以我使用 span 来避免问题。我尝试了 div,但我有一些不同的行为。

function addEventEditionButton(btnId,cssProperty,cssPropertieValy) {
  let buttonTarget = document.getElementById(btnId);
  buttonTarget.addEventListener("click",function () {
    let selection = window.getSelection().getRangeAt(0);
    let selectedText = selection.extractContents();
    let span = document.createElement("span");
    try{
        span.style[cssProperty] = cssPropertieValy;
    }catch(e){
        console.trace(e);
    }    
    span.appendChild(selectedText);
    selection.insertNode(span);
  });
}

addEventEditionButton("bold","fontWeight","bold");
addEventEditionButton("italic","fontStyle","italic");
addEventEditionButton("underline","textDecoration","underline");
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <!-- <link rel="stylesheet" href="./style/style.css" /> -->
    <link
      rel="stylesheet"
      href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css"
      integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p"
      crossorigin="anonymous"
    />
    <title>TextEditor</title>
    <style>
      .input-container {
        border: 1px solid black;
        width: 223px;
        height: 103px;
        overflow: scroll;
      }
    </style>
  </head>

  <body>
    <header>
      <h1>Text Editor</h1>
    </header>
    <main>
      <div class="functionality">
        <div class="container">
          <button class="btn" id="bold"><i class="fas fa-bold"></i></button>
          <button class="btn" id="italic"><i class="fas fa-italic"></i></button>
          <button class="btn" id="underline">
            <i class="fas fa-underline"></i>
          </button>
          <button class="btn" id="align-left">
            <i class="fas fa-align-left"></i>
          </button>
          <button class="btn" id="justify">
            <i class="fas fa-align-justify"></i>
          </button>
          <button class="btn" id="align-right">
            <i class="fas fa-align-right"></i>
          </button>
        </div>
      </div>
      <div contenteditable class="input-container">
        <span name="text-input-c1" id="text-input"></span>
      </div>
    </main>
  </body>
  <script src="./stackoverflow.js"></script>
</html>

请注意此 HTML 更改:

<div contenteditable class="input-container">
    <span name="text-input-c1" id="text-input"></span>
</div>
,

我的建议:

const formatText = (tag) => {
  var start = textarea.selectionStart,end = textarea.selectionEnd,len = textarea.value.length,text = textarea.value.substring(start,end);
  if (text) textarea.value = textarea.value.substring(0,start) + `<${tag}>${text}</${tag}>` + textarea.value.substring(end,len);
}
form {
  display: flex;
  flex-direction: column;
}

textarea {
  width: 100%;
  height: 100px;
  margin-bottom: 20px;
}

button {
  margin-bottom: 20px;
}
<form id="form">
  <textarea id="textarea">
Lorem ipsum dolor sit amet,consectetur adipiscing elit. Aenean venenatis justo ante,sed condimentum dui lobortis nec. Morbi ut aliquam turpis. Aliquam elementum urna diam. Morbi ullamcorper dolor ipsum,quis porttitor tortor bibendum nec. Donec imperdiet neque nec est faucibus,ac congue ligula hendrerit. Cras quis metus ullamcorper,commodo est vel,elementum nulla. In hac habitasse platea dictumst. Morbi posuere pulvinar tellus,quis tincidunt felis condimentum at. Maecenas eu molestie lorem. Nullam finibus luctus mauris,ut tincidunt diam ultrices id. Curabitur vitae vehicula mi,et tincidunt nulla. Sed vitae rhoncus sem,quis aliquet quam. Etiam dignissim lacus eget ex dictum scelerisque. Quisque id ornare odio,non placerat odio.
</textarea>
  <button type="button" onclick="formatText('i');">Italic</button>
  <button type="button" onclick="formatText('b');">Bold</button>
  <button type="button" onclick="formatText('u');">Underlined</button>
</form>

选择您想要斜体/粗体/下划线的文本,然后单击按钮。

,

您不能为文本区域的内容设置样式,而是使用 Div。

对于选择和粗体,你可以试试这个。

$('#bold').click(function() {
    var selected_text = window.getSelection ? 
        "" + window.getSelection() : document.selection.createRange().text;
     console.log(selected_text);
    $("div:contains('"+selected_text+"')").html(function(_,html) {
      return html.split(selected_text).join("<b>cow</b>");
   });

});

注意:我还没有测试过