自定义富文本编辑器(模拟飞书信息发送框)_elementui


<template>
<div class="home" :style="{ height: height }">
<div class="rightCon" :style="{ height: height }">
<img style="display: none" class="welcome" src="./welcome.png" />
<div class="sendmegCon">
<span v-if="fuWenShow">
<Button
size="small"
onclick="javascript:document.execCommand('bold')"
>
加粗
</Button>
<Button
size="small"
onclick="javascript:document.execCommand('underline')"
>
下划线
</Button>
<Button
size="small"
onclick="javascript:document.execCommand('copy')"
>
复制
</Button>
<Button
size="small"
onclick="javascript:document.execCommand('indent')"
>
缩进
</Button>
<Button
size="small"
onclick="javascript:document.execCommand('italic')"
>
斜体
</Button>
<Button
size="small"
onclick="javascript:document.execCommand('undo')"
>
撤销
</Button>
<Select
v-model="fontSize"
@on-change="fontSizeChange"
placeholder="字号"
size="small"
style="width: 70px"
>
<Option value="1">10</Option>
<Option value="2">12</Option>
<Option value="3">16</Option>
<Option value="4">18</Option>
<Option value="5">24</Option>
<Option value="6">32</Option>
<Option value="7">48</Option>
</Select>
</span>
<span v-if="userShow">
<span class="atUser" @click="userClick('张三')">张三</span>
<span class="atUser" @click="userClick('李四')">李四</span>
<span class="atUser" @click="userClick('王五')">王五</span>
<span class="atUser" @click="userClick('张六')">张六</span>
<span class="atUser" @click="userClick('刘八')">刘八</span>
</span>
<span v-if="emojShow">
<img
v-for="(item, index) in 12"
@click="emojClick(index + 1)"
:src="'emoj/' + (index + 1) + '.png'"
class="emoj"
/>
</span>
<div>
<pre
spellcheck="true"
id="content"
class="lark-editor lark-empty"
contenteditable="true"
data-text="发送给 飞书助手"
></pre>
</div>
<span class="sendButton">
<Tooltip content="发送消息" placement="top">
<Icon @click="sendMegClick" type="md-paper-plane" size="20" />
</Tooltip>
<Tooltip content="表情" placement="top">
<Icon type="md-happy" @click="emojShowClick" size="20" />
</Tooltip>
<Tooltip content="添加图片" placement="top">
<Icon type="md-add-circle" @click="imgupload" size="20" />
</Tooltip>
<Tooltip content="选择成员" placement="top">
<Icon type="md-at" @click="userShowClick" size="20" />
</Tooltip>

<Tooltip content="富文本消息" placement="top">
<Icon type="logo-chrome" @click="fuWenShowClick" size="20" />
</Tooltip>
</span>
</div>
<div class="rightTop">
<div class="appItem">
<span class="imgCon">
<img :src="'./icon/' + 1 + '.png'" />
</span>

<div>
<div>智能人事</div>
<div>消息</div>
</div>
</div>

<div class="righttopright">
<Icon type="ios-videocam" />
<Icon type="ios-contacts" />
<Icon type="md-checkmark" />
</div>
</div>

<div
class="rightContent"
id="rightContent"
:style="{ height: megHeight }"
>
<div class="message" v-for="item in 3">
<div class="messageIcon">
<img src="./icon/4.png" />
</div>
<div class="messageInfo">
<div class="messageUser">
飞书助手
<span class="megDate">2022年05月20日&nbsp;08:49</span>
</div>
<div class="messageContent">
你好!我是你的飞书助手
????你可以向我提问,试试输入问题或关键词,我会努力回答或转人工客服。当然,你也可以在帮助中心查看更多实用教程哦!点击左上角“头像”-“我的客服”,可以随时找到我,为了保护您的隐私,请您反馈问题时进行信息保密。
</div>
</div>
</div>

<div class="message" v-for="item in megArr">
<div class="messageIcon">
<img src="./icon/4.png" />
</div>
<div class="messageInfo">
<div class="messageUser">
飞书助手
<span class="megDate">2022年05月20日&nbsp;08:49</span>
</div>
<div v-html="item.info" class="messageContent"></div>
</div>
</div>
</div>
</div>
<div class="leftCon" :style="{ height: height }">
<div class="handlerLine">
<Input v-model="searchValue" placeholder="搜索" style="width: 310px">
<span slot="append">
<Icon type="ios-search" />
</span>
</Input>
</div>

<div class="appsCon">
<div
@click="appClick"
class="appItem"
v-for="(item, index) in appNames"
>
<span class="imgCon">
<img :src="'./icon/' + (index + 1) + '.png'" />
<span class="huiBiao">2</span>
</span>

<div>
<div>{{ item }}</div>
<div>卡片消息</div>
</div>
<div class="date">2022年2月1日</div>
</div>
</div>
</div>

<input type="file" style="display: none" id="file" />
</div>
</template>

<script>
export default {
name: "Home",
data() {
return {
// 字号
fontSize: 0,
// 页面高度
height: 0,
// 消息容器高度
megHeight: 0,
// 搜索输入值
searchValue: "",
// 应用选中
appActiveType: "",
// 输入框DOM
contentPre: "",
// 消息容器Dom
rightContentDom: "",
// 表情展示
emojShow: false,
// 用户展示
userShow: false,
// 富文本消息展示
fuWenShow: false,
// 消息集合
megArr: [],
// 上传文件input
fileDom: "",
appTypeArr: [
"全部",
"综合OA",
"客户服务",
"设计工具",
"综合人事",
"办公管理",
"综合财务",
"生产效率",
"项目管理",
"安全合规",
"商旅出行",
"待办工具",
"员工激励",
"工商法律",
"电子办公",
],
appNames: [
"众阳团队",
"智能人事",
"管理员小助手",
"工作台助手",
"红包助手",
],
};
},
mounted() {
var that = this;
// 初始化页面高度
that.height = window.innerHeight + "px";
that.megHeight = window.innerHeight - 150 + "px";
that.contentPre = document.querySelector("#content");
that.contentPre.innerHTML = "请输入";
that.contentPre.addEventListener(
"focus",
function (event) {
if (that.contentPre.innerHTML == "请输入") {
that.contentPre.innerHTML = "";
}
},
false
);
that.contentPre.addEventListener(
"keydown",
function (event) {
if (event.keyCode == "13" && event.shiftKey) {
// var range = window.getSelection().getRangeAt(0);
// var p=document.createElement("p")
// p.style.marginRight="10px"
// range.insertNode(p);
// // that.contentPre.blur();
// // that.contentPre.focus();
// return false
}
if (event.keyCode == "13" && !event.shiftKey) {
that.sendMegClick();
return false;
}
},
false
);

that.rightContentDom = document.querySelector("#rightContent");
that.fileDom = document.querySelector("#file");

that.fileDom.addEventListener("change", function (e) {
var filesList = that.fileDom.files;
if (filesList.length == 0) {
//如果取消上传,则上传文件的长度为0
console.log("没有上传任何文件");
return;
} else {
//如果有文件上传,这在这里面进行
console.log(filesList);
var reader = new FileReader();
reader.onload = function (e) {
var imgBase = reader.result; //这个就是base64的编码
that.imguploadClick(imgBase);
};
reader.readAsDataURL(filesList[0]);
}
});
},
methods: {
fontSizeChange(val) {
document.execCommand("fontSize", false, val);
},
imgupload() {
let that = this;
that.fileDom.click();
},
imguploadClick(imgSrc) {
let that = this;
if (that.contentPre.innerHTML == "请输入") {
that.contentPre.innerHTML = "";
}
that.contentPre.innerHTML += `<img src="${imgSrc}" class="uploadImg">`;
},
userClick(name) {
let that = this;
if (that.contentPre.innerHTML == "请输入") {
that.contentPre.innerHTML = "";
}
that.contentPre.innerHTML += `<span class="atUserBlue">@${name}</span>&nbsp;`;
that.userShow = false;
},
emojClick(i) {
let that = this;
if (that.contentPre.innerHTML == "请输入") {
that.contentPre.innerHTML = "";
}
that.contentPre.innerHTML += `<img src="emoj/${i}.png" class="emoj">`;
that.emojShow = false;
},
fuWenShowClick() {
this.fuWenShow ? (this.fuWenShow = false) : (this.fuWenShow = true);
},
userShowClick() {
this.userShow ? (this.userShow = false) : (this.userShow = true);
},
emojShowClick() {
this.emojShow ? (this.emojShow = false) : (this.emojShow = true);
},
appTypeClick(num) {
this.appActiveType = num;
},
appClick() {},
sendMegClick() {
let that = this;
if (
that.contentPre.innerHTML == "" ||
that.contentPre.innerHTML == "请输入"
) {
return;
}

that.megArr.push({
info: that.contentPre.innerHTML.replaceAll("\n", "<br>"),
});
that.contentPre.innerHTML = "请输入";
that.contentPre.blur();
that.$nextTick(() => {
that.rightContentDom.scrollTop = 10000000000;
});
},
},
};
</script>

<style scoped>
.rightContent {
overflow: auto;
}
pre {
outline: none;
padding: 0;
overflow-x: hidden;
width: 100%;
margin: 0px;
white-space: pre-wrap;
overflow-wrap: break-word;
}
.sendButton {
display: block;
position: absolute;
right: 40px;
bottom: 33px;
width: 100px;
height: 20px;
}

.sendmegCon {
background: white;
position: absolute;
width: 100%;
bottom: 0px;
left: 0px;
padding: 20px;
padding-top: 5px;
font-variant-ligatures: none;
}
.sendmegCon > div {
border: 1px solid #dde0e3;
border-radius: 12px;
min-height: 45px;
padding-top: 12px;
padding-bottom: 12px;
padding-left: 20px;
padding-right: 120px;
}
.messageIcon {
width: 30px;
height: 30px;
}
.messageContent {
background: #eef0f1;
padding: 12px;
border-radius: 12px;
color: black;
font-size: 12px;
font-weight: initial;
word-break: break-all;
}

.messageInfo {
flex: 1;
padding: 10px;
padding-top: 5px;
}
.messageUser {
font-size: 13px;
color: #8f959e;
margin-bottom: 5px;
}
.megDate {
font-size: 12px;
margin-left: 10px;
}
.messageIcon img {
width: 30px;
height: 30px;
border-radius: 100%;
}
.message {
padding: 20px;
padding-bottom: 0px;
display: flex;
margin-right: 120px;
background: white;
}
.rightTop {
border-bottom: 1px solid #dce0e2;
}
.rightTop .appItem {
float: left;
}
.rightTop .appItem:hover {
background: white;
}
.rightTop::after {
content: "";
display: block;
clear: both;
}
.righttopright {
float: right;
font-size: 20px;
padding-right: 20px;
line-height: 60px;
}
.welcome {
width: 180px;
height: 180px;
position: absolute;
left: 50%;
top: 50%;
margin-left: -90px;
margin-top: -90px;
}
.rightCon {
margin-left: 350px;
position: relative;
padding-top: 1px;
}
.date {
text-align: right;
color: #8f969f;
padding-right: 10px;
}
.handlerLine {
height: 64px;
line-height: 64px;
background: #fff;
padding: 18px;
}
.mianbaoCon .mianBao:not(:last-child)::after {
content: "/";
margin-left: 10px;
}
.mianbaoCon {
padding: 18px;
}
.mianbaoCon .mianBao:first-child {
padding-left: 0px;
}
.mianbaoCon .mianBao {
display: inline-block;
padding-left: 14px;
color: #636b73;
cursor: pointer;
}
.appItem {
display: flex;
align-items: center;
height: 60px;
width: 350px;
}
.leftCon {
width: 350px;

border-right: 1px solid #dce0e2;
position: absolute;
left: 0px;
top: 0px;
overflow: auto;
}
.appsCon::after {
content: "";
display: block;
clear: both;
}
.appsCon {
padding-top: 0px;
cursor: pointer;
}
.appItem:hover {
background: #dee0e3;
}
.appItem img {
width: 30px;
height: 30px;
border-radius: 100%;
}

.imgCon {
width: 30px;
height: 30px;
margin-left: 15px;
margin-right: 10px;
position: relative;
}
.appItem > div {
flex: 1;
}
.appItem > div div:first-child {
color: black;
font-size: 14px;
font-weight: 600;
word-break: break-all;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
}
.appItem > div div:last-child {
color: #8f969f;
font-size: 12px;
line-height: 18px;
word-break: break-all;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
}
.home {
background: white;
padding-left: 0px;
position: relative;
}
.huiBiao {
position: absolute;
right: -5px;
top: -5px;
height: 15px;
text-align: center;
min-width: 15px;
line-height: 15px;
display: inline-block;
border-radius: 12px;
font-size: 12px;
background: #f54a45;
color: white;
}
</style>