CKEditor富文本编辑器的使用及DIV获取焦点

前言

本文主要使用CKEditor4版本

CKEditor4

下载地址

https://ckeditor.com/ckeditor-4/download/

官方文档

https://ckeditor.com/docs/ckeditor4/latest/guide/dev_installation.html

使用CKEditor

把下载的包放在 public文件夹下

index.html中添加

1
<script type="text/javascript" src="./ckeditor/ckeditor.js"></script>

页面中

1
2
3
<div class="warp_editor">
<textarea id="editor" rows="10" cols="80" v-model="editorData"></textarea>
</div>

样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.warp_editor {
position: relative;
width: 800px;
height: 200px;
border: 1px solid #eee;
margin-top: 120px;
}

.cke_editable {
width: 100%;
height: 100%;
overflow-y: auto;
text-align: left;
}

初始化

1
window.CKEDITOR.inline('editor', {height: '300px', width: '100%', toolbar: 'full'})

或者

1
window.CKEDITOR.replace('editor', {height: '300px', width: '100%', toolbar: 'full'})

取值赋值

获取富文本

1
2
3
4
let html1 = window.CKEDITOR.instances["editor"].getData();
let html2 = myeditor.getData();
console.info("html1", html1);
console.info("html2", html2);

获取纯文本内容:

1
2
3
4
5
// inline模式(div包含)
const content = CKEDITOR.instances["editor"].container.getText();

// stand模式
const content =CKEDITOR.instances["editor"].document.getBody().getText(); //取得纯文本

如果要赋值那么就是

1
myeditor.setData("需要赋值的内容");

监听值变化

1
2
3
4
let myeditor = window.CKEDITOR.inline('editor', {height: '100%', width: '100%', toolbar: 'full'})
myeditor.on('change', () => {
this.editorData = myeditor.getData();
});

图片转base64

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
CKEDITOR.replace('description');
SetCKEditor("description", _self.model.Description);

function SetCKEditor(ckname, data) {
CKEDITOR.instances[ckname].on('instanceReady', function (event) {
var _data = (data || "");
if (_data != "") {
this.setData(HTMLEncode(_data));
}
this.document.on("paste", function (e) {//重写该ckeditor实例的粘贴事件
var items = e.data.$.clipboardData.items;//获取该ckeditor实例的所有剪切板数据
for (var i = 0; i < items.length; ++i) {//循环该数据并只获取类型为image/png格式的数据
var item = items[i];
if (item.kind == 'file' && item.type == 'image/png') {
var imgFile = item.getAsFile();
if (!imgFile) {
return true;
}
var reader = new FileReader();
reader.readAsDataURL(imgFile);//转化为base64格式
reader.onload = function (e) {//在控件中插入该图片
CKEDITOR.instances["description"].insertHtml('<img src="' + this.result + '" alt="" />');
}
return false;
}
}
});
});
}

本地文件转Base64

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function changeBase64(url) {
var imgSrc = url; // 图片本地路劲
var image = new Image()
image.setAttribute("crossOrigin",'Anonymous')
image.src = imgSrc
image.onload = () => {
var canvas = document.createElement("canvas")
canvas.width = image.width
canvas.height = image.height
var ctx = canvas.getContext("2d")
ctx.drawImage(image, 0, 0, image.width, image.height)
var ext = image.src.substring(image.src.lastIndexOf(".") + 1).toLowerCase()
var dataUrl = canvas.toDataURL("image/" + ext)
var base64 = JSON.parse(JSON.stringify(dataUrl)) // 这里就是转化成的编码
console.log(base64);
}
}
changeBase64('./头像-男学生1.png')

自定义Vue组件

两种方式都要注意在组件销毁的时候删除DOM。

InlineEditor

无论是粘贴图片还是上传都转为Base64。

InlineEditor.vue

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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<template>
<textarea :id="editorid" v-html="ckehtml"></textarea>
</template>

<script>
export default {
name: "inline-editor",
props: {
ckehtml: {
type: String,
default() {
return "";
}
},
ckeid: {
type: String,
default() {
return "";
}
}
},
data() {
return {
editorid: null,
domArr: []
};
},
methods: {
uuid() {
let s = [];
let hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = "-";
return s.join("");
},
async initEditor() {
await this.$nextTick();
let myeditor = window.CKEDITOR.inline(this.editorid, {
height: "100%",
width: "100%",
toolbar: "full",
extraPlugins: "zimage",
removeButtons:
"Source,Save,NewPage,ExportPdf,Preview,Print,Templates,Cut,Copy,Find,Scayt,Form,Checkbox,Radio,TextField,Textarea,Select,Button,ImageButton,HiddenField,CreateDiv,Blockquote,Language,Link,Unlink,Anchor,Flash,Smiley,PageBreak,Iframe,ShowBlocks,Maximize,About,Paste,PasteText,PasteFromWord,Undo,Redo,Replace,SelectAll,CopyFormatting,RemoveFormat,Styles,Format,Font,FontSize,TextColor,BGColor,NumberedList,BulletedList,Outdent,Indent,BidiLtr,BidiRtl,Table,HorizontalRule,SpecialChar,Image"
});
if (myeditor) {
myeditor.on("change", () => {
let data = {
id: this.editorid,
html: myeditor.getData(),
txt: myeditor.container.getText()
};

this.$emit("change", data);
});

myeditor.on("instanceReady", () => {
//因为ckeditor会产生新的DOM所以要在页面销毁时删除添加的DOM
let dom1 = document.getElementById(this.editorid);
if (dom1) {
this.domArr.push(dom1);

let dom3 = dom1.parentNode.querySelector(".cke_textarea_inline");
if (dom3) {
this.domArr.push(dom3);
}
}

let dom2 = document.getElementById("cke_" + this.editorid);
if (dom2) {
this.domArr.push(dom2);
}
});
}
}
},
beforeDestroy() {
//之所以提前保存DOM是因为在页面销毁时获取不到DOM但是DOM还在就很奇怪。
for (let i = 0; i < this.domArr.length; i++) {
let dom = this.domArr[i];
if (dom) {
dom.remove();
}
}
},
created() {
console.info("created");
this.editorid = this.ckeid || this.uuid();
},
async mounted() {
await this.initEditor();
}
};
</script>

<style>
.cke_editable {
width: 100%;
height: 100%;
overflow-y: auto;
text-align: left;
}
</style>

使用

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
<template>
<div id="app">
<div class="warp_editor">
<inline-editor ckeid="my_editor" :ckehtml="editorData" @change="editor_change"></inline-editor>
</div>
<div class="warp_editor">
<inline-editor :ckehtml="editorData" @change="editor_change"></inline-editor>
</div>
</div>
</template>

<script>
import InlineEditor from "@/components/InlineEditor";

export default {
name: "app",
components: {InlineEditor},
data() {
return {
editorData: "<p>Content of the editor.</p>",
};
},
mounted() {

},
methods: {
editor_change(data) {
console.info(data);
}
}
};
</script>

<style lang="less">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}

.warp_editor {
position: relative;
width: 600px;
height: 200px;
border: 1px solid #eee;
margin-top: 120px;
}
</style>

CommonEditor

实现了无论粘贴图片还是上传图片都保存到服务器上。

CommonEditor.vue

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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
<template>
<textarea :id="editorid" v-html="ckehtml" :key="editorid"></textarea>
</template>

<script>
export default {
name: "common-editor",
props: {
ckehtml: {
type: String,
default() {
return "";
},
},
ckeid: {
type: String,
default() {
return "";
},
},
},
data() {
return {
editorid: "",
myeditor: null,
uploadUrl: "https://schoolfiletest.psvmc.cn/up/upfile",
uploadWebUrl: "https://schoolfiletest.psvmc.cn/dn/down_webfile",
showImageUrl: "https://schoolstatictest.psvmc.cn/static/",
cacheImgs: {},
};
},
async created() {},
async mounted() {
this.editorid = this.ckeid || this.uuid();
await this.initEditor();
},
beforeDestroy() {
let dom1 = document.getElementById(this.editorid);
dom1 && dom1.remove();
let dom2 = document.getElementById("cke_" + this.editorid);
dom2 && dom2.remove();
},
methods: {
uuid() {
let s = [];
let hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = "-";
return s.join("");
},
async initEditor() {
await this.$nextTick();

let myeditor = window.CKEDITOR.replace(this.editorid, {
height: "100%",
width: "100%",
toolbar: "full",
filebrowserImageUploadUrl: " ",
removeButtons:
"Source,Save,NewPage,ExportPdf,Preview,Print,Templates,Cut,Copy,Find,Scayt,Form,Checkbox,Radio,TextField,Textarea,Select,Button,ImageButton,HiddenField,CreateDiv,Blockquote,Language,Link,Unlink,Anchor,Flash,Smiley,PageBreak,Iframe,ShowBlocks,Maximize,About,Paste,PasteText,PasteFromWord,Undo,Redo,Replace,SelectAll,CopyFormatting,RemoveFormat,Styles,Format,Font,FontSize,TextColor,BGColor,NumberedList,BulletedList,Outdent,Indent,BidiLtr,BidiRtl,Table,HorizontalRule,SpecialChar,zimage",
});
this.myeditor = myeditor;

myeditor.on("fileUploadRequest", (evt) => {
let fileLoader = evt.data.fileLoader,
xhr = fileLoader.xhr;
let filename = fileLoader.fileName;
let strArr = filename.split(".");
let suffix = strArr[strArr.length - 1];
suffix = suffix.toLowerCase();
let myFile = fileLoader.file;
if (suffix === "png" || suffix === "jpeg" || suffix === "jpg") {
this.uploadFile(xhr, myFile, filename);
} else {
this.$Message.warning("请上传png、jpeg、jpg格式的图片");
}
evt.stop();
});

myeditor.on("fileUploadResponse", (evt) => {
let data = evt.data,
xhr = data.fileLoader.xhr;
let result = JSON.parse(xhr.responseText);
if (result.code === 0) {
data.url = this.showImageUrl + result.obj;
} else {
data.message = result.msg;
evt.cancel();
}
evt.stop();
});

myeditor.on("afterPaste", () => {
for (const imgSrc in this.cacheImgs) {
if (!this.cacheImgs[imgSrc]) {
this.uploadWebFile(imgSrc);
}
}
});
myeditor.on("blur", () => {});

myeditor.on("instanceReady", () => {
myeditor.setData(this.ckehtml);
myeditor.dataProcessor.htmlFilter.addRules({
elements: {
img: (el) => {
let imgSrc = el.attributes.src;
if (imgSrc) {
if (imgSrc.indexOf(this.showImageUrl) === -1) {
this.cacheImgs[imgSrc] = "";
}
}
},
},
});
});

myeditor.on("change", () => {
if (myeditor.document.getBody().$) {
let data = {
id: this.editorid,
html: myeditor.getData(),
txt: myeditor.document.getBody().getText(),
};

this.$emit("change", data);
}
});
},

uploadFile(xhr, myFile, filename) {
let formData = new FormData();
let savefolder = "/test/upload";
formData.append("savefolder", savefolder);
formData.append("iscover", "0");
formData.append("isrename", "1");

if (myFile instanceof Blob) {
formData.append(
"file",
new window.File([myFile], filename, { type: myFile.type })
);
} else {
formData.append("file", myFile);
}
xhr.open("POST", this.uploadUrl, true);
xhr.send(formData);
},
uploadWebFile(imgSrc) {
let xhr;
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xhr = new XMLHttpRequest();
} else {
// code for IE6, IE5
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
let formData = new FormData();
let savefolder = "/test/upload";
formData.append("newpath", savefolder);
formData.append("filepath", imgSrc);
xhr.open("POST", this.uploadWebUrl, true);
xhr.send(formData);
// 4.设置监听
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
let result = JSON.parse(xhr.responseText);
if (result.code === 0) {
let imageUrl = this.showImageUrl + result.obj;
this.cacheImgs[imgSrc] = imageUrl;
}
} else {
alert("error");
}
}
};
},
},
};
</script>

<style>
.cke_editable {
width: 100%;
height: 100%;
overflow-y: auto;
text-align: left;
}
</style>

使用ckeditor4-vue

这种方式支持的功能较少

并且扩展性不好,建议自己引用

结合VUE

1
npm install --save ckeditor4-vue

main.js引入

1
2
import CKEditor from 'ckeditor4-vue';
Vue.use(CKEditor);

页面中

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
<template>
<div id="app">
<ckeditor
class="warp_editor"
v-model="editorData"
:config="editorConfig"
type="inline"
></ckeditor>
</div>
</template>

<script>

export default {
name: "app",
data() {
return {
editorData: "<p>Content of the editor.</p>",
editorConfig: {},
};
},
};
</script>

<style lang="less">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}

.warp_editor {
position: relative;
width: 400px;
height: 200px;
border: 1px solid #eee;
margin-top: 120px;
}

.cke_editable {
width: 100%;
height: 100%;
overflow-y: auto;
text-align: left;
}
</style>

上传图片到服务器

默认的编辑器配置是支持粘贴的图片自动转Base64的

要想图片上传至服务器就要把 config.js中添加

1
config.filebrowserImageUploadUrl = "";

如下

1
2
3
4
5
6
7
8
9
10
11
12
CKEDITOR.editorConfig = function (config) {
config.removeButtons = "Source,Save,NewPage,ExportPdf,Preview,Print,Templates,Cut,Copy,Find,Scayt,Form,Checkbox,Radio,TextField,Textarea,Select,Button,ImageButton,HiddenField,CreateDiv,Blockquote,Language,Link,Unlink,Anchor,Flash,Smiley,PageBreak,Iframe,ShowBlocks,Maximize,About,Paste,PasteText,PasteFromWord,Undo,Redo,Replace,SelectAll,CopyFormatting,RemoveFormat,Styles,Format,Font,FontSize,TextColor,BGColor,NumberedList,BulletedList,Outdent,Indent,BidiLtr,BidiRtl,Table,HorizontalRule,SpecialChar";
config.language = "zh-cn";
config.image_previewText = " ";
config.exportPdf_tokenUrl = " ";
config.removeDialogTabs = "html5video:advanced;image:advanced;image:Link"; //隐藏“超链接”与“高级选项”只留上传和预览按钮
config.extraPlugins = "uploadimage,editorplaceholder";
config.filebrowserImageUploadUrl = ""; //上传图片的服务器地址
//config.filebrowserHtml5videoUploadUrl = ""; //上传视频的服务器地址";
config.removePlugins = "elementspath,easyimage,cloudservices"; //隐藏左下角提示
config.allowedContent = true; //允许所有标签
};

上传图片转Base64

默认的编辑器配置是支持粘贴的图片自动转Base64的

我们想点击图片上传按钮后选中图片确定也用base64保存,就要自定义插件。

plugins文件夹下添加zimage文件夹

添加以下文件

  1. plugins/zimage/plugin.js
  2. plugins/zimage/dialog/dialog.js
  3. plugins/zimage/icons/zimage.png

注意其中

第1项名称不能变。

第3项的图片名称要和定义插件时指定的名称相同,建议使用插件的名称。

plugins/zimage/plugin.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CKEDITOR.plugins.add('zimage', {
icons: 'zimage',
init: function (editor) {
// 给自定义插件注册一个调用命令
editor.addCommand('zimage', new CKEDITOR.dialogCommand('zimageDialog'));

editor.ui.addButton('zimage', {
// label为鼠标悬停时展示的字
label: '添加图片',
command: 'zimage',
// 将插件放在哪一组toolbar, 像我这样写的话,将放在'insert'组的第一个,后面的数字是这个数据的下标
toolbar: 'insert,0'
});
// 加载自定义窗口,'zimageDialog'跟上面调用命令的'zimageDialog'一致;
CKEDITOR.dialog.add('zimageDialog', this.path + 'dialog/dialog.js');
}
});

plugins/zimage/dialog/dialog.js

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
CKEDITOR.dialog.add('zimageDialog', function (editor) {
return {
title: '上传本地图片',
minWidth: 400,
minHeight: 100,
contents: [
{
id: 'Upload',
label: '上传',
elements: [
// 我这里需要一个tab页面,所以elements数组只有一个对象
{
// type为html表示html代码
type: 'html',
// 接下来html属性就可以直接写html代码了
html: '<div>'
+ '<label for="zfileupload">选择图片:</label>'
+ '<input type="file" name="zfileupload" id="zfileupload">'
+ '</div>',
// 那要怎么拿到自定义窗口的元素呢?在ckeditor自带的自定义窗口里并不容易拿到,这时候我们得用到onLoad函数了
onLoad: function () {
// 在自定义窗口展示的时候会触发这条函数;而我们就能在这条函数里写我们的代码了;
var ele = document.getElementById('zfileupload');
// 给id为'zfileupload'的input绑定change事件
ele.addEventListener('change', function () {
// 当用户没选或者点取消的时候直接return
if (this.files.length == 0) return;
var imageData = this.files[0];
// 检测后缀名
var lastIndex = imageData.name.lastIndexOf('.');
var imageSuffix = imageData.name.substring(lastIndex + 1);
// 判断后缀名
if (!(imageSuffix == 'png' || imageSuffix == 'jpg' || imageSuffix == 'jpeg' || imageSuffix == 'bmp')) {
alert('图片格式只支持"png/jpg/jpeg/bmp格式"');
return
}
// 大小不能超过1m
if (imageData.size > 5 * 1024 * 1024) {
alert('图片大小不能超过5M');
return
}
// 使用FileReader接口读取图片
var reader = new FileReader();
reader.addEventListener('load', function () {
var imageBase64 = reader.result;
sessionStorage.setItem('z_image', imageBase64)
})
// 将图片转成base64格式
reader.readAsDataURL(imageData)
})
}
}
]
}
],
onOk: function () {
// this这里就是自定窗口了,ckeditor内部封装好了。
var dialog = this;
// 创建img标签
var image = editor.document.createElement('img');
// 给img标签设置class类
image.setAttribute('class', 'insert-image');
var imageData = sessionStorage.getItem('z_image');
// 将图片数据赋予img标签
image.setAttribute('src', imageData);
// 利用ckeditor提供的接口将标签插入到富文本框中
editor.insertElement(image);
},
};
});

config.jsextraPlugins添加我们的插件名

如下

1
2
3
4
5
6
7
8
9
10
11
12
CKEDITOR.editorConfig = function (config) {
config.removeButtons = "Source,Save,NewPage,ExportPdf,Preview,Print,Templates,Cut,Copy,Find,Scayt,Form,Checkbox,Radio,TextField,Textarea,Select,Button,ImageButton,HiddenField,CreateDiv,Blockquote,Language,Link,Unlink,Anchor,Flash,Smiley,PageBreak,Iframe,ShowBlocks,Maximize,About,Paste,PasteText,PasteFromWord,Undo,Redo,Replace,SelectAll,CopyFormatting,RemoveFormat,Styles,Format,Font,FontSize,TextColor,BGColor,NumberedList,BulletedList,Outdent,Indent,BidiLtr,BidiRtl,Table,HorizontalRule,SpecialChar";
config.language = "zh-cn";
config.image_previewText = " ";
config.exportPdf_tokenUrl = " ";
config.removeDialogTabs = "html5video:advanced;image:advanced;image:Link"; //隐藏“超链接”与“高级选项”只留上传和预览按钮
config.extraPlugins = "uploadimage,editorplaceholder,zimage";
config.filebrowserImageUploadUrl = ""; //上传图片的服务器地址
//config.filebrowserHtml5videoUploadUrl = ""; //上传视频的服务器地址";
config.removePlugins = "elementspath,easyimage,cloudservices"; //隐藏左下角提示
config.allowedContent = true; //允许所有标签
};

DIV获取焦点

div在正常情况下是无法获得焦点的,而我们常用的blur()和focus()多是常用于input,对于div都是没有用的。让一个div获取焦点,其解决方案如下:

增加:tabindex = "-1"
如:

1
<div class="icon-change" tabindex="-1" @blur="colorShow"></div>

然后继续写失焦和聚焦事件就好了。

tabindex属性:

  1. html中的tabIndex属性可以设置键盘中的TAB键在控件中的移动顺序,即焦点的顺序。把控件的tabIndex属性设成1到32767的一个值,就可以把这个控件加入到TAB键的序列中。
  2. 当浏览者使用TAB键在网页控件中移动时,将首先移动到具有最小tabIndex属性值的控件上,最后在具有最大tabIndex属性值的控件上结束移动。
  3. 如果有两个控件的tabIndex属性相同,则以控件在html代码中出现的顺序为准。
  4. 默认的tabIndex属性为 0,将排列在在所有指定tabIndex的控件之后。
  5. 而若把tabIndex属性设为一个负值(如tabIndex="-1"),那么这个链接将被排除在TAB键的序列之外。
  6. 注意:如果使用-1值时,onfocus与onblur事件仍被启动。

如果想让编辑器鼠标移开自动取消焦点可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dom_scroll_event() {
let card = document.querySelector(".card");
let lasttime = new Date().getTime();
card.onscroll = function() {
let nowtime = new Date().getTime();
if (nowtime - lasttime > 500) {
let div_first = document.querySelector("div");
if (div_first) {
div_first.setAttribute("tabindex", "-1");
div_first.focus();
}
}
lasttime = nowtime;
};
},

触发事件

触发事件

1
2
3
4
5
6
7
8
9
10
11
12
13
function FireEvent(elem, eventName) {
if (typeof elem == "object") {
eventName = eventName.replace(/^on/i, "");
if (document.all) {
eventName = "on" + eventName;
elem.fireEvent(eventName);
} else {
var evt = document.createEvent("HTMLEvents");
evt.initEvent(eventName, true, true);
elem.dispatchEvent(evt);
}
}
}

调用

1
FireEvent(document.getElementById('id'), 'change')

HTML处理

1
let newhtml = data.html.replace(/<(?!img|p|\/p).*?>/g, "");

常见错误

1
Error code: pastetools-unsupported-image. {type: 'image/wmf', index: 0}