里面有猫!Contenteditable 实现简单的富文本编辑器!


可爱的猫猫镇楼

Contenteditable 是 HTML 的一个超好用的全局属性,有了它,就好像给网页里的各种元素(如:div)都加上了神奇的 "编辑开关" 。只要把它的值设置为 true,对应的元素马上就摇身一变,成了能让用户随意编辑的区域。

它的核心原理其实也不难理解,简单来说,就是把用户输入的内容,按照 HTML 的规则,转化成对应的 HTML 结构。比如你输入一段带格式的文字,它会自动帮你生成 b 标签(加粗)、i 标签(斜体)来标记格式,真正实现了 "所见即所得" 。

基础实现

接下来,我将用 Contenteditable 搭建一个超简易的富文本编辑器,带加粗、斜体等这些基本格式设置的那种,代码量不大,新手也能轻松拿捏。

xml 复制代码
<!DOCTYPE html>
<html>

<head>
  <style>
    .editor-container {
      border: 1px solid #ddd;
      border-radius: 4px;
      padding: 10px;
      min-height: 200px;
    }

    .toolbar {
      margin-bottom: 10px;
      display: flex;
      align-items: center;
    }

    .toolbar button {
      margin-right: 5px;
      padding: 5px 10px;
      background: #f5f5f5;
      border: 1px solid #ddd;
      border-radius: 3px;
      cursor: pointer;
    }

    .toolbar button:hover {
      background: #e9e9e9;
    }

    .toolbar select,input {
      margin-right: 5px;
    }

    /* 编辑器内容样式 */
    .editor-content {
      white-space: pre-wrap;
      outline: none;
    }
  </style>
</head>

<body>
  <div class="toolbar">
    <button onclick="toggleBold()">B</button>
    <button onclick="toggleItalic()">I</button>
    <button onclick="toggleUnderline()">U</button>
    <!-- 样式设置 -->
    <select id="fontSize" onchange="setFontSize(this.value)">
      <option value="12">12px</option>
      <option value="14">14px</option>
      <option value="16" selected>16px</option>
      <option value="18">18px</option>
    </select>
    <input type="color" id="textColor" onchange="setTextColor(this.value)">
    <button onclick="insertLink()">链接</button>
    <button onclick="insertImage()">图片</button>
    <button onclick="undo()">撤销</button>
    <button onclick="redo()">重做</button>
  </div>

  <div class="editor-container" contenteditable="true" id="editor"></div>

  <script>
    document.execCommand('fontSize', false, 4);
    // 基础功能实现
    function toggleBold() {
      document.execCommand('bold', false, null);
    }

    function toggleItalic() {
      document.execCommand('italic', false, null);
    }

    function toggleUnderline() {
      document.execCommand('underline', false, null);
    }

    // 设置字体大小
    function setFontSize(size) {
      let fontSize = size == 12 ? 2 : (size == 14 ? 3 : (size == 16 ? 4 : 5))
      document.execCommand('fontSize', false, fontSize);
    }

    // 设置文本颜色
    function setTextColor(color) {
      document.execCommand('foreColor', false, color);
    }

    function insertLink() {
      const url = prompt('请输入链接地址:');
      if (url) {
        document.execCommand('createLink', false, url);
      }
    }

    function insertImage() {
      const imgUrl = prompt('请输入图片地址:');
      if (imgUrl) {
        document.execCommand('insertImage', false, imgUrl);
      }
    }

    // 撤销/重做
    function undo() {
      document.execCommand('undo', false, null);
    }

    function redo() {
      document.execCommand('redo', false, null);
    }

    // 内容获取与保存
    function getContent() {
      return document.getElementById('editor').innerHTML;
    }

    function saveContent() {
      localStorage.setItem('editorContent', getContent());
      alert('内容已保存到本地存储');
    }

    // 加载历史内容
    window.addEventListener('load', () => {
      const savedContent = localStorage.getItem('editorContent');
      if (savedContent) {
        document.getElementById('editor').innerHTML = savedContent;
      }
    });
  </script>
</body>

</html>

代码主要分为 3 个部分,最上面通过 style 标签包裹的是 CSS 部分,主要控制编辑器整体的样式,中间是 HTML 部分,主要由一系列按钮以及最重要的「编辑器」的 div 盒子组成,最下面 script 标签中则是 HTML 中按钮相对应的 JS 逻辑。

这块有两个关键点,一个就是给作为「编辑器」的 div 设置 contenteditable = true,这样它就成了一个可编辑的区域;另一个关键点就是 document.execCommand 方法,通过它来实现编辑器的各个功能。

上图就是这个简易编辑器的页面样式,主要包含了:加粗、斜体、下划线、字号、颜色、链接、图片、撤销、恢复等功能。这样,一个简单的富文本编辑器就基本成型啦!是不是很方便!

实际开发痛点

虽然我实际的工作过程中并不做富文本编辑器这方面的工作,但这块的工作之复杂、繁琐也是早有耳闻。使用 Contenteditable 富文本编辑器在实际开发中,会遇到不少让人头疼的问题,如:光标和选区问题,有用过的小伙伴可能有切身体会,我们在操作的过程中,这个光标位置和选区范围经常不太听话,明明看着光标在文字中间,获取到的位置信息却不对;选中文本后执行操作,效果也不是我们预期的那样。这主要是因为不同浏览器 对光标和选区的处理有差异,再加上 Contenteditable 自身机制的复杂性,就容易出现各种问题。

要解决这个问题,我们可以尝试借助 Range 和 Selection 这两个 JavaScript 对象。Range 对象能精确表示文档中的一个区域,通过它可以获取和操作选区的起始位置、结束位置等信息 。Selection 对象则代表用户当前选中的区域,比如可以用它来判断是否有文本被选中,以及获取选中的文本内容。

优缺点

Contenteditable 的优点是非常明显的:

  • 简单易用,开箱即用
  • 轻量级,性能佳
  • 原生支持键盘操作
  • 实时生成 HTML代码

但是它的缺点不可忽视:

  • 浏览器兼容性问题
  • 复杂格式控制困难
  • 粘贴富文本内容容易导致代码冗余
  • 移动端兼容性

因此,如果只是实现简单的富文本编辑功能,Contenteditable 是个不错的选择,能满足很多基础场景的需求;但要是遇到复杂的功能要求,还是推荐使用像 TinyMCE、Quill 这样成熟的富文本编辑库 。不过,掌握 Contenteditable 的原理,能让我们在面对定制化需求时,有更灵活的应对思路。

以上,就是 Contenteditable 实现简单富文本编辑器相关的全部内容,如果对您有帮助,那是对我最好的激励!如果您感兴趣的话,点个关注吧!我会持续更新的!

相关推荐
Pop–1 小时前
Vue3 el-tree:全选时只返回父节点,半选只返回勾选中的节点(省-市区-县-镇-乡-村-街道)
开发语言·javascript·vue.js
滿1 小时前
Vue3 + Element Plus 动态表单实现
javascript·vue.js·elementui
阿金要当大魔王~~1 小时前
面试问题(连载。。。。)
前端·javascript·vue.js
yuanyxh2 小时前
commonmark.js 源码阅读(一) - Block Parser
开发语言·前端·javascript
进取星辰2 小时前
22、城堡防御工事——React 19 错误边界与监控
开发语言·前端·javascript
ドロロ8063 小时前
element-plus点击重置表单,却没有进行重置操作
javascript·vue.js·elementui
t_hj4 小时前
Ajax案例
前端·javascript·ajax
未脱发程序员5 小时前
分享一款开源的图片去重软件 ImageContrastTools,基于Electron和hash算法
前端·javascript·electron
geovindu6 小时前
vue3: pdf.js 2.16.105 using typescript
javascript·vue.js·typescript·pdf
ZHOU_WUYI8 小时前
用react实现一个简单的三页应用
前端·javascript·react.js