效果图:
组件代码:
<template>
<div class="box">
<el-button
type="primary"
icon="el-icon-view"
style="cursor: pointer; margin-bottom: 20px"
@click="see()"
>预览</el-button
>
<el-button
v-if="!isignore"
type="primary"
@click="sensitive()"
icon="el-icon-view"
style="cursor: pointer; margin-bottom: 20px"
>一键忽略敏感词汇</el-button
>
<el-button
v-else
type="success"
icon="el-icon-check"
style="cursor: pointer; margin-bottom: 20px"
>已忽略敏感词汇</el-button
>
<el-button
v-if="isignore"
type="warning"
@click="again()"
icon="el-icon-close"
style="cursor: pointer; margin-bottom: 20px"
>解除忽略</el-button
>
<div id="editor"></div>
<div id="editorBox" v-if="lookSEE">
<el-dialog :visible.sync="lookSEE">
<el-dialog
width="1100px"
title="正文内容 > 效果预览"
:visible.sync="lookSEE"
append-to-body
@close="concal()"
>
<hr />
<div class="html" v-html="contentEditor"></div>
<div slot="footer" class="dialog-footer">
<el-button @click="concal()">取消</el-button>
</div>
</el-dialog>
</el-dialog>
</div>
</div>
</template>
<script>
import E from "wangeditor";
import { list, alllist } from "@/api/business/sensitiveWord";
// import keywords from "../assets/js/info"; //敏感词
export default {
data() {
return {
contentEditor: "",
lookSEE: false,
isignore: true,
ignore: '<i style="display: none;">已忽略敏感词</i>',
editor: undefined,
show: true,
ignoreChars:
" \t\r\n~!@#$%^&*()_+-=【】、{}|;':\",。、《》?αβγδεζηθικλμνξοπρστυφχψωΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ。,、;:?!…—·ˉ¨‘’“”々~‖∶"'`|〃〔〕〈〉《》「」『』.〖〗【】()[]{}ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩①②③④⑤⑥⑦⑧⑨⑩⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇≈≡≠=≤≥<>≮≯∷±+-×÷/∫∮∝∞∧∨∑∏∪∩∈∵∴⊥∥∠⌒⊙≌∽√§№☆★○●◎◇◆□℃‰€■△▲※→←↑↓〓¤°#&@\︿_ ̄―┌┍┎┐┑┒┓─┄┈├┝┞┟┠┡┢┣│┆┊┬┭┮┯┰┱┲┳┼┽┾┿╀╁╂╃└┕┖┗┘┙┚┛━┅┉┤┥┦┧┨┩┪┫┃┇┋┴┵┶┷┸┹┺┻╋╊╉╈╇╆╅╄",
ignoreObj: {},
keywords: [],//敏感词
sensitiveWords: undefined,
map: undefined,
iskeyword: false, //是否包含敏感词
queryParams: {},
};
},
props: {
contentHtml: {
type: String,
default() {
return "";
},
},
},
created() {
for (let i = 0, j = this.ignoreChars.length; i < j; i++) {
this.ignoreObj[this.ignoreChars.charCodeAt(i)] = true;
}
alllist(this.queryParams, this.$i18n.locale).then((response) => {
this.keywords = response.data;
// 获取敏感词库对象
this.map = this.buildMap(this.keywords);
});
if (this.contentHtml) {
this.contentEditor = this.contentHtml;
}
// 判断是否已经忽略敏感词汇
let reg = new RegExp(/<i style="display: none;">已忽略敏感词<\/i>/, "g");
this.isignore = reg.test(this.contentEditor);
},
mounted() {
this.editor = new E("#editor");
// 设置编辑区域高度为 300px
this.editor.config.height = 300;
// 编辑器 z-index 默认为 10000,可以自行调整。
this.editor.config.zIndex = 20;
// 可以修改 placeholder 的提示文字。
this.editor.config.placeholder = "请输入正文";
// 取消自动 focus
this.editor.config.focus = false;
// *****************************************************
this.editor.config.menus = [
"head",
"bold",
"fontSize",
"fontName",
"italic",
"underline",
"strikeThrough",
"indent",
"lineHeight",
"foreColor",
"backColor",
"link",
"list",
// "todo",
"justify",
"quote",
"emoticon",
"image",
"video",
"table",
// "code", // 插入代码
"splitLine",
"undo",
"redo",
];
// *****************************************************
// 配置颜色(文字颜色、背景色)
this.editor.config.colors = [
"#000000",
"#eeece0",
"#1c487f",
"#4d80bf",
"#ffffff",
"#FF0000",
"#00FF00",
" #0000FF",
"#FF00FF",
"#FFFF00",
"#70DB93",
"#5C3317",
];
// *****************************************************
// 配置字体
this.editor.config.fontNames = [
// 字符串形式
"仿宋",
"黑体",
"楷体",
"标楷体",
"华文仿宋",
"华文楷体",
"宋体",
"微软雅黑",
"Arial",
"Tahoma",
"Verdana",
"Times New Roman",
"Courier New",
];
// *****************************************************
// 设置字号,只能改变 name字段
this.editor.config.fontSizes = {
"x-small": { name: "14px", value: "1" },
small: { name: "16px", value: "2" },
normal: { name: "18px", value: "3" },
large: { name: "20px", value: "4" },
"x-large": { name: "22px", value: "5" },
"xx-large": { name: "24px", value: "6" },
"xxx-large": { name: "26px", value: "7" },
};
// 配置行高
this.editor.config.lineHeights = [
"1",
"1.25",
"1.5",
"1.75",
"2",
"2.5",
"3",
];
// *****************************************************
// 插入网络图片的回调
this.editor.config.linkImgCallback = function (src, alt, href) {
};
// *********************粘贴********************************
// 关闭粘贴样式的过滤
this.editor.config.pasteFilterStyle = false;
// 忽略粘贴内容中的图片
this.editor.config.pasteIgnoreImg = false;
// ************************敏感词 处理*****************************
// 粘贴文本识别敏感词
this.editor.config.pasteTextHandle = (pasteStr) => {
// 对粘贴的文本进行处理
let arr = this.checkSensitive(pasteStr);
if (arr) this.iskeyword = true;
arr.forEach((item, index) => {
var reg = new RegExp(item, "g");
pasteStr = pasteStr.replace(
reg,
` <span id="checkSensitive" style="background-color: rgb(250, 228, 34);">${item}<i style="color: rgb(250, 0, 0);font-style: italic;">[敏感词,请更改]</i></span> `
);
});
return pasteStr;
};
// *************************上传图片****************************
this.editor.config.showLinkImg = true; //上传网络图片
this.editor.config.uploadImgShowBase64 = true; //base64 保存图片
// 限制图片大小和类型
this.editor.config.uploadImgMaxSize = 2 * 1024 * 1024; // 2M
// // 如果不希望限制类型,可将其设为空数组:
this.editor.config.uploadImgAccept = [];
this.editor.config.uploadImgMaxLength = 3; // 一次最多上传 5 个图片
// ***********************创建富文本***************
this.editor.config.onchange = (html) => {
this.contentEditor = html;
this.sentContent();
};
this.editor.config.onfocus = (html) => {
if (this.isignore) {
this.sendIskeyword();
this.contentEditor = html;
} else {
this.changIsignore(html);
}
this.sentContent();
};
this.editor.create();
// 初始化
this.$nextTick(() => {
if (this.contentEditor) {
this.editor.txt.html(this.contentEditor);
}
});
},
methods: {
// 忽略功能
sensitive() {
this.isignore = true;
this.show = false;
// 给已经设置忽略的字符串添加标识 === 》 在this.contentEditor 最前面添加一个隐藏的i标签
this.contentEditor = this.ignore + this.contentEditor;
let reg = new RegExp(
/<i style="color: rgb\(250, 0, 0\);font-style: italic;">\[敏感词,请更改\]<\/i>/,
"g"
);
let reg1 = new RegExp(
/style="background-color: rgb\(250, 228, 34\);"/,
"g"
);
this.contentEditor = this.contentEditor.replace(reg1, "");
this.contentEditor = this.contentEditor.replace(reg, "");
this.editor.txt.html(this.contentEditor);
this.sentContent();
this.sendIskeyword();
},
// 向父组件传递富文本内容
sentContent() {
this.$emit("sentContent", this.contentEditor);
},
// 向父组件传递富文本是否包含敏感词
sendIskeyword() {
let reg = new RegExp(/\[敏感词,请更改\]/);
let val = reg.test(this.contentEditor);
this.$emit("sendIskeyword", val);
},
// 解除忽略
again() {
let reg = new RegExp(/<i style="display: none;">已忽略敏感词<\/i>/, "g");
this.contentEditor = this.contentEditor.replace(reg, "");
this.isignore = false;
this.changIsignore(this.contentEditor);
this.sendIskeyword();
},
// 预览
see() {
this.lookSEE = true;
if (this.isignore) {
this.sendIskeyword();
this.contentEditor = this.contentEditor;
} else {
this.changIsignore(this.contentEditor);
}
},
concal() {
this.lookSEE = false;
},
changIsignore(html) {
//处理忽略敏感词
let arr = this.checkSensitive(html);
arr.forEach((item, index) => {
var reg = new RegExp(item, "g");
html = html.replace(
reg,
` <span id="checkSensitive" style="background-color: rgb(250, 228, 34);">${item}<i style="color: rgb(250, 0, 0);font-style: italic;">[敏感词,请更改]</i></span> `
);
});
this.contentEditor = html;
this.editor.txt.html(this.contentEditor);
if (arr.length > 0) {
this.sendIskeyword();
} else {
this.sendIskeyword();
}
},
// 具体检测代码。
check(map, content) {
const result = [];
let stack = [];
let point = map;
for (let i = 0, len = content.length; i < len; ++i) {
const code = content.charCodeAt(i);
if (this.ignoreObj[code]) {
continue;
}
const ch = content.charAt(i);
const item = point[ch.toLowerCase()];
if (!item) {
i = i - stack.length;
stack = [];
point = map;
} else if (item.empty) {
stack.push(ch);
result.push(stack.join(""));
stack = [];
point = map;
} else {
stack.push(ch);
point = item;
}
}
return result;
},
buildMap(wordList) {
const result = {};
for (let i = 0, len = wordList.length; i < len; ++i) {
let map = result;
const word = wordList[i];
for (let j = 0; j < word.length; ++j) {
const ch = word.charAt(j).toLowerCase();
if (map[ch]) {
map = map[ch];
if (map.empty) {
break;
}
} else {
if (map.empty) {
delete map.empty;
}
map[ch] = {
empty: true,
};
map = map[ch];
}
}
}
return result;
},
checkSensitive(content) {
const words = this.check(this.map, content);
return words;
},
},
};
</script>
<style scoped>
#contentEditor {
width: 900px;
}
.html {
margin-top: 20px;
height: 100%;
min-height: 70vh;
}
.wrap {
width: 670px;
height: 300px;
line-height: 300px;
background-color: rgb(75, 73, 73);
color: #fff;
text-align: center;
}
.box {
position: relative;
}
/* 修改富文本字号 */
font[size="1"] {
font-size: 14px;
}
font[size="2"] {
font-size: 16px;
}
font[size="3"] {
font-size: 18px;
}
font[size="4"] {
font-size: 20px;
}
font[size="5"] {
font-size: 22px;
}
font[size="6"] {
font-size: 24px;
}
font[size="7"] {
font-size: 26px;
}
/* table 样式 必须加 否则表格没有样式 */
.html >>> table {
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
margin: 10px 0;
line-height: 1.5;
}
.html >>> table td,
.html >>> table th {
border-bottom: 1px solid #ccc;
border-right: 1px solid #ccc;
padding: 3px 5px;
min-height: 30px;
height: 30px;
}
.html >>> table th {
border-bottom: 2px solid #ccc;
text-align: center;
background-color: #f1f1f1;
}
</style>