项目需求是这样的:要求实现类似于微信聊天一样,表情+文字效果 “文字效果”

表情包三种方案

表情包的实现其实可以分为以下三种情况:

  1. 表情包:点击表情--直接发送大表情(这种方案其实就是发送了一张定义好的图片而已)
  2. emoji图标表情:系统可识别的emoji图标表情,这种表情实现起来相对麻烦一些,其实这种方法emoji我们可以当成一个2位字符的特殊文字去处理
    • 推荐emoji网址:emojis

      • 案例:禾蛙招聘网站
  3. 自定义表情:一版是设计画好的,需要我们实现文字+表情进行发送和回显的
    • 思路1:我们在点击单个表情的时候输入框内需要添加表情,这是输入框内表情可以用‘[微笑]‘这种方式代替。只有在回显的时候去识别特殊表示,再用表情去替换掉即可

      • 案例:BOSS直聘网站
    • 思路2:输入框也需要是表情的回显,这种方法就相对麻烦了一些
      • 案例:微信客户端

实现

这里针对自定义表情包的思路2,进行实现,个人认为也是最麻烦的实现

实现效果

这里只针对输入框进行实现,对于数据传递给后端,消息的回显这里就不进行阐述了,想必大家也有自己更好的设计方法。

1、布局

大家可能会想到输入区域可以用用input,或者是textarea标签,但针对‘文字+自定义图片表情’是不太适用的,不过对于其他的实现方案还是可行的。

实现思路

  • 采用div+ contenteditable="true"属性

    • 举例:'

      这是一个可编辑段落。

      '

contenteditable属性:

  • 属性指定元素内容是否可编辑。
  • 所有主流浏览器都支持 contenteditable 属性
  • 设置了true:该标签默认就存在了@fcous,@input等事件函数
  • 注意: 当元素中没有设置 contenteditable 属性时,元素将从父元素继承。
描述
true 指定元素是可编辑的
false 指定元素是不可编辑的
    <div
id="emojiText"
contenteditable="true"
ref="edit"
placeholder="请输入内容"
></div>

2、实现

这里实现思路包括三个方向:

  1. 添加表情,添加文字
  2. 获取输入的消息内容,传递给后端
  3. 拿到特殊消息体'[微笑]',渲染对应的表情

添加表情,添加文字

输入文字:单纯的输入文字其实很简单,思路就是可编辑区域可输入对应的文本内容

添加表情:实现思路是,再点击添加表情时就是讲表情地址生成<img>标签插入到可编辑区域内

添加表情存在的问题:

问题1:添加表情时光标不会聚焦到可编辑区域

问题2:添加表情无法添加到光标定位的位置上

问题1解决方案

添加表情时检查是否聚焦,无聚焦执行fcous强制聚焦

let obj = this.$refs.edit; // obj 是可编辑的div
let range, node;
if (!obj.hasfocus) {
obj.focus();
}

问题2解决方案

window.getSelection:选择的文本范围或光标的当前位置。

getRangeAt

返回选区开始的节点(Node)。

因为通常情况下用户只能选择一个范围,所以只有一个选区(range),此方法一般为getRangeAt(0)

range = window.getSelection().getRangeAt(0);
range.collapse(false); //光标移至最后 node = range.createContextualFragment(Img);
let c = node.lastChild;
range.insertNode(node);
if (c) {
range.setEndAfter(c);
range.setStartAfter(c);
}
let j = window.getSelection();
j.removeAllRanges();
j.addRange(range);

完整代码

<template>
<div>
<div
id="emojiText"
contenteditable="true"
ref="edit"
placeholder="请输入内容"
></div>
<ul>
<li v-for="item in emojis" :key="item.name">
<img :src="item.path" alt="" @click="getEmojis" />
</li>
</ul>
<button @click="senMsg">发送</button>
</div>
</template> <script>
export default {
components: {},
data() {
return {
emojis: [
{
name: "[emoji-1]",
path: require("./assets/emojis/m1.png"),
},
{
name: "[微笑]",
path: require("./assets/emojis/m2.png"),
},
{
name: "[emoji-3]",
path: require("./assets/emojis/m3.png"),
},
],
};
},
mounted() {},
methods: {
getEmojis(event) {
let Img = `<img src="${event.target.src}" style='height:10px;'>`; let obj = this.$refs.edit; // obj 是可编辑的div
let range, node;
if (!obj.hasfocus) {
obj.focus();
}
/*
window.getSelection:选择的文本范围或光标的当前位置。
getRangeAt
返回选区开始的节点(Node)。
因为通常情况下用户只能选择一个范围,所以只有一个选区(range),此方法一般为getRangeAt(0)
*/
if (window.getSelection && window.getSelection().getRangeAt) {
range = window.getSelection().getRangeAt(0);
range.collapse(false); //光标移至最后 node = range.createContextualFragment(Img);
let c = node.lastChild;
range.insertNode(node);
if (c) {
range.setEndAfter(c);
range.setStartAfter(c);
}
let j = window.getSelection();
j.removeAllRanges();
j.addRange(range);
} else if (document.selection && document.selection.createRange) {
document.selection.createRange().pasteHTML(Img);
}
},
senMsg() {
console.log(this.$refs.edit.innerHTML);
},
natchMsg() {
let str = "比如‘[微笑]’asdtgsaghd[微笑]ggg";
let newStr = str;
this.emojis.forEach((item) => {
console.log(str.indexOf(item.name));
if (str.indexOf(item.name) > -1) {
let Img = `<img src="${item.path}" style='height:10px;'>`;
newStr = str.replaceAll(item.name, Img);
}
});
console.log(newStr);
},
},
};
</script> <style lang='scss' scoped>
#emojiText {
width: 600px;
height: 300px;
border: 1px solid #111;
}
ul {
display: flex;
list-style: none;
}
li img {
width: 20px;
height: 20px;
}
.msgicon {
width: 10px;
height: 10px;
}
</style>

最新文章

  1. 5 构建Mysql+heartbeat+DRBD+LVS集群应用系统系列之生产环境下drbd裂脑处理
  2. 【oracle】oracle表结构导出到Word
  3. linux下配置安装python3
  4. safari 日期对象新建new Date( timeStr ) 参数TimeStr格式
  5. JVM性能监控与故障处理命令行工具
  6. Hadoop入门进阶课程1--Hadoop1.X伪分布式安装
  7. win7锁定到任务栏的路径在哪里
  8. 第4章 sed命令
  9. codevs1387
  10. [Luogu2617]Dynamic Rankings(整体二分)
  11. ruby簡單的代碼行統計工具
  12. [工具开发] Grafana 报警仪表盘
  13. leetcode1034
  14. [PHP] 常备的现代 PHP 项目开发准备
  15. anaconda安装win10
  16. 05-sudo权限配置
  17. html-文件上传设置accept类型延时问题
  18. Sentry项目监控工具结合vue的安装与使用(前端)
  19. NO--14 微信小程序,左右联动二
  20. Google C++单元测试框架之宏

热门文章

  1. C语言的return语句
  2. 复杂对象List集合的排序
  3. MySQL:提高笔记-3
  4. mongodb的简单查询
  5. IC封装的热特性
  6. NB-IoT的DRX、eDRX、PSM三个模式怎么用?通俗解释,看完就懂!
  7. 求树的直径【两遍BFS】
  8. 我的笔记本电脑瞬间扩大一个T的容量!
  9. C++中gSOAP的使用
  10. 记一次 php-fpm 连接 nginx 的错误。