header-bg.jpg
Vue中制作可以插入emoji表情的聊天输入框组件
发表于 2019-04-13 01:49
|
分类于 JavaScript
|
评论次数 24
|
阅读次数 3143

vincent.jpg

一般在网页中见到的文本输入框的添加表情功能都是在用户选定表情后, 在文本域中插入特定的字符代表一个表情, 例如:smile代表一个微笑, 作为用户的我, 体验起来就很不舒适, 我就喜欢QQ聊天框这种, 能够实时能够看到表情在输入框中被渲染出来的效果, 所以在我自己写项目的时候, 直接就把这个功能实现了, 下面讲解我是如何在Vue项目中实现文本域预览emoji表情这个功能的.

Emoji表情库

巧妇难为无米之炊, 造这个轮子第一步就是需要找到很多emoji表情, 不然该如何下手呢?我找到了这个网站, 非常给力, 拥有所有平台实现emoji表情以及对应的unicode编码, 传送门

template

在模板中使用v-for将emoji渲染出来, 我没有使用textarea标签, 是因为textarea不能自适应高度, 如果要自适应高度, 又需要一个轮子, 所以干脆直接使用div的contenteditable属性, 来模拟一个textarea好了

<template>
    <div class="area-box">
        <div ref="area"  contenteditable="true"></div>
        <div class="send-box">
            <i @click="emoji_show = !emoji_show"></i>
            <div v-show="emoji_show" class="emotion-box">
                <div class="emotion-list">
                    <i v-for="v in emoji" @click="addEmoji(v)">{{v}}</i>
                </div>
            </div>
        </div>
    </div>
</template>

script

主要问题在于如何在点击每个emoji表情字符时, 在文本域中光标所在位置插入相应的emoji字符, 以及插入字符后, 如何将光标定位正确, addEmoji就是我的实现方法, 详细的注释在每行都写了, 没有太大难度

<script>
    export default {
        data() {
            return {
                emoji_show: false,
                emoji: ["😀", "😃", "😄", "😁", "😆", "😅", "🤣", "😂"],
            }
        },
        methods: {
            addEmoji(str) {
                let area = this.$refs.area;
                if (document.selection) {
                    area.focus();
                    const sel = document.selection.createRange();
                    sel.text = str;
                    sel.select();
                } else if (area.selectionStart || area.selectionStart === '0') {// Mozilla/NETSCAPE support
                    const startPos = area.selectionStart,
                        endPos = area.selectionEnd,
                        // save scrollTop before insert
                        restoreTop = area.scrollTop;
                    area.innerText = area.innerText.substring(0, startPos) + str + area.innerText.substring(endPos, area.innerText.length);
                    if (restoreTop > 0) {
                        // restore previous scrollTop
                        area.scrollTop = restoreTop;
                    }
                    area.focus();
                    area.selectionStart = startPos + str.length;
                    area.selectionEnd = startPos + str.length;
                } else {
                    const selection = window.getSelection();

                    // .nodeName === '#text'
                    if (selection.anchorNode && selection.anchorNode.nodeType === 3 && selection.anchorNode.parentNode === area) {// 光标选中
                        const range = selection.getRangeAt(0),
                            rangeStartOffset = range.startOffset,// 获取光标位置
                            textNode = range.startContainer;

                        if (!range.collapsed) {// 不是同一位置 代表选择了内容 则先删除选择的内容
                            range.deleteContents();
                        }

                        textNode.insertData(rangeStartOffset, str);// 文本节点在光标位置处插入新的表情内容
                        range.setStart(selection.anchorNode, rangeStartOffset + str.length);// 光标移动到表情的后面, 1个emoji的长度并不固定
                        range.collapse(true);// 光标开始和光标结束重叠
                        selection.removeAllRanges();// 清除选定对象的所有光标对象
                        selection.addRange(range);// 插入新的光标对象
                    } else {// 未出现光标 直接点击表情 默认插入最后位置
                        area.innerText += str;
                        selection.selectAllChildren(area);// 选择编辑器
                        selection.collapseToEnd();// 光标移动至最后
                    }
                }
            },
        },

    }
</script>

完整聊天框组件

以上的代码是关于核心功能的实现, 还有一些样式, 细节问题相关的代码非常多, 并没有展示出来, 我对此已经封装好了一个开箱即用的聊天框组件, 如果你觉得像我这样自己动手造轮子很麻烦, 那完全可以用我已封装好的这个组件:

github传送门

安装

// 命令行
cnpm install vue-area

// main.js中:
import Editor from 'vue-area';
Vue.use(Editor);

使用


<editor :show="area" @send="send()" v-model="comment"></editor>

发布评论
评论
共计 24条评论
最新评论
2020-11-19 15:03:09哈哈[江苏省南京市网友]
啊啊啊啊
0
0
回复
2020-10-20 14:06:17[江苏省南京市网友]
0
0
回复
2020-10-14 17:48:00[上海市网友]
vue-area没用了,作者把这个包删了,后来又有作者用vue-area这个名字注册了,是个省市县的选择组件。这个作者的git上也删除了这个项目。
0
0
回复
2020-10-14 09:57:39聚焦[河北省廊坊市网友]
买买买
0
0
回复
2020-09-22 10:28:29112[广东省深圳市网友]
11
0
0
回复