大家好,我是考100分的小小码 ,祝大家学习进步,加薪顺利呀。今天说一说富文本编辑器官网_富文本编辑器是做什么的,希望您对编程的造诣更进一步.
简介
富文本编辑器,能够使web
页面像word
一样,实现对文本的编辑,通常应用在一些文本处理比较多的系统中。现在业界有很多成熟的富文本编辑器,比如功能齐全啊TinyMCE、轻量高效的wangEditor、百度出品的UEditor等。富文本编辑器很多,但是却很少思考如何从零开始,实现一个富文本编辑器。本文主要简述如何从零开始,实现一个简易的富文本编辑器。
基本使用
普通的HTML
标签,能够输入的通常只是表单,表单输入的是纯文本,不带格式的内容。富文本相对于表单,能够给输入文本内容增加一些自定义内容样式,比如加粗、字体颜色、背景…。富文本的实现,主要是给HTML标签,比如div
增加一个contenteditable
属性,拥有该属性的HTML
标签,就能够对该标签里的内容,实现自定义的编辑。最简单的富文本编辑器如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app" style="width: 200px;height: 200px;background-color: antiquewhite;" contenteditable='true'></div>
</body>
</html>
基本操作
富文本类似于Word,有很多操作文本选项,比如文本的加粗、添加背景颜色、段落缩进等,使用方式是命令式的,只需要执行document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)
,其中aCommandName
是命令名称,aShowDefaultUI
一个 Boolean
, 是否展示用户界面,一般为 false
。Mozilla 没有实现。aValueArgument
,额外参数,一般为null
。
基本操作命令
以下简单列举一些富文本操作命令,下面给出一些例子的简单使用
命令 | 值 | 说明 |
---|---|---|
backcolor | 颜色字符串 | 设置文档的背景颜色 |
bold | null | 将选择的文本加粗 |
createlink | URL字符串 | 将选择的文本转换成一个链接,指向指定的URL |
indent | null | 缩进文本 |
copy | null | 将选择的文本复制到剪切板 |
cut | null | 将选择文本剪切到剪切板 |
inserthorizontalrule | null | 在插入字符处插入一个hr元素 |
Example:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
<style> html, body{ width: 100%; height: 100%; padding: 0; margin: 0; } #app{ display: flex; flex-direction: column; justify-content: flex-start; width: calc(100% - 100px); height: calc(100% - 100px); padding: 50px; } .operator-menu{ display: flex; justify-content: flex-start; align-items: center; width: 100%; min-height: 50px; background-color: beige; padding: 0 10px; } .edit-area{ width: 100%; min-height: 600px; background-color: blanchedalmond; padding: 20px; } .operator-menu-item{ padding: 5px 10px; background-color: cyan; border-radius: 10px; cursor: pointer; margin: 0 5px; } </style>
</head>
<body>
<div id="app">
<div class="operator-menu">
<div class="operator-menu-item" data-fun='fontBold'>加粗</div>
<div class="operator-menu-item" data-fun='textIndent'>缩进</div>
<div class="operator-menu-item" data-fun='inserthorizontalrule'>插入分隔符</div>
<div class="operator-menu-item" data-fun='linkUrl'>链接百度</div>
</div>
<div class="edit-area" contenteditable="true"></div>
</div>
<script> let operationItems = document.querySelector('.operator-menu') // 事件监听采用mousedown,click事件会导致富文本编辑框失去焦点 operationItems.addEventListener('mousedown', function(e) { let target = e.target let funName = target.getAttribute('data-fun') if (!window[funName]) return window[funName]() // 要阻止默认事件,否则富文本编辑框的选中区域会消失 e.preventDefault() }) function fontBold () { document.execCommand('bold') } function textIndent () { document.execCommand('indent') } function inserthorizontalrule () { document.execCommand('inserthorizontalrule') } function linkUrl () { document.execCommand('createlink', null, 'www.baidu.com') } </script>
</body>
</html>
文本范围与选区
- 富文本中,文本范围和选区是一个非常强大的功能,借助于文本选区,我们可以对选中文本做一些自定义设置。核心是两个对象,
Selection
和Range
对象。用比较官方的说法是,Selection
对象,表示用户选择的文本范围或光标的当前位置,Range
对象表示一个包含节点与文本节点的一部分的文档片段。简单来说,Selection
是指页面中,我们鼠标选中的所有区域,Range
是指页面中我们鼠标选中的单个区域,属于一对多的关系。比如,我们要获取当前页面的选区对象,可以调用var selection = window.getSelection()
,如果想要获取到第一个文本选区信息,可以调用var rang = selection.getRangeAt(0)
,获取到选区文本信息,采用range.toString()
。 - 文本范围与选区,一个比较经典的用法就是,富文本粘贴格式过滤。在我们往富文本编辑器中复制文本时,会保留原文本的格式,如果我们要去除复制的默认格式,只保留纯文本,该如何操作呢?
- 博主在处理这个问题时,首先想到的是,能不能监听粘贴事件
(paste)
,在粘贴文本时,将剪切板内容替换掉。这一个里面也是有坑的,粘贴时操作剪切板是不生效的。在实现功能需求时,最初采用的是正则匹配,去除HTML标签。奈何文本格式五花八门,经常出现各种奇奇怪怪的字符,问题比较多,而且复制大文本时,页面存在性能问题,这并不是一种好的处理方式,直到后来真正理解了文本范围与选区,才发现这个设置,真香。 富文本选区的处理逻辑大致思路如下:
- 监听文本粘贴事件
- 阻止默认事件(阻止浏览器默认复制操作)
- 获取复制纯文本
- 获取页面文本选区
- 删除已选中文本选区
- 创建文本节点
- 将文本节点插入到选区中
- 将焦点移动到复制文本结尾
获取粘贴纯文本
let $editArea = document.querySelector('.edit-area')
$editArea.addEventListener('paste', e => {
// 阻止默认的复制事件
e.preventDefault()
let txt = ''
let range = null
// 获取复制的文本
txt = e.clipboardData.getData('text/plain')
// 获取页面文本选区
range = window.getSelection().getRangeAt(0)
// 删除默认选中文本
range.deleteContents()
// 创建一个文本节点,用于替换选区文本
let pasteTxt = document.createTextNode(txt)
// 插入文本节点
range.insertNode(pasteTxt)
// 将焦点移动到复制文本结尾
range.collapse(false)
})
除此之外,还有很多操作可以借助于选区来实现,比如光标的定位、选中区域内容包裹其他样式等。
实现手动将光标定位到最后一个字符
function keepLastIndex(element) {
if (element && element.focus){
element.focus();
} else {
return
}
let range = document.createRange();
range.selectNodeContents(element);
range.collapse(false);
let sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
选中区域包裹其他样式
function addCode () {
let selection = window.getSelection()
// 暂时处理第一个选区
let range = selection.getRangeAt(0)
// 拷贝一份原始选中数据
let cloneNodes = range.cloneContents()
// 移除选区
range.deleteContents()
// 创建内容容器
let codeContainer = document.createElement('code')
codeContainer.appendChild(cloneNodes)
// 往选区内添加文本
range.insertNode(codeContainer)
}
附件
以下为测试代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<!-- https://electronjs.org/docs/tutorial/security#csp-meta-tag -->
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
<style> html, body{ width: 100%; height: 100%; padding: 0; margin: 0; } #app{ display: flex; flex-direction: column; justify-content: flex-start; width: calc(100% - 100px); height: calc(100% - 100px); padding: 50px; } .operator-menu{ display: flex; justify-content: flex-start; align-items: center; width: 100%; min-height: 50px; background-color: beige; padding: 0 10px; } .edit-area{ width: 100%; min-height: 600px; background-color: blanchedalmond; padding: 20px; } .operator-menu-item{ padding: 5px 10px; background-color: cyan; border-radius: 10px; cursor: pointer; margin: 0 5px; } </style>
</head>
<body>
<div id="app">
<div class="operator-menu">
<div class="operator-menu-item" data-fun='fontBold'>加粗</div>
<div class="operator-menu-item" data-fun='textIndent'>缩进</div>
<div class="operator-menu-item" data-fun='inserthorizontalrule'>插入分隔符</div>
<div class="operator-menu-item" data-fun='linkUrl'>链接百度</div>
<div class="operator-menu-item" data-fun='addCode'>code</div>
</div>
<div class="edit-area" contenteditable="true"></div>
</div>
<script> let operationItems = document.querySelector('.operator-menu') // 事件监听采用mousedown,click事件会导致富文本编辑框失去焦点 operationItems.addEventListener('mousedown', function(e) { let target = e.target let funName = target.getAttribute('data-fun') if (!funName) return window[funName]() // 要阻止默认事件,否则富文本编辑框的选中区域会消失 e.preventDefault() }) let $editArea = document.querySelector('.edit-area') $editArea.addEventListener('paste', e => { // 阻止默认的复制事件 e.preventDefault() let txt = '' let range = null // 获取复制的文本 txt = e.clipboardData.getData('text/plain') // 获取页面文本选区 range = window.getSelection().getRangeAt(0) // 删除默认选中文本 range.deleteContents() // 创建一个文本节点,用于替换选区文本 let pasteTxt = document.createTextNode(txt) // 插入文本节点 range.insertNode(pasteTxt) // 将焦点移动到复制文本结尾 range.collapse(false) keepLastIndex($editArea) }) function fontBold () { document.execCommand('bold') } function textIndent () { document.execCommand('indent') } function inserthorizontalrule () { document.execCommand('inserthorizontalrule') } function linkUrl () { document.execCommand('createlink', null, 'www.baidu.com') } function addCode () { let selection = window.getSelection() // 暂时处理第一个选区 let range = selection.getRangeAt(0) // 拷贝一份原始选中数据 let cloneNodes = range.cloneContents() // 移除选区 range.deleteContents() // 创建内容容器 let codeContainer = document.createElement('code') codeContainer.appendChild(cloneNodes) // 往选区内添加文本 range.insertNode(codeContainer) } function keepLastIndex(element) { if (element && element.focus){ element.focus(); } else { return } let range = document.createRange(); range.selectNodeContents(element); range.collapse(false); let sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); } </script>
</body>
</html>
参考资料
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/13734.html