效果图
直接把完整组件拿出来,使用时候自己看好接口干嘛的,对应上
<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
type="primary"
@click="discern()"
icon="el-icon-view"
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>
<!-- <el-row>
<el-col :span="12"> <div id="editor"></div></el-col>
<el-col :span="12">
预览
<hr />
<div class="html" v-html="contentEditor"></div
></el-col>
</el-row> -->
<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 { getToken } from "@/utils/auth";//获取请求头
import { uploadPath } from "@/api/upload";//上传文件的地址
import { alllist } from "@/api/business/sensitiveWord";//获取敏感词列表
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() {
// console.log(this.contentHtml,"传参内容");
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 = [
"#333333",
"#1c487f",
"#eeece0",
"#4d80bf",
"#ffffff",
"#FF0000",
"#00FF00",
" #0000FF",
"#FF00FF",
"#FFFF00",
"#70DB93",
"#5C3317",
];
// *****************************************************
// 配置字体
this.editor.config.fontNames = [
// 字符串形式
// "仿宋",
// "黑体",
// "楷体",
// "标楷体",
// "华文仿宋",
// "华文楷体",
// "宋体",
"微软雅黑",
"Microsoft YaHei",
// "Times New Roman",
// "Arial",
// "Tahoma",
// "Verdana",
// "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) => {
// 对粘贴的文本进行处理
// sss = false;
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 = 8 * 1024 * 1024; // 8M
// 如果不希望限制类型,可将其设为空数组:
this.editor.config.uploadImgAccept = [];
this.editor.config.uploadImgMaxLength = 3; // 一次最多上传 5 个图片
// console.log(uploadPath, "请求地址");
this.editor.config.uploadImgServer = uploadPath; // 上传图片的接口地址
this.editor.config.uploadFileName = "file"; // formdata中的name属性
// this.editor.config.debug = true; // 开启debug模式
this.editor.config.uploadImgHeaders = {
Authorization: getToken(), // 设置请求头
};
this.editor.config.uploadImgHooks = {
// 图片上传并返回结果,但图片插入错误时触发
fail: function (xhr, editor, result) {
// console.log(xhr, "插入错误时触发 xhr");
// console.log(editor, "插入错误时触发 editor");
// console.log(result, "插入错误时触发 result");
},
success: function (xhr, editor, result) {
// 图片上传并返回结果,图片插入成功之后触发
// console.log(xhr, editor, result, "成功之后触发");
},
before: function (xhr, editor, files) {
// 图片上传之前触发
// xhr 是 XMLHttpRequst 对象,editor 是编辑器对象,files 是选择的图片文件
// 如果返回的结果是 {prevent: true, msg: 'xxxx'} 则表示用户放弃上传
// console.log(xhr, editor, files, "图片上传之前触发");
},
error: function (xhr, editor) {
// console.log(xhr.response, editor, "图片上传出错时触发");
},
// 图片上传并返回了结果,想要自己把图片插入到编辑器中
// 例如服务器端返回的不是 { errno: 0, data: [...] } 这种格式,可使用 customInsert
customInsert: function (insertImgFn, result) {
// result 即服务端返回的接口
// insertImgFn 可把图片插入到编辑器,传入图片 src ,执行函数即可
insertImgFn(result.data.full);
},
};
// *********************上传本地视频******************************
this.editor.config.uploadVideoServer = uploadPath; // 上传的接口地址
this.editor.config.uploadVideoParams = {
'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundarycZm1pHksXeHS6t5r'
}
this.editor.config.uploadVideoHeaders = {
Authorization: getToken(), // 设置请求头
};
let this_ = this
this.editor.config.uploadVideoName = "file";
this.editor.config.uploadVideoHooks = {
// 上传完成处理方法
fail: (xhr, editor, result) => {
// 插入图片失败回调
},
success: (xhr, editor, result) => {
// 图片上传成功回调
},
timeout: (xhr, editor) => {
// 网络超时的回调
},
error: (xhr, editor) => {
// 图片上传错误的回调
console.log("err--->", xhr);
},
customInsert: function (insertVideo, result) {
console.log("result--->", result);
const link = result.data.full;
insertVideo(link)
},
};
// ***********************创建富文本***************
this.editor.config.onchange = (html) => {
this.contentEditor = html;
this.sentContent();
};
this.editor.config.onfocus = (html) => {
if (this.isignore) {
// console.log("有标识,不识别");
this.sendIskeyword();
this.contentEditor = html;
} else {
// console.log("没有标识,要识别");
// console.log(html);
this.changIsignore(html);
}
this.sentContent();
};
this.editor.create();
// 初始化
this.$nextTick(() => {
if (this.contentEditor) {
// console.log("初始化");
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) {
// console.log("有标识,不识别");
this.sendIskeyword();
this.contentEditor = this.contentEditor;
} else {
// console.log("没有标识,要识别");
this.changIsignore(this.contentEditor);
}
},
concal() {
this.lookSEE = false;
},
changIsignore(html) {
//处理忽略敏感词
// console.log("处理忽略敏感词");
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>
/* #editor {
width: 50%;
} */
#contentEditor {
width: 900px;
}
.html {
/* width: 50%; */
margin-top: 20px;
height: 100%;
min-height: 70vh;
}
.wrap {
/* position: absolute; */
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>