Vue实现输入框@功能的示例代码

发布时间:2024-02-18 13:30

目录
  • 前言
  • 成员列表
    • 创建
    • 使用
  • 输入框
    • 获取光标的坐标
    • 保存光标
    • 插入文本
    • 运行结果
  • 总结

    前言

    前几篇文章中分别介绍了如何实现聊天输入框的双向绑定、回车键发送、粘贴文本图片等功能,本着完善输入框的目的,文本重点介绍聊天框如何实现@功能。

    文章回顾:

    Vue实现contenteditable元素双向绑定的方法详解

    Vue实现输入框回车发送和粘贴文本与图片功能

    首先需要先理清思路:

    • 成员列表组件,需要根据光标的位置调整,点击成员项时回调成员信息
    • 获取光标的位置坐标(x值,y值)
    • 输入框失焦时记录光标
    • 成员列表回调时,将成员信息插入到光标位置,在此之前需要先恢复之前的光标
    • 将光标移动到新的位置

    既然有了思路,那么就可以一步一步实现。

    成员列表

    创建

    实现成员列表的方式比较简单,其实就是一个列表,一个简单的v-for循环就可以搞定,点击时将当前选择的成员项回调给父组件。

    新增一个AtPop.vue文件:

    
    

    使用

    在父组件中,注册并使用成员列表组件。我们需要在用户输入@的时候弹出成员列表,因此需要监听用户的输入,然后在用户选择成员后需要关闭。关键是获取光标位置,这个由输入框获取,在父组件只需要使用即可。

    // 核心代码
    ...
    // 选择成员时插入数据,并关闭弹窗
    onSelect(item) {
        console.log(\'onSelect\', item);
        this.$refs.inputBox.insertContent(`${item.name} `); // 有空格
        this.isShowAt = false;
    },
    // 输入框输入时回调函数
    inputFunc(data, event) {
        console.log(\'inputFunc\', data, event);
        if (event.data === \'@\') {
            this.isShowAt = true; // 显示弹窗
            this.$nextTick(() => {
            let dom = document.getElementsByClassName(\'at-pop-index\')[0]; // 获取成员列表弹窗,需要放在nextTick中
            // 设置位置
            dom.style.position = \'fixed\';
            dom.style.left = Math.floor(data.left + 10) + \'px\';
            dom.style.top = Math.floor(data.top) + \'px\';
            dom.style.zIndex = 9999;
            })
        } else {
            this.isShowAt = false;
        }
    },
    ...

    输入框

    输入框需要处理光标位置的获取、将值插入到光标的位置等,是本次功能实现的核心。

    当输入框聚焦时,我们会看到光标闪动,想要获取光标的位置以便于插入数据,则需要借助Selection对象。Selection表示用户选择的一段文本范围或者插入数据的当前位置。既然是获取选取范围,那当前选择范围的index=0就是当前光标的位置。我们想要实现的效果是成员列表跟随光标移动,因此就需要获取光标的坐标值。

    获取光标的坐标

    let range = window.getSelection().getRangeAt(0); // 获取当前光标
    let position = range.getBoundingClientRect(); // 获取当前光标的位置

    getBoundingClientRect()方法会返回一个DOMRect矩形对象,其包含矩形区域的坐标值。将获取到的坐标值回调给父组件的方法,显示成员列表。

    当我们在输入框输入@的时候,页面会出现成员列表,此时输入框还是聚焦的。但是如果我们点击了成员列表的某一项,此时输入框已经失焦了,虽然我们可以获取选择的成员并插入,如果只是简单的字符串追加的话,光标会在下次输入时默认定位到开头;或者我们需要在中间插入选择的成员,会发现没有位置可以插入。因此我们需要在失焦的时候先保存当前光标,并在插入时还原光标。

    保存光标

    // DivEditable.vue
    // 失焦
    inputBlur(event) {
        this.selection = this.saveSelection();
        this.$emit(\'blurFunc\', event);
    },
    // 失焦时保存光标
    saveSelection() {
        if (!window.getSelection) {
            return null;
        }
        let sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            return sel.getRangeAt(0);
        }
    },

    光标暂存了,我们需要将插入成员封装成方法,并可以给父组件调用,这样父组件在获取到成员信息后就可以直接调用。接下来需要使用上面已经保存的光标位置:

    插入文本

    // DivEditable.vue
    // 恢复光标
    restoreSelection(range) {
        if (range) {
            let sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        }
    },
    // 插入数据
    insertContent(value) {
        // this.$refs.editor.focus();
        let range, node;
        this.restoreSelection(this.selection); // 还原失焦前的光标位置
        range = window.getSelection().getRangeAt(0);
        range.collapse(false); // 光标移动到最后
    ​
        node = range.createContextualFragment(value);
        let child = node.lastChild;
        console.log(\'lastChild\', child);
        range.insertNode(node);
        // 将光标的起始位置设置在当前插入的元素后面
        if (child) {
            range.setEndAfter(child);
            range.setStartAfter(child);
        }
    ​
        let sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
        this.$emit(\'input\', this.$refs.editor.innerHTML);
    },

    其实到这里就基本实现了@功能,但是还有一个问题,当输入框失焦时回调了父组件的blurFunc方法,导致成员列表关闭了,但是数据还没有拿到。处理这种问题,有两种思路:

    • 使用setTimeout设置定时器,延后执行关闭成员列表操作
    • 修改取数逻辑为异步操作,等到数据拿到后才关闭成员列表

    简单点,就采用setTimeout实现。

    // InputBox.vue
    blurFunc(event) {
        // 失焦时延时关闭弹窗,避免还未拿到数据
        if (this.isShowAt) {
            setTimeout(() => {
                this.isShowAt = false;
            }, 500);
        }
    },

    运行结果

    输入框输入@,在光标位置附近弹出成员列表

    \"Vue实现输入框@功能的示例代码_第1张图片\"

    选择成员后,将成员信息插入到输入框中

    \"Vue实现输入框@功能的示例代码_第2张图片\"

    总结

    本文介绍了实现输入框@功能的方法,简单易上手

    主要使用了SelectionRange对象的相关方法,完成对光标的处理以及输入的插入

    本文实现的@功能,无法删除时整体删除。目前有两种思路:将@xxx转换为图片并插入到输入框,笔者简单写了demo验证了一下,效率不高,且会有卡顿;另一种方式就是监听退格键,删除时判断删除对象是否被包含着有意义的@xxx中,如果是则整体删除,如果不是则默认的方式删除,这种方式笔者没有尝试,难度比较大。

    至此,输入框的功能就基本完善了。需要看完整代码的可移步 项目地址

    以上就是Vue实现输入框@功能的示例代码的详细内容,更多关于Vue输入框@功能的资料请关注脚本之家其它相关文章!

    ItVuer - 免责声明 - 关于我们 - 联系我们

    本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

    桂ICP备16001015号