资讯专栏INFORMATION COLUMN

业务开发情境之:实现一个@功能

BetaRabbit / 581人阅读

摘要:我们算出这个相对于页面左上角的和,就是等下选框相对于文本框的和的距离,因为我们选框是绝对定位相对于,所以在加上文本框相对于的和就是我们选框所要定位的和了。

最近接到了一个业务需求,让用户能够通过网页聊天框的方式在线完成交易,一个用户可能有多个业务群,其中一个功能就是要@人,@这个功能在现实的应用中经常可以遇到,比如微博、QQ都有@功能,今天我们就以前端的方式谈谈怎么一步步实现一个@功能。

@功能涉及到的原生API

obj.selectionStart获取光标位置

obj.setSelectionRange(n, n)设置光标位置

keyup事件和keydown事件

1.搭建我们的html文件

几个地方特别说明下:实际操作中,我们出现了@选框要实时更新列表数据,在这个dome中我们先用静态列表代替,效果是一样的。然后这个pre是用来定位@选框用的,注意pre大小,字体要和输入框一样,并将pre绝对定位到页面的左上角,并设置不可见。








2、实现@选框出现,并将@选框定位到当前光标右下角

具体实现思路:检测键盘的左边是否是@字符,如果有的话,将输入框光标前面的内容复制一份到pre,并在pre后面增加一个span,这个sapn用来协助定位@选框的。我们算出这个span相对于页面左上角的left和top,就是等下@选框相对于文本框的left和top的距离,因为我们@选框是绝对定位相对于body,所以在加上文本框相对于body的offsetLeft和offsetTop就是我们@选框所要定位的left和top了。

//全局定义一个变量为光标位置
var cursor;
//文本框绑定keyup事件,检测输入
textapp.addEventListener("keyup", function(e){
    //获取光标
    cursor = textapp.selectionStart;
    // 当前光标所在位置的前一位为@字符,出现@选框
    if(textapp.value.substring(0,cursor).charAt(cursor-1) === "@"){
        // 判断最后一个字符是否为@
        pre_text.innerHTML = textapp.value.substring(0,cursor);
        pre_text.innerHTML += "";
        var span = document.getElementById("proxy");
        var conX = textapp.offsetLeft;
        var conY = textapp.offsetTop;
        var spanX = span.offsetLeft + conX;
        var spanY = span.offsetTop + conY;
        selectuser.style.left = spanX + "px";
        selectuser.style.top = spanY + "px";
        selectuser.style.display = "block";
        //设置@选框的默认样式
        listSet();
    }else{
        selectuser.style.display = "none";
    }    
})
// @框默认设置
function listSet() {
    var list = $("#selectlist");
    list.focus();
    $("#selectlist").find("li").eq(0).addClass("hover").siblings("li").removeClass("hover");
    $("#selectuser").scrollTop(0);
}
3.键盘直接操作@选框

当我们的@选框出现了,并且定位好了,出现在我们想要的位置了,我们直接用键盘上下去选择所要@的人了(鼠标点击选中情况等下介绍)。这里我们要考虑的点有两个:1.当我们光标在输入框最后,我们按上下左右光标就会变化位置。2.选择之后光标位置的变化。

1的解决办法是:我们光标位置的变化是在keydown的时候执行的,keydown是先于我们的keyup之前执行的,所以我们就要在keydown的时候就阻止默认,防止光标移动

textapp.addEventListener("keydown", function(e){
    //建立在@选框出现的情况下
    if(selectuser.style.display == "block"){
        var code = e.keyCode;
        //左右回车时阻止默认,防止光标移动
        if(code == 38 || code == 40 || code == 13){
            e.preventDefault();
        }
    }
})

2.选中@人后,我们用setSelectionRange来设置光标的位置,将下面这段代码输入框keyup绑定事件里面,放在最前面

    // 当@选框存在时,判断键盘上移,下移,以及回车选中事件
    if(selectuser.style.display == "block"){
        var code = e.keyCode;
        if(code == 38){
            // 上移
            preCode();
            return;
        }else if (code == 40){
            // 下移
            nextCode();
            return;
        }else if(code == 13){
            //回车选中@人
            var textname = "";
            $("#selectlist").find("li").each(function(){
                if($(this).hasClass("hover")){
                    textname = $(this).html();
                }
            });
            //@完后文本框显示内容
            $("#app").val(getText($("#app").val(), cursor, textname));
            //添加后光标的位置
            var n = textname.length + 1 + cursor;
            //设置光标的位置
            textapp.setSelectionRange(n, n);
            //选中后隐藏@选框
            $("#selectuser").hide();
            return;
        }
    }

上面这段代码我们用到了三个函数

    // 键盘上移
    function preCode() {
        var index = $("#selectlist").find(".hover").index();
        if(index == 0){
            return;
        }else{
            index--;
            $("#selectuser").scrollTop(index * 26);
            $("#selectlist").find("li").eq(index).addClass("hover").siblings("li").removeClass("hover");
        }
    }
    // 键盘下移
    function nextCode() {
        var len = $("#selectlist").find("li").length;
        var index = $("#selectlist").find(".hover").index();
        if(index == len-1){
            return;
        }else{
            index++;
            $("#selectuser").scrollTop(index * 26);
            $("#selectlist").find("li").eq(index).addClass("hover").siblings("li").removeClass("hover");
        }
    }
    //@人的文本格式,为后面加一个空格,后面用到 
    function getText(app, cursor, textname) {
        var text1 = app.substring(0, cursor);
        var text2 = app.substring(cursor);
        return text1 + textname + " " + text2;
    }
4.提交操作时,取出有效的@人

当我们消息输入完成后,点击发送(我们这里用个提交按钮)。我们要检测这个消息中是否有@人,并把当前这条消息有效的@人取出来,这里注意并不是说我们之前选中了@某个人后就有效了,可能在这个人的名字中我又输入了其他的字符。所以我们要在发送消息的时候做一次检查,把有效的@人提取出来,并且以后台规定的数据格式。(我们暂且规定为数组吧)。

    // 提交
    $("#submit").on("click", function() {
        var msg = $("#app").val();
        //检测输入框是否为空
        if(msg === ""){
            alert("内容不能为空!");
            return;
        }
        //返回有效@人列表
        var arr = handleMsg(msg);
    });
    //操作信息提取有效@人
    function handleMsg(msg) {
        //存放有效@人id的数组
        var At = [];
        //正则验证吧以@开头空格结束的选出来已数组的形式
        var arrAt = msg.match(/@{1}([u4e00-u9fa5]|w)+s{1}/g);
        //说明没有@人,直接韩慧
        if(arrAt === null){
            console.log("没有选中@的人!");
            return At;
        }
        // 对arrAt数组即当前信息@人的列表进行遍历
        for (var i = 0; i < arrAt.length; i++) {
            var username = arrAt[i].replace("@", "").trim();
            // 对比当前群组人选
            var grounpuser = $("#selectlist").find("li");
            for (var j = 0; j < grounpuser.length; j++) {
                //如果名字相同,则把id放进数组内容
                if(username == grounpuser.eq(j).html()){
                    var uid = grounpuser.eq(j).attr("uid");
                    At.push(uid);
                    break;
                }
            };
        };
        return At;
    }
完结

好了,一个@的功能已经基本实现了,剩下的就是通过ajax与后台的交互了。如果你觉得本篇文章对你有收获请赞下,也可以关注下我,分享工作,学习的前端个人感悟分享。github

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79783.html

相关文章

  • 业务开发情境:文本框的base64编码图片粘贴直接上传七牛

    摘要:我们的功能需要用到的接口事件读取完成,无论成功与否,还有方法将文件读取为。检测是否为图片类型图片的编码这里设置获取的数据获取后台的给的将文件读取为上传事件当的时候说明我们成功的把图片传上七牛了,并且七牛给我们返回了一个字符串。 最近在做的一个聊天消息的功能。有个图片上传的功能,可以通过按钮上传也可以通过Ctrl+V上传。按钮上传的我们可以通过七牛的API就可以做了,我们现在来说说Ctr...

    xiao7cn 评论0 收藏0
  • 业务开发情境实现一个@功能

    摘要:我们算出这个相对于页面左上角的和,就是等下选框相对于文本框的和的距离,因为我们选框是绝对定位相对于,所以在加上文本框相对于的和就是我们选框所要定位的和了。 最近接到了一个业务需求,让用户能够通过网页聊天框的方式在线完成交易,一个用户可能有多个业务群,其中一个功能就是要@人,@这个功能在现实的应用中经常可以遇到,比如微博、QQ都有@功能,今天我们就以前端的方式谈谈怎么一步步实现一个@功能...

    xuexiangjys 评论0 收藏0
  • 函数式编程与面向对象编程[5]:编程的本质

    摘要:函数式编程与面向对象编程编程的本质之剑目录编程的本质读到两篇文章写的不错综合摘录一下复合是编程的本质函数式程序员在洞察问题方面会遵循一个奇特的路线。在面向对象编程中,类或接口的声明就是表面。 函数式编程与面向对象编程[5]:编程的本质 之剑 2016.5.6 01:26:31 编程的本质 读到两篇文章,写的不错, 综合摘录一下 复合是编程的本质 函数式程序员在洞察问题方面会遵循...

    miracledan 评论0 收藏0
  • 漫谈 | 区块链会是哈贝马斯所说的“理想话语情境”吗?

    摘要:区块链科技原罪还是交往理性迄今为止,我们尚未见到从中本聪开始的任何一位区块链开发者提及哈贝马斯,但区块链却奇妙契合了哈贝马斯对理想话语情境的描述。 生活在我们这个时代的人,不可避免的活在消费控制之下。著名的哲学家马尔库塞说,人们似乎是为商品而生活。小轿车、高清晰度的传真装置、错层式家庭住宅以及厨房设备成了人们生活的灵魂。人们被被消费欲望所控制,自主性丧失,个性泯灭,成为单向度的人。 s...

    andong777 评论0 收藏0
  • JAVA 序列化

    摘要:静态变量序列化情境查看清单的代码。之所以打印的原因在于序列化时,并不保存静态变量,这其实比较容易理解,序列化保存的是对象的状态,静态变量属于类的状态,因此序列化并不保存静态变量。解决要想将父类对象也序列化,就需要让父类也实现接口。 原文 https://www.ibm.com/developer...  引言 将 Java 对象序列化为二进制文件的 Java 序列化技术是 Java 系...

    GeekQiaQia 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<