什么是contenteditable

允许用户编辑元素中的内容,如div、span等

使用

下面记录几个工作中用过的功能

1
2
3
4
5
6
7
8
9
10
<div 
id="editor"
class="editor content"
contenteditable
spellcheck="false"
placeholder="请输入内容,点击回车即可发送!"
onkeydown="keydown()"
onkeyup="keyup()"
onpaste="listenPaste()"
></div>
开启可编辑
1
<div contenteditable="true"></div> 
获取数据
1
2
3
const dom = document.getElementById('editor')
const allData = dom.innerHTML
const textData = dom.innerText.trim()
shift+enter换行
1
2
3
4
5
6
7
8
9
10
11
12
// 换行操作更改,不是shift+enter不换行
function keydown(e) {
if(!e.shiftKey && e.keyCode == 13) {
e.cancelBubble = true; // ie阻止冒泡行为
e.stopPropagation(); // Firefox阻止冒泡行为
e.preventDefault(); // 取消事件的默认动作*换行
//以下处理发送消息代码
if (e.keyCode == 13) {
send()
}
}
}
换行后有个换行符
1
2
3
4
5
6
7
8
9
function keyup(e, user) {
// 删除,解决换行后删除最后会留一个br的问题
if(e.keyCode == 8) {
const editor = document.getElementById('editor')
if(editor.innerHTML === '<br>') {
editor.innerHTML = ''
}
}
}
粘贴文本去除格式,粘贴文件
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// 监听粘贴文件
async function listenPaste(e) {
let clipboardData = e.clipboardData
if (clipboardData) {
// 文件
const arr = Array.from(clipboardData.files)
for (let i = 0; i < arr.length; i++) {
const item = arr[i]
let blob = await fileToBlob(item)
fileReader({ type: item.type }, blob)
}
// 粘贴的是文件就只有文件,不考虑文本
if(arr.length > 0) return

// 文本去除格式
e.stopPropagation();
e.preventDefault();
var text = '', event = (e.originalEvent || e);
if (event.clipboardData && event.clipboardData.getData) {
text = event.clipboardData.getData('text/plain');
} else if (window.clipboardData && window.clipboardData.getData) {
text = window.clipboardData.getData('Text');
}
// execCommand提示将被弃用,TODO:替换方案
if (document.queryCommandSupported('insertText')) {
document.execCommand('insertText', false, text);
} else {
document.execCommand('paste', false, text);
}
}
}

// 编辑器渲染文件
function fileReader(item, blob) {
console.log('fileReader----', item, blob)
let type = 'file'
if(item.type.match(/^image\//i)) {
// image
type = 'img'
}else if(item.type === 'text/plain') {
// txt
type = 'txt'
}else if(item.type.includes('sheet')) {
// excel
type = 'excel'
}else if(item.type.split('.')[item.type.split('.').length - 1] === 'document') {
// doc
type = 'doc'
}else if(item.type === 'application/pdf') {
// pdf
type = 'pdf'
}
// 生成id,添加到fileList全局变量暂存,发送时从这儿获取,发送后清空
const id = Math.random()
fileList.push({ id: id, file: blob, type: type })
// 按文件类型显示图片,并给img添加data-id属性,将来获取编辑内容的时候去找到真实文件
let blobUrl = URL.createObjectURL(blob)
let img = new Image()
const url = type === 'img' ? blobUrl : blobUrl
img.src = url
img.setAttribute('data-id', id)
img.style.width = '50px'
img.style.height = '50px'
img.style.objectFit = 'contain'
img.onclick = function() {}
const box = document.createElement('span')
box.appendChild(img)
document.getElementById('editor').appendChild(box)
}

// 获取内容时找到真实文件
const imgs = document.querySelectorAll('#editor img')
const imgIds = imgs.map(item => Number(item.getAttribute('data-id')))
const fileData = fileList.filter(item => imgIds.includes(Number(item.id))).map(item => item.file)

文件相关用到的方法

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
function fileToBlob(file) {
console.log('filetoblob====', file)
// 创建 FileReader 对象
let reader = new FileReader();
return new Promise(resolve => {
// FileReader 添加 load 事件
reader.addEventListener('load', (e) => {
let blob;
if (typeof e.target.result === 'object') {
blob = new Blob([e.target.result])
} else {
blob = e.target.result
}
resolve(blob)
})
// FileReader 以 ArrayBuffer 格式 读取 File 对象中数据
reader.readAsArrayBuffer(file)
})
}

function blobToArrayBuffer(blob, callback) {
const fileReader = new FileReader();
fileReader.onload = function(event) {
// 转换为ArrayBuffer
const arrayBuffer = event.target.result;
// 转换为Uint8Array,类似于Node.js中的Buffer
const uint8Array = new Uint8Array(arrayBuffer);
callback(null, uint8Array);
};
fileReader.onerror = function(error) {
callback(error, null);
};
fileReader.readAsArrayBuffer(blob);
}