<template>
<div class="edit-container">
<div id="myEditor" ref="myEditor" contenteditable="true" @blur="getBlur()" @keyup="statisticsNum()" />
<div class="flex-between-center bottom-btn">
<div class="flex-start-center">
<div class="button" @click="openEmoji">插入表情</div>
<div class="button" @click="addLink">插入超链接</div>
<div class="button" @click="addMiniprogramLink">插入小程序</div>
</div>
<div class="statistics">已输入{{ total }}字</div>
</div>
<div v-if="isOpenEmoji" class="emoji-content">
<div v-for="(item, index) in emojiList" :key="index" class="emoji-item" @click="addEmoji(index)">{{ item }}</div>
</div>
</div>
</template>
<script>
import emojiData from './emoji.json';
let sel;
let range;
export default {
data() {
return {
total: 0,
emojiList: [],
isOpenEmoji: false
};
},
methods: {
// 字数统计
statisticsNum() {
const limitText = this.$refs.myEditor.innerHTML;
const limitLen = limitText.length;
if (limitText === '') {
this.$refs.myEditor.blur();
} else {
// this.setFocus($('#myEditor'));
}
this.total = limitLen;
},
// 获取全部表情
getEmoji() {
for (const i in emojiData) {
this.emojiList.push(emojiData[i].char);
}
},
openEmoji() {
this.isOpenEmoji = !this.isOpenEmoji;
},
// 添加表情
addEmoji(index) {
for (const i in this.emojiList) {
if (index === Number(i)) {
const face = this.emojiList[index] + ' ';
this.insertHtml(face);
}
}
},
// 插入超链接
addLink() {
const link = `<a target='_blank' contenteditable='false' href='https://www.baidu.com/'>超链接(百度)</a>`;
this.insertHtml(link);
},
// 插入小程序
addMiniprogramLink() {
const link = `<a target='_blank' contenteditable='false' href='https://www.baidu.com/' data-miniprogram-appid='111' data-miniprogram-path='https://www.baidu.com/'>虚拟小程序</a>`;
this.insertHtml(link);
},
// 作用:失去焦点时获取光标的位置
getBlur() {
sel = window.getSelection();
if (sel && sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
// range.deleteContents();
}
},
// 作用:在contenteditable="true"文本框光标处插入内容
insertHtml(html) {
// IE9 and non-IE
if (window.getSelection) {
if (sel && sel.getRangeAt && sel.rangeCount) {
const el = document.createElement('div');
el.innerHTML = html;
const frag = document.createDocumentFragment();
let node, lastNode;
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
if (lastNode) {
range = range.cloneRange();
range.setStartAfter(lastNode);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
}
} else if (document.selection && document.selection.type !== 'Control') {
// IE < 9
document.selection.createRange().pasteHTML(html);
}
this.statisticsNum();
},
// 作用:设置光标始终在文本最后
// 情景:利用contenteditable=”true”模拟输入框时,focus()方法会将光标定位在文本的首位,需要将光标挪到最后一位
// 注意:根据实际情况判断是否需要这段代码
setFocus(el) {
el = el[0]; // jquery 对象转dom对象
el.focus();
range = document.createRange();
range.selectNodeContents(el);
range.collapse(false);
sel = window.getSelection();
// 判断光标位置,如不需要可删除
if (sel.anchorOffset !== 0) {
return;
}
sel.removeAllRanges();
sel.addRange(range);
}
},
created() {
this.getEmoji();
}
};
</script>
<style scoped>
.flex-between-center {
display: flex;
justify-content: space-between;
align-items: center;
}
.flex-start-center {
display: flex;
justify-content: start;
align-items: center;
}
.edit-container {
position: relative;
width: 500px;
height: 300px;
background: #859ffc;
border: 1px solid #EBEEF5;
margin: 20px;
font-size: 12px;
}
#myEditor {
box-sizing: border-box;
width: 460px;
height: 230px;
background: #fff;
margin: 20px auto 0;
padding: 10px;
line-height: 18px;
}
.bottom-btn {
box-sizing: border-box;
width: 460px;
height: 30px;
background: #fff;
margin: 0 auto;
padding: 0 10px;
border-top: 1px solid #EBEEF5;
}
.button {
margin-right: 10px;
color: #57e;
cursor: pointer;
}
.statistics {
color: #999;
}
.emoji-content {
width: 220px;
height: 280px;
background: #fff;
border: 1px solid #EBEEF5;
border-radius: 4px;
position: absolute;
top: 0px;
left: 502px;
display: flex;
flex-wrap: wrap;
padding: 10px;
overflow: auto;
}
.emoji-item {
width: 14%;
font-size: 18px;
list-style: none;
text-align: center;
cursor: pointer;
}
</style>