JavaScript实现简单文本编辑器

百度富文本编辑器的文件结构

核心属性 / 方法 / 接口

contentEditable

html属性 用来设置 或 返回元素的内容是否可以被编辑

语法:

1
2
3
4
5
6
<p contentEditable = 'true | false' >...</p>

<script>
HTMLElementObject.contentEditable = true | false
HTMLElementObject.isContentEditable() // 获取元素是否是可编辑状态
</script>

document.execCommand()

操作可编辑元素的语法糖 大多数文本编辑命令都可执行

语法:

1
2
3
4
5
6
7
bool = document.execCommand( aCommandName,ashowDefaultUI,aValueArgument )

/**
* aCommandName : 命令的名称,可用命令参考mdn
* aShowDefaultUI : 是否展示用户界面 | false
* aValueArgument : 一些命令需要的额外参数如字体颜色/大小 | null
*/

借用语法糖实现的编辑器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<body>
<button data-command='bold' onclick="changeStyle(this.dataset)">B</button>
<button data-command="italic" onclick="changeStyle(this.dataset)">I</button>
<button data-command="fontSize" data-value="7" onclick="changeStyle(this.dataset)">fontSize</button>
<button data-command="foreColor" data-value="red" onclick="changeStyle(this.dataset)">color</button>
<button data-command="justifyCenter" onclick="changeStyle(this.dataset)">居中对齐</button>
<button data-command="justifyLeft" onclick="changeStyle(this.dataset)">左对齐</button>
<button data-command="justifyRight" onclick="changeStyle(this.dataset)">右对齐</button>
<br />
<p contentEditable='true'>犹豫就会败北</p>
<p contentEditable='true'>果断就会白给</p>


<script>
function changeStyle(data) {
var attr = data.command
var value = data.value
value ? document.execCommand(attr, false, value) : document.execCommand(attr, false, null)
}
</script>
</body>

Selection

Selection对象表示用户选择的文本范围或插入符号的当前位置。它代表页面中的文本选区,可能横跨多个元素。

语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var selObj = document.getSelection()  // window | document 获取Selection对象
var selStr = selObj.toString() // 获取选中区域的 ‘纯文本’

document.onselectionchange = function(){ // 监听鼠标锚点的变化
console.log( document.getSelection() )
/**
* Selection = {
* anchorNode: node 选取起点所在节点,
* anchorOffset: num 起点偏移量,
* focusNode: node 选取终点所在节点,
* focusOffset: num 终点偏移量,
* isCollapsed: bool 起始点是否在同一位置,
* rangeCount: 返回该选区所包含的连续范围的数量
*
* }
*/
}

Range

表示一个包含节点与文本节点的一部分的文档片段

语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 创建一个文档范围
var range = document.createRange()
var range = new Range()

// 获取选中的文档范围
var range = document.getSelection().getRangeAt(0)

/**
* Range = {
* collapsed : 起始点位置是否相同,
* commonAncetorContainer : 选中区域所在的完整节点, eg: <b> hhh<i>5[5</i>6]6</b> -> <b> hhh<i>55</i>66</b>
* endContainer : 包含range的终点节点, -> 66
* endOffset : 返回一个表示 Range 终点在 endContainer 中的位置的数字。 -> 1 (选中的6在66中排位第几)
* }
*
* Range.cloneContents() 返回一个包含 Range 中所有节点的文档片段
* Range.deleteContents() 移除range包含的内容
* Range.extractContents() 把 Range 的内容从文档树移动到一个文档片段中
* Range.insertNode(Node) 在range起点处插入一个节点
* Range.surroundContents(newNode) 将range内容移动到一个新的节点中
*/

利用 range & selection 接口实现的简易编辑器

有bug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<body>
<button data-command="b" onclick="changeStyle(dataset)"> B </button>
<button data-command="i" onclick="changeStyle(dataset)"> I </button>
<button data-command="h1" onclick="changeStyle(dataset)"> h1 </button>
<button data-value="textAlign:center" onclick="changeStyle(dataset)"> 居中</button>
<button data-value="textAlign:right" onclick="changeStyle(dataset)"> 居右</button>
<button data-value="textAlign:left" onclick="changeStyle(dataset)"> 居左</button>
<button id='btn'>
测试按钮
</button>
<p contentEditable='true'>犹豫<b>就会败北<i>52</i>墨菲</b>定律</p>
<p contentEditable='true'>薛定谔的猫🐱</p>

<script>
// 1.surrounContents(Node) 在原有内容 的基础上包裹一层node节点
// 不能判断是否已经有该元素
function changeStyle(data) {
var tagName = data.command || null
var value = data.value || null
var selobj = document.getSelection()
var Node = document.createElement(tagName)
var range = selobj.getRangeAt(0)
if(value){
var attr = value.split(':')[0].trim(),
cssStyle = value.split(':')[1].trim()
range.commonAncestorContainer.parentElement.style[attr] = cssStyle
}else{
range.surroundContents(Node)
}
}

// 2.把选择的范围节点删除 在字符串外重新添加标签,只能一种标签存在
btn.onclick = function(){
var range = document.getSelection().getRangeAt(0)
var oB = document.createElement('b')
oB.innerHTML = range.toString()
range.deleteContents()
range.insertNode(oB)
}
</script>
</body>

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2019-2023 John Doe
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信