Rich Text API

This note summarizes the information from the network of
Jane book Gangster three times daily _9862
tuobaye personal blog

There are three related rich text API and a new property

  • var selection = window.getSelection();
  • var range = selection.getRangeAt;
  • document.execCommand(x,y,z);
  • The new attribute contenteditable = "true"

first step

<!-- 让标签变成可输入的区域 -->
<div contenteditable="true" id="rich-editor">

range to the object and the object selection operation of the cursor
normally we do not directly target selection operation, but requires the user to select the operating ranges of the object corresponds with seleciton (region), commonly known as拖蓝

var selection = window.getSelection();
var range = selection.getRangeAt(0);
// 由于浏览器当前可能存在多个文本选取,所以 getRangeAt 函数接受一个索引值。在富文本编辑其中,我们不考虑多选取的可能性,就当上面是固定写法

image.png

This is the printing position of the cursor as the cursor console and can not operate simultaneously, with the timer

image.png

This drag blue print position, and console since the cursor can not operate simultaneously, with the timer

Properties of the above two graphs

  • startContainer: start node range range.
  • endContainer: End Node range range
  • startOffset: start position of the offset range.
  • endOffset: offset range end position.
  • commonAncestorContainer: Returns the deepest node and comprising startContainer of endContainer.
  • collapsed: Returns a Range for determining whether the same start and end positions Boolean values.

selection methods are

selection.getRangeAt()
selection.removeAllRanges()
selection.addRange()

There are methods range

range.setStart(): 设置 Range 的起点
range.setEnd(): 设置 Range 的终点
range.selectNode(): 设定一个包含节点和节点内容的 Range
range.collapse(): 向指定端点折叠该 Range
range.insertNode(): 在 Range 的起点处插入节点。
range.cloneRange(): 返回拥有和原 Range 相同端点的克隆 Range 对象

Therefore, the basic operation is the rich text editor, delete the original ranges to ensure that the cursor will change to a position that we want

let selection  =  window.getSelection();
selection.removeAllRanges();
let range  =  document.createRange();
range.setStart(startContainer,startOffset);
range.setEnd(endContainer,endOffset);
selection.addRange(range);

The operation of the text

// 一句代码实现富文本编辑器的核心
document.execCommand(x,y,z)

// x参数
// 有选中文字,加粗,下划线,删除线,斜体
// 有有当前光标所在行,左 居中 右 两端
// 有有光标所在行, 右缩进 左缩进
// 有有插入,有序列表,无序列表
// 有有选中文字变成,上标 下标
// 有有,全选 复制 剪切
// 有有选中字体,字体大小
// 有有选中字体,字体风格
// 有有选择字体,字体颜色

// y参数,就是false

// z参数是需要选中的功能传进来的value

See specific second code above big brother

"" Also you need to add a few features in it, repair a few bug

插入 ul 和 ol 位置错误
当我们调用 document.execCommand("insertUnorderedList", false, null) 来插入一个列表的时候,新的列表会被插入

标签中,为此我们需要每次调用该命令前做一次修正,参考代码如下:

function  adjustList(){
   let lists = document.querySelectorAll("ol, ul");
   for(let i = 0;i < lists.length;i++)  {
      let ele = lists[i];  // ol
      let parentNode = ele.parentNode;
      if(parentNode.tagName === 'P' && parentNode.lastChild === parentNode.firstChild){
         parentNode.insertAdjacentElement('beforebegin',ele);
         parentNode.remove()
      }
   } 
}

插入分割线
调用 document.execCommand('insertHorizontalRule', false, null); 会插入一个<hr>标签
光标和<hr>的效果一致了。为此要判断当前光标是否在<li>里面,如果是则在<hr>后面追加一个空的文本节点 #text 不是的话追加 <p><br></p>。然后将光标定位在里面,可用如下方式查找。

function  findParentByTagName(root, name){
    let parent=root;
    if  (typeof name === "string"){
        name = [name];
    }
    while(name.indexOf(parent.nodeName.toLowerCase())===-1&&parent.nodeName!=="BODY"&&parent.nodeName!=="HTML"){
        parent=parent.parentNode;
    }
    return  parent.nodeName === "BODY" || parent.nodeName === "HTML"?null:parent;
}

插入链接
调用 document.execCommand('createLink', false, url); 方法我们可以插入一个 url 链接,但是该方法不支持插入指定文字的链接。同时对已经有链接的位置可以反复插入新的链接。为此我们需要重写此方法。

function  insertLink(url,title){
    let selection = document.getSelection(),
    range = selection.getRangeAt(0);
    if(range.collapsed){
        let start = range.startContainer,
        parent=Util.findParentByTagName(start,'a');
        if(parent){
            parent.setAttribute('src',url);
        }else{
            this.insertHTML(`<a href="${url}">${title}</a>`);
        }
    }else{
        document.execCommand('createLink',false,url);
    }
}

处理 paste 粘贴
在富文本编辑器中,粘贴效果默认采用如下规则:

  1. 如果是带有格式的文本,则保留格式(格式会被转换成html标签的形式)
  2. 粘贴图文混排的内容,图片可以显示,src 为图片真实地址。
  3. 通过复制图片来进行粘贴的时候,不能粘入内容
  4. 粘贴其他格式内容,不能粘入内容

为了能够控制粘贴的内容,我们监听 paste 事件。该事件的 event 对象中会包含一个 clipboardData 剪切板对象。

对于规则一和规则二,我们可以利用该对象的 getData 方法来获得带有格式和不带格式的内容

// 先判断格式
let plainText = event.clipboardData.getData('text/plain');  // 无格式文本
let plainHTML = event.clipboardData.getData('text/html'); // 有格式文本
// 再选择调用
document.execCommand('insertText', false, plainText);
// 或
document.execCommand('insertHTML', false, plainHTML); 
来重写编辑上的paste效果。

However, for Rule 3, the above scheme can not be dealt with. Here we want to introduce event.clipboardData.items, which is an array that contains the contents of all the objects in the clipboard when you copy a picture to paste, then the length of it is two event.clipboardData.items

// items[0] 为图片的名称
// items[0].kind 为 string
// items[0].type 为 text/plain 或 text/html
// 获取内容方式如下:
items[0].getAsString(str => {
    // 处理 str 即可
})

// items[1] 为图片的二进制数据
// items[1].kind 为 file
// items[1].type 为 图片的格式
// 想要获取里面的内容,我们就需要创建 FileReader 对象了,示例代码如下:

let file = items[1].getAsFile();
// file.size 为文件大小
let reader = new FileReader();
reader.onload = function()  {
    // reader.result 为文件内容,就可以做上传操作了
}

if(/image/.test(item.type))  {
    reader.readAsDataURL(file); // 读取为 base64 格式
}

Insert Picture failure

document.execCommand('insertImage', 'false', url);

If the editor loses focus, the selection and range objects will be destroyed. Therefore calls insertImage, and can not get the cursor location, and therefore fails. This requires increased, backupRange () and restoreRange () function. When the page loses focus range of recovery information before recording range information, insert pictures

// 需要在光标离开时记录位置,使用的是最上面的两句代码
var selection = window.getSelection();
var range = selection.getRangeAt(0);

// 当用户选择了图片文件后,执行fous()
document.querySelector("#rich-editor").focus()

// 然后移动光标到之前的位置
// 再执行
document.execCommand('insertImage', 'false', url);

Guess you like

Origin www.cnblogs.com/pengdt/p/12037988.html