精华内容
下载资源
问答
  • 不知道距离上一篇多久没有写了,可能是因为忙(lan)的关系吧。... 抽空写了新版本的聊天室,内容和上次差不多,这次加上了数据库来处理一些逻辑,包括登录注册功能,OK,现在开始。 好友申请...

      不知道距离上一篇多久没有写了,可能是因为忙(lan)的关系吧。废话不多说,今天要介绍的不算什么新知识,主要是逻辑上的一些东西。什么逻辑呢,加好友,发送好友申请,对方审批通过,拒绝。(很遗憾,对方审批通过和拒绝后的通知没做,看完本博客的小伙伴有兴趣的可以尝试一下)。

      抽空写了新版本的聊天室,内容和上次差不多,这次加上了数据库来处理一些逻辑,包括登录注册功能,OK,现在开始。

    1. 好友申请

      新版本中做了一个默认分组:注册用户 的功能,即所有注册进来的人都会存在于该组中,该组和普通群组一样,可以群聊,也可以单独找人聊,添加好友的目的就是为了在茫茫人海中找到TA。O(∩_∩)O,先上一个图:

     

      我当前的用户是zhangsan,点击一下GD,可以看到如下窗口:

      我们就从这一步开始吧。首先,当前用户和要聊天的用户建立连接之后,在后台检查是否是好友并且是否存在好友申请记录(后续会提到 ),逻辑很简单,建立一个好友表,查一下,有没有好友关系即可,我们具体看一下,客户端连接成功之后,返回的json是什么:

      解释一下,每个字段的含义。

    gid 聊天室唯一id
    history 聊天历史记录集合
    isfriend 是否是好友,handle,申请处理结果
    rid 对方id
    sid 本人id
    type one代表单聊  group代表群组

     

     

     

     

     

     

     

     

      可以看到isfriend中的friend为0,那么就会弹出“还不是好友,是否添加对方为好友”的提示。如果isfriend中的handle(0代表对方申请成为好友,1代表对方同意,2代表对方拒绝),当你点击发送的时候会弹出如下框,添加备注,并且发送成功之后,提示文字会更改:

      2.好友审批

      好友申请已经完成了,我们换成GD用户登录,点击钟表图标,会看到如下效果:

      点击头像,弹出对话框:

      点击是,加为好友,否,拒绝添加好友。拒绝我就不演示了。点击是之后呢,再看看我们的好友列表是不是多了一个好友呢,而且默认分组就是我的好友哦。

      在换回zhangsan用户,看看吧

      PS:虽然不加好友也能聊天。但毕竟多了一层好友关系嘛。其实这个web聊天室可以把很多QQ的功能模仿出来。这次就先介绍加好友吧。(至于为什么拿GD做示范。。。大概是脑子抽了吧。)

      总结:本期简单介绍了加好友的逻辑流程.也作为此系列的终结篇。抽空研究一下,权限验证等其他高级功能。为大家奉献出来,希望大家喜欢,本期就到这里啦。( ^_^ )/~~拜拜

      代码地址:https://github.com/fanpan26/LayIM_SignalR_Chat

    转载于:https://www.cnblogs.com/panzi/p/5461364.html

    展开全文
  •  看起来挺简单,细节还是很多的,好,接上一篇,我们已经成功连接singalR服务器了,那么剩下的内容呢,就是一步一步实现聊天功能。  我们先看看缺什么东西 点击好友弹框之后,要给服务器发消息,进入组Group....

    ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(三) 激动人心的时刻到啦,实现1v1聊天

     

      看起来挺简单,细节还是很多的,好,接上一篇,我们已经成功连接singalR服务器了,那么剩下的内容呢,就是一步一步实现聊天功能。

      我们先看看缺什么东西

    1. 点击好友弹框之后,要给服务器发消息,进入组Group.Group原理在上一篇已经介绍了,这里不再赘述。
    2. 点击发送消息到后台,后台在传送回来
    3. 将htmlappend到相应元素上,demo已经实现了,我们把代码拿过来用就可以了
    4. 模拟用户登录,点击发送聊天

      在做上述工作之前,还是要做许多准备工作的。我们分析一下界面元素

      

      好的,可以看到,一个消息里面有消息发送时间(addtime),用户名(username),用户头像(userphoto),用户消息体(msgcontent),除此之外还需要用户id,聊天id,以及组名(groupname).以此我先在后台建立模型。

      

    复制代码
    namespace LayIM.Model
    {
        public enum CSMessageType
        {
            System = 1,//系统消息,出错,参数错误等消息
            Custom = 2 //普通消息,对话,或者群组消息
        }
    }
    复制代码
    复制代码
    namespace LayIM.Model
    {
        public class CSChatMessage
        {
            public CSChatMessage() {
                addtime = DateTime.Now.ToString("HH:mm:ss");
            }
            /// <summary>
            /// 消息来源
            /// </summary>
            public CSUser fromuser { get; set; }
            public CSUser touser { get; set; }
            /// <summary>
            /// 消息内容
            /// </summary>
            public string msg { get; set; }
            /// <summary>
            /// 消息发送时间
            /// </summary>
            public string addtime { get; set; }
            /// <summary>
            /// 消息类型
            /// </summary>
            public CSMessageType msgtype { get; set; }
    
            public object other { get; set; }
        }
    }
    复制代码
    复制代码
    namespace LayIM.Model
    {
        public class SingalRUser
        {
            protected string _groupName { get; set; }
            private string _connectionId { get; set; }
            /// <summary>
            /// 用户当前所在组
            /// </summary>
            public string groupname
            {
                get
                {
                    return this._groupName;
                }
            }
            /// <summary>
            /// 用户当前所在connectionid
            /// </summary>
            public string connectionid
            {
                get
                {
                    return this._connectionId;
                }
            }
            public SingalRUser(string groupName, string connectionId)
            {
                _groupName = groupName;
                _connectionId = connectionId;
            }
            public SingalRUser() { }
        }
        /// <summary>
        /// 用户Model
        /// </summary>
        public class CSUser : SingalRUser
        {
            public CSUser(string groupName, string connectionId) :
                base(groupName, connectionId)
            {
            }
            /// <summary>
            /// 用户id
            /// </summary>
            public int userid { get; set; }
            /// <summary>
            /// 用户昵称
            /// </summary>
            public string username { get; set; }
            /// <summary>
            /// 用户头像
            /// </summary>
            public string photo { get; set; }
        }
    }
    复制代码

      ok,很简单的几个model,CSUser为用户,CSChatMessage为消息体。那么,如果想让两个用户联通,我们需要得到他们所在的组,即经常说到的 userID1+userID2,生成组名代码如下:(主要保证两个用户的组名唯一性就可,方法随意)

    复制代码
        /// <summary>
            /// 根据两个用户ID得到对应的组织名称
            /// </summary>
            /// <param name="sendid">发送人(主动联系人)</param>
            /// <param name="receiveid">接收人(被动联系人)</param>
            /// <returns></returns>
            public static string GetGroupName(string sendid, string receiveid)
            {
                /*
                    排序的目的就是为了保证,无论谁连接服务器,都能得到正确的组织ID
                */
                int compareResult = string.Compare(sendid, receiveid);
                if (compareResult > 0) {
                    //重新排序 如果sendid>receiveid
                    return string.Format("G{0}{1}", receiveid, sendid);
                }
                return string.Format("G{0}{1}", sendid, receiveid);
            }
    复制代码

    现在groupName也有了,我们回到 CustomServiceHub 类中来。添加用户加入组的方法,这个方法什么时候调用呢,就是当你点击某个用户头像弹出聊天框的时候调用。

    复制代码
    /// <summary>
            /// 人对人聊天 连接服务器
            /// </summary>
            /// <param name="sendid">发送人</param>
            /// <param name="receiveid">接收人</param>
            /// <returns></returns>
            public Task ClientToClient(string sendid, string receiveid)
            {
                if (sendid == null || receiveid == null) { throw new ArgumentNullException("sendid or receiveid can't be null"); }
                //获取组名
                string groupName = MessageUtils.GetGroupName(sendid, receiveid);
                //将当前用户添加到此组织内
                Groups.Add(CurrentUserConnectionId, groupName);
                //构建系统连接成功消息
                var msg = MessageUtils.GetSystemMessage(groupName, MessageConfig.ClientToClientConnectedSucceed, new { currentid = sendid, receiveid = receiveid });
                //将消息推送到当前组 (A和B聊天的组) 同样调用receiveMessage方法
                return Clients.Caller.receiveMessage(msg);
            }
    复制代码

      里面有些代码是我封装的,大体看清思路就可以了。下面去读一下layim.js里的源代码,找到弹出用户窗口那一段。

    复制代码
     //弹出聊天窗
            config.chatings = 0;
            node.list.on('click', '.xxim_childnode', function () {
                var othis = $(this);
                //当前登录用户id
                var currentid = config.user.id;
                //取得被点击的用户id
                var receiveid = othis.data('id');
                //调用signalR封装的方法,连接服务器,将发送人id,接收人id传给后台,当前用户加入组
                csClient.server.ctoc(currentid, receiveid);
                xxim.popchatbox(othis);
            });
    复制代码

      在看一下csClient到底做了什么

    复制代码
     ctoc: function (sid, rid) {
                    //调用hub的clientToClient方法
                    if (!chat.isConnected(rid)) {
                        //如果没有连接过,进行连接
                        console.log("用户 " + rid + "没有连接过...");
                        _this.proxy.proxyCS.server.clientToClient(sid, rid);
                    } else {
                        console.log("用户 " + rid + "已经连接过了,不需要连接了...");
                    }
                },
    复制代码

      这里呢,我另外加了个js对象缓存,防止每次点击都要重复连接数据库,当然,页面刷新之后缓存消失,需要重新 连。到这里我们点击一下,看看效果。

      好,从上图可以看到,服务器返回了成功的消息,并且,groupname也是按照顺序生成的。这个消息有什么用呢,其实对于客户端是没有什么效果的,如果想要提示用户连接成功或者提示对方是否在线可以用到,这里我不在扩展,只是为了打印看是否连接成功,当连接成功之后呢,用户就会存在组 G1000010003中了,这时候你发消息如果对面没有连接的话,他是看不见的。连接成功之后,就要做发消息功能了。继续回到 CustomServiceHub 类,添加发送消息方法:

    复制代码
    /// <summary>
            /// 发送消息 ,服务器接收的是CSChatMessage实体,他包含发送人,接收人,消息内容等信息
            /// </summary>
            /// <param name="msg"></param>
            /// <returns></returns>
            public Task ClientSendMsgToClient(CSChatMessage msg)
            {
                var groupName = MessageUtils.GetGroupName(msg.fromuser.userid.ToString(), msg.touser.userid.ToString());
                /*
                中间处理一下消息直接转发给(A,B所在组织,即聊天窗口)
                */
                msg.msgtype = CSMessageType.Custom;//消息类型为普通消息
                return Clients.Group(groupName).receiveMessage(msg);
            }
    复制代码

      可以看到,同样是用到了receiveMessage方法,不过这里呢,调用的Clients.Group(groupName)也就是说,发送的这条消息职能在这个组内的人才能看到,那么组里就两个人,是不是就实现了1对1 聊天呢,离线留言也支持哦。消息发送成功之后,其实不管对方在不在线,我们都可以做一下本地处理,为了演示消息发送效果,我们不用本地js在发送的时候直接拼接到页面上,而是client端接收到消息体之后再处理,这样会看出消息延时效果。(扩展:假如发送的消息很慢的话,就可以在消息体旁边加一个等待的小菊花,提示发送成功,失败等。)好,我直接将layim里模拟消息处理的代码拿出来了,我们看详细代码。

    复制代码
       handleCustomMsg: function (result) {
                var log = {};
                //接收人
                var keys = 'one' + result.touser.userid;
                //发送人
                var keys1 = 'one' + result.fromuser.userid;
                //这里一定要注意,这个keys是会变的,也就是说,如果只取一个的话,会造成 log.imarea[0]为undefined的情况,至于为什么会变,看看代码好好思考一下吧
                log.imarea = $('#layim_area' + keys);//layim_areaone0
                if (!log.imarea.length) {
                    log.imarea = $('#layim_area' + keys1);//layim_areaone0
                }
                //拼接html模板
                log.html = function (param, type) {
                    return '<li class=" + (type === 'me' ? 'layim_chateme' : '') + ">'
                        + '<div class="layim_chatuser">'
                            + function () {
                                if (type === 'me') {
                                    return '<span class="layim_chattime">' + param.time + '</span>'
                                           + '<span class="layim_chatname">' + param.name + '</span>'
                                           + '<img src="' + param.face + '" >';
                                } else {
                                    return '<img src="' + param.face + '" >'
                                           + '<span class="layim_chatname">' + param.name + '</span>'
                                           + '<span class="layim_chattime">' + param.time + '</span>';
                                }
                            }()
                        + '</div>'
                        + '<div class="layim_chatsay">' + param.content + '<em class="layim_zero"></em></div>'
                    + '</li>';
                };
                //上述代码还是layim里的代码,只不过拼接html的时候,参数采用signalR返回的参数
                var type = result.fromuser.userid == currentUser.id ? "me" : "";//如果发送人的id==当前用户的id,那么这条消息类型为me
                //拼接html 直接调用layim里的代码
                log.imarea.append(log.html({
                    time: result.addtime,
                    name: result.fromuser.username,
                    face: result.fromuser.photo,
                    content: result.msg
                }, type));
                //滚动条处理
                log.imarea.scrollTop(log.imarea[0].scrollHeight);
            },
    复制代码

      好了, 代码也都处理完了,这里呢有个小插曲,我们怎么确定当前用户是谁呢?由于我写的是死数据,所以我就采用随机生成的方法,然后将用户保存到 localStorage里面了,这样当用户再次打开页面,还是会取到第一次的用户,这里呢不多做介绍了。

    复制代码
     /*
            获取随机一个用户
            当用户第一次登陆就获取,然后存到本地localStorage中模拟用户,之后再登录就直接从缓存里面取
            */
            function getRandomUser() {
                var userKey = "SIGNALR_USER";
                var user = local.get(userKey);
                if (user) { return JSON.parse(user);}
                var userids = [];
                var usernames = ["痴玉", "书筠", "诗冬", "飞枫", "盼玉", "靖菡", "宛雁", "之卉", "凡晴", "书枫", "沛梦"];
                var userphotos = [];
                //添加id,用户头像数组
                for (var i = 0; i < 9; i++) {
                    userids.push(10000 + i);
                    userphotos.push("/photos/00" + i.toString() + ".jpg");
                }
                //取一个random值,自动生成当前用户
                var random = Math.random().toString().substr(3, 1);
                if (random > 8) { random = 8; }
                var user = {
                    name: usernames[random],
                    photo: userphotos[random],
                    id:userids[random]
                };
                local.set(userKey, JSON.stringify(user));
                return user;
            }
            /*本地存储*/
            var local = {
                get: function (key) {
                    return localStorage.getItem(key);
                },
                set: function (key, value) {
                    localStorage.setItem(key, value);
                }
            }
    复制代码

      当然里面有好多需要注意的细节没有给大家讲,具体的可以看详细代码,思路基本已经出来了。我在重复一遍吧:第一,点击用户,连接服务器,当前用户加入对应的组。第二,发送消息,调用server端的方法,将消息发送出去后,在推送到组里面去,第三,客户端接收到消息之后,加到html页面上,就这么简单。还有一个细节,注意消息在左边还是右边。

      演示一下吧:模拟第一个用户登录。(谷歌浏览器)

      好,很好听的名字:飞枫,id为10003,下面第二个用户登录,(QQ浏览器)

      id为10001,名字为 书筠。那么我们先用第一个用户点击  书筠 头像 打开聊天窗口,然后在用第二个用户点击 飞枫头像打开聊天窗口(由于没有做历史记录,所以离线留言功能暂时不支持,只支持在线)

      打开之后,唉,单身的我只能模拟两个人聊天玩了。。

     

    到此为止呢,1v1聊天就到一段落,仅支持。。。文本,还不知道输入script有没有处理。。另外还有一个bug,就是窗口多开的话,应该 信息可能会乱,不是因为 发送乱了,而是,里面有可能有重复的ID导致信息赋html错误,我没测,但是我猜测是这样的。非常感谢“贤心”大神的web前端通讯框架。本篇到此结束,喜欢的同学点个赞吧。多多转发哦。下篇预告:最终章-修改1v1聊天bug,添加图片表情,附件传送功能。群聊功能实现。

    GitHub地址: 

    https://github.com/fanpan26/LayIM/tree/master

     

    作者:丶Pz

    出处:https://www.cnblogs.com/panzi/p/5146573.html

    本站使用「署名 4.0 国际」创作共享协议,转载请在文章明显位置注明作者及出处。

    转载于:https://www.cnblogs.com/Jeely/p/11058530.html

    展开全文
  • 看起来挺简单,细节还是很多的,好,接上一篇,我们已经成功连接singalR服务器了,那么剩下的内容呢,就是一步一步实现聊天功能。  我们先看看缺什么东西 点击好友弹框之后,要给服务器发消息,进入组Group....

      看起来挺简单,细节还是很多的,好,接上一篇,我们已经成功连接singalR服务器了,那么剩下的内容呢,就是一步一步实现聊天功能。

      我们先看看缺什么东西

    1. 点击好友弹框之后,要给服务器发消息,进入组Group.Group原理在上一篇已经介绍了,这里不再赘述。
    2. 点击发送消息到后台,后台在传送回来
    3. 将htmlappend到相应元素上,demo已经实现了,我们把代码拿过来用就可以了
    4. 模拟用户登录,点击发送聊天

      在做上述工作之前,还是要做许多准备工作的。我们分析一下界面元素

      

      好的,可以看到,一个消息里面有消息发送时间(addtime),用户名(username),用户头像(userphoto),用户消息体(msgcontent),除此之外还需要用户id,聊天id,以及组名(groupname).以此我先在后台建立模型。

      

    namespace LayIM.Model
    {
        public enum CSMessageType
        {
            System = 1,//系统消息,出错,参数错误等消息
            Custom = 2 //普通消息,对话,或者群组消息
        }
    }
    namespace LayIM.Model
    {
        public class CSChatMessage
        {
            public CSChatMessage() {
                addtime = DateTime.Now.ToString("HH:mm:ss");
            }
            /// <summary>
            /// 消息来源
            /// </summary>
            public CSUser fromuser { get; set; }
            public CSUser touser { get; set; }
            /// <summary>
            /// 消息内容
            /// </summary>
            public string msg { get; set; }
            /// <summary>
            /// 消息发送时间
            /// </summary>
            public string addtime { get; set; }
            /// <summary>
            /// 消息类型
            /// </summary>
            public CSMessageType msgtype { get; set; }
    
            public object other { get; set; }
        }
    }
    namespace LayIM.Model
    {
        public class SingalRUser
        {
            protected string _groupName { get; set; }
            private string _connectionId { get; set; }
            /// <summary>
            /// 用户当前所在组
            /// </summary>
            public string groupname
            {
                get
                {
                    return this._groupName;
                }
            }
            /// <summary>
            /// 用户当前所在connectionid
            /// </summary>
            public string connectionid
            {
                get
                {
                    return this._connectionId;
                }
            }
            public SingalRUser(string groupName, string connectionId)
            {
                _groupName = groupName;
                _connectionId = connectionId;
            }
            public SingalRUser() { }
        }
        /// <summary>
        /// 用户Model
        /// </summary>
        public class CSUser : SingalRUser
        {
            public CSUser(string groupName, string connectionId) :
                base(groupName, connectionId)
            {
            }
            /// <summary>
            /// 用户id
            /// </summary>
            public int userid { get; set; }
            /// <summary>
            /// 用户昵称
            /// </summary>
            public string username { get; set; }
            /// <summary>
            /// 用户头像
            /// </summary>
            public string photo { get; set; }
        }
    }

      ok,很简单的几个model,CSUser为用户,CSChatMessage为消息体。那么,如果想让两个用户联通,我们需要得到他们所在的组,即经常说到的 userID1+userID2,生成组名代码如下:(主要保证两个用户的组名唯一性就可,方法随意)

        /// <summary>
            /// 根据两个用户ID得到对应的组织名称
            /// </summary>
            /// <param name="sendid">发送人(主动联系人)</param>
            /// <param name="receiveid">接收人(被动联系人)</param>
            /// <returns></returns>
            public static string GetGroupName(string sendid, string receiveid)
            {
                /*
                    排序的目的就是为了保证,无论谁连接服务器,都能得到正确的组织ID
                */
                int compareResult = string.Compare(sendid, receiveid);
                if (compareResult > 0) {
                    //重新排序 如果sendid>receiveid
                    return string.Format("G{0}{1}", receiveid, sendid);
                }
                return string.Format("G{0}{1}", sendid, receiveid);
            }

    现在groupName也有了,我们回到 CustomServiceHub 类中来。添加用户加入组的方法,这个方法什么时候调用呢,就是当你点击某个用户头像弹出聊天框的时候调用。

    /// <summary>
            /// 人对人聊天 连接服务器
            /// </summary>
            /// <param name="sendid">发送人</param>
            /// <param name="receiveid">接收人</param>
            /// <returns></returns>
            public Task ClientToClient(string sendid, string receiveid)
            {
                if (sendid == null || receiveid == null) { throw new ArgumentNullException("sendid or receiveid can't be null"); }
                //获取组名
                string groupName = MessageUtils.GetGroupName(sendid, receiveid);
                //将当前用户添加到此组织内
                Groups.Add(CurrentUserConnectionId, groupName);
                //构建系统连接成功消息
                var msg = MessageUtils.GetSystemMessage(groupName, MessageConfig.ClientToClientConnectedSucceed, new { currentid = sendid, receiveid = receiveid });
                //将消息推送到当前组 (A和B聊天的组) 同样调用receiveMessage方法
                return Clients.Caller.receiveMessage(msg);
            }

      里面有些代码是我封装的,大体看清思路就可以了。下面去读一下layim.js里的源代码,找到弹出用户窗口那一段。

     //弹出聊天窗
            config.chatings = 0;
            node.list.on('click', '.xxim_childnode', function () {
                var othis = $(this);
                //当前登录用户id
                var currentid = config.user.id;
                //取得被点击的用户id
                var receiveid = othis.data('id');
                //调用signalR封装的方法,连接服务器,将发送人id,接收人id传给后台,当前用户加入组
                csClient.server.ctoc(currentid, receiveid);
                xxim.popchatbox(othis);
            });

      在看一下csClient到底做了什么

     ctoc: function (sid, rid) {
                    //调用hub的clientToClient方法
                    if (!chat.isConnected(rid)) {
                        //如果没有连接过,进行连接
                        console.log("用户 " + rid + "没有连接过...");
                        _this.proxy.proxyCS.server.clientToClient(sid, rid);
                    } else {
                        console.log("用户 " + rid + "已经连接过了,不需要连接了...");
                    }
                },

      这里呢,我另外加了个js对象缓存,防止每次点击都要重复连接数据库,当然,页面刷新之后缓存消失,需要重新 连。到这里我们点击一下,看看效果。

      好,从上图可以看到,服务器返回了成功的消息,并且,groupname也是按照顺序生成的。这个消息有什么用呢,其实对于客户端是没有什么效果的,如果想要提示用户连接成功或者提示对方是否在线可以用到,这里我不在扩展,只是为了打印看是否连接成功,当连接成功之后呢,用户就会存在组 G1000010003中了,这时候你发消息如果对面没有连接的话,他是看不见的。连接成功之后,就要做发消息功能了。继续回到 CustomServiceHub 类,添加发送消息方法:

    /// <summary>
            /// 发送消息 ,服务器接收的是CSChatMessage实体,他包含发送人,接收人,消息内容等信息
            /// </summary>
            /// <param name="msg"></param>
            /// <returns></returns>
            public Task ClientSendMsgToClient(CSChatMessage msg)
            {
                var groupName = MessageUtils.GetGroupName(msg.fromuser.userid.ToString(), msg.touser.userid.ToString());
                /*
                中间处理一下消息直接转发给(A,B所在组织,即聊天窗口)
                */
                msg.msgtype = CSMessageType.Custom;//消息类型为普通消息
                return Clients.Group(groupName).receiveMessage(msg);
            }

      可以看到,同样是用到了receiveMessage方法,不过这里呢,调用的Clients.Group(groupName)也就是说,发送的这条消息职能在这个组内的人才能看到,那么组里就两个人,是不是就实现了1对1 聊天呢,离线留言也支持哦。消息发送成功之后,其实不管对方在不在线,我们都可以做一下本地处理,为了演示消息发送效果,我们不用本地js在发送的时候直接拼接到页面上,而是client端接收到消息体之后再处理,这样会看出消息延时效果。(扩展:假如发送的消息很慢的话,就可以在消息体旁边加一个等待的小菊花,提示发送成功,失败等。)好,我直接将layim里模拟消息处理的代码拿出来了,我们看详细代码。

       handleCustomMsg: function (result) {
                var log = {};
                //接收人
                var keys = 'one' + result.touser.userid;
                //发送人
                var keys1 = 'one' + result.fromuser.userid;
                //这里一定要注意,这个keys是会变的,也就是说,如果只取一个的话,会造成 log.imarea[0]为undefined的情况,至于为什么会变,看看代码好好思考一下吧
                log.imarea = $('#layim_area' + keys);//layim_areaone0
                if (!log.imarea.length) {
                    log.imarea = $('#layim_area' + keys1);//layim_areaone0
                }
                //拼接html模板
                log.html = function (param, type) {
                    return '<li class="' + (type === 'me' ? 'layim_chateme' : '') + '">'
                        + '<div class="layim_chatuser">'
                            + function () {
                                if (type === 'me') {
                                    return '<span class="layim_chattime">' + param.time + '</span>'
                                           + '<span class="layim_chatname">' + param.name + '</span>'
                                           + '<img src="' + param.face + '" >';
                                } else {
                                    return '<img src="' + param.face + '" >'
                                           + '<span class="layim_chatname">' + param.name + '</span>'
                                           + '<span class="layim_chattime">' + param.time + '</span>';
                                }
                            }()
                        + '</div>'
                        + '<div class="layim_chatsay">' + param.content + '<em class="layim_zero"></em></div>'
                    + '</li>';
                };
                //上述代码还是layim里的代码,只不过拼接html的时候,参数采用signalR返回的参数
                var type = result.fromuser.userid == currentUser.id ? "me" : "";//如果发送人的id==当前用户的id,那么这条消息类型为me
                //拼接html 直接调用layim里的代码
                log.imarea.append(log.html({
                    time: result.addtime,
                    name: result.fromuser.username,
                    face: result.fromuser.photo,
                    content: result.msg
                }, type));
                //滚动条处理
                log.imarea.scrollTop(log.imarea[0].scrollHeight);
            },

      好了, 代码也都处理完了,这里呢有个小插曲,我们怎么确定当前用户是谁呢?由于我写的是死数据,所以我就采用随机生成的方法,然后将用户保存到 localStorage里面了,这样当用户再次打开页面,还是会取到第一次的用户,这里呢不多做介绍了。

     /*
            获取随机一个用户
            当用户第一次登陆就获取,然后存到本地localStorage中模拟用户,之后再登录就直接从缓存里面取
            */
            function getRandomUser() {
                var userKey = "SIGNALR_USER";
                var user = local.get(userKey);
                if (user) { return JSON.parse(user);}
                var userids = [];
                var usernames = ["痴玉", "书筠", "诗冬", "飞枫", "盼玉", "靖菡", "宛雁", "之卉", "凡晴", "书枫", "沛梦"];
                var userphotos = [];
                //添加id,用户头像数组
                for (var i = 0; i < 9; i++) {
                    userids.push(10000 + i);
                    userphotos.push("/photos/00" + i.toString() + ".jpg");
                }
                //取一个random值,自动生成当前用户
                var random = Math.random().toString().substr(3, 1);
                if (random > 8) { random = 8; }
                var user = {
                    name: usernames[random],
                    photo: userphotos[random],
                    id:userids[random]
                };
                local.set(userKey, JSON.stringify(user));
                return user;
            }
            /*本地存储*/
            var local = {
                get: function (key) {
                    return localStorage.getItem(key);
                },
                set: function (key, value) {
                    localStorage.setItem(key, value);
                }
            }

      当然里面有好多需要注意的细节没有给大家讲,具体的可以看详细代码,思路基本已经出来了。我在重复一遍吧:第一,点击用户,连接服务器,当前用户加入对应的组。第二,发送消息,调用server端的方法,将消息发送出去后,在推送到组里面去,第三,客户端接收到消息之后,加到html页面上,就这么简单。还有一个细节,注意消息在左边还是右边。

      演示一下吧:模拟第一个用户登录。(谷歌浏览器)

      好,很好听的名字:飞枫,id为10003,下面第二个用户登录,(QQ浏览器)

      id为10001,名字为 书筠。那么我们先用第一个用户点击  书筠 头像 打开聊天窗口,然后在用第二个用户点击 飞枫头像打开聊天窗口(由于没有做历史记录,所以离线留言功能暂时不支持,只支持在线)

      打开之后,唉,单身的我只能模拟两个人聊天玩了。。

     

    到此为止呢,1v1聊天就到一段落,仅支持。。。文本,还不知道输入script有没有处理。。另外还有一个bug,就是窗口多开的话,应该 信息可能会乱,不是因为 发送乱了,而是,里面有可能有重复的ID导致信息赋html错误,我没测,但是我猜测是这样的。非常感谢“贤心”大神的web前端通讯框架。本篇到此结束,喜欢的同学点个赞吧。多多转发哦。下篇预告:最终章-修改1v1聊天bug,添加图片表情,附件传送功能。群聊功能实现。

    GitHub地址: 

    https://github.com/fanpan26/LayIM/tree/master

     

    转载于:https://www.cnblogs.com/panzi/p/5146573.html

    展开全文
  • 上一篇介绍了加好友的流程,这里不再赘述,不过之前的聊天只能发送普通文字,那么本篇就教你如何实现发送附件和图片消息。我们先对功能进行分析: 发送图片,附件,需要实现上传图片和附件的功能。 textarea不能...

      上一篇介绍了加好友的流程,这里不再赘述,不过之前的聊天只能发送普通文字,那么本篇就教你如何实现发送附件和图片消息。我们先对功能进行分析:

    • 发送图片,附件,需要实现上传图片和附件的功能。
    • textarea不能显示图片,所以需要做图片转换
    • 接收到消息之后需要在将图片转换回原来图片
    • 附件特殊样式处理

      那么我们先实现文件的上传功能,由于用的是MVC,就简单做一个无刷新无进度条上传,所以图片和文件就需要小一点,否则用户体验就差了。我用的是jquery.form.js实现form提交文件,后台用HttpPostedFileBase 接收file文件,然后保存。最后返回文件的新路径和名称。看一下后台代码:(一段很简单的文件上传代码,没有做过多的处理,注意要新建好upload文件夹)

     public JsonResult UploadFile(HttpPostedFileBase file,int userid=0)
            {
                if (file != null && file.ContentLength > 0)
                {
                    string fileExtension = Path.GetExtension(file.FileName).ToLowerInvariant();
                    string fileName = Guid.NewGuid().ToString();
                    string fullFileName = string.Format("{0}{1}", fileName, fileExtension);
                    string oldFileName = Path.GetFileName(file.FileName);
    
                    string fileSavePath = string.Format("{0}{1}", Server.MapPath("/upload/"),fullFileName);
                    string url = "/upload/" + fullFileName;
                    file.SaveAs(fileSavePath);
                    bool isImg = FileExtension.isImage(fileExtension);
                    if (userid > 0) {
                        UserBLL.UpdateUserPhoto(url, userid);
                    }
                    return Json(new { url = url, name = oldFileName, ext = fileExtension, name1 = fullFileName, t = isImg ? "img" : "file" }, JsonRequestBehavior.DenyGet);
                }
                return Json("", JsonRequestBehavior.DenyGet);
            }

      下面我们在看一下如果文件上传成功,返回的json:

      ext: 文件后缀,name: 文件原名 name1: 文件新名称 t: img/file  url:文件路径

      那么上传完文件之后要以特殊标志显示在聊天输入框中。我们简单赋值就可以了。效果如下:

      那么点击发送的时候增加了什么逻辑呢,就是把图片相关信息一并发送到服务器,打印一下发送的消息json:

      注意一下两个画红框的地方,其实我的做法很简单,当消息接收到之后,我将url替换掉name,同时拼接img标签就可以了。接收到消息之后代码处理如下:

           //images 为图片数组  files为附件数组  content为原消息
                log.handleMessage = function (content, images, files) {
                    //处理替换图片消息
                    if (images && images.length > 0) {
                        for (var i = 0; i < images.length; i++) {
                            content = content.replace(images[i].name, '<img src="' + images[i].url + '" width="200" height="200"/>');
                        }
                    }
                    //处理替换附件消息
                    if (files && files.length > 0) {
                        for (var i = 0; i < files.length; i++) {
                            var ext = files[i].name.split('.')[1];
                            ext = ext.substr(0, ext.length - 1);
                            var img = '<img src="/images/' + ext + '.png" width="30" height="30"/>';
                            content = content.replace(files[i].name,'<a href="' + files[i].url + '">' + img + '' + files[i].name + '</a>');
                        } 
                    }
                    return content;
                }

      那么经过消息处理之后,聊天消息显示框的内容就是活生生的图片和附件了。附件点击可以下载哦。不过为了历史记录不受影响,记住将附件或者图片消息json存入数据库,方便转换。

      下面我们总结一下:如果需要发送带图片和附件的消息,首先要做的就是将图片或者文件上传到服务器。然后相当于将路径发送给对方,展示。因为消息展示本身就是html所以,图片无非是img标签罢了。更多的内容不再赘述,详细demo移步:

      https://github.com/fanpan26/LayIM_SignalR_Chat 记得给一颗星星哦。

    转载于:https://www.cnblogs.com/panzi/p/5522736.html

    展开全文
  • 本系统采用了 B/S 体系结构,以 MySql 作为数据库管理数据,以 JSP 作为...仿QQ整合了一套完整的即时聊天功能,包含一对一聊天以及多对多群聊,往着美观大气用户体验高的方针,把分组、好友、群聊完美完整地呈现于主
  • 实现功能: 1:即时聊天(没有使用Ajax,使用网页自动刷新),支持未读消息通知。 2:好友管理,查找、添加、删除好友等 3:空间管理,设置背景颜色,空间留言等 4:系统登录,注册,头像设置,注销等 5:新闻显示,...
  • 功能实现1.修改功能(密码、昵称、个性签名)2.添加好友、删除好友3.单聊功能4.判断好友是否在线二. 模块划分三. 使用的知识nettyswing集合等同步阻塞队列synchronousQueue数据库MySQL中的CRUDC3p0连接池JSON字符串四...
  • 如何在自己的网站加上 qq在线交谈,离线留言功能。即点击qq个性图标,可以打开客户机端的qq客户端。实现和业主的qq聊天对话框。 如: QQ在线状态官网: http://wp.qq.com/index.html 说明: ...
  • 安卓268聊天室app+server

    2017-09-19 22:08:00
    二、功能实现: 可以在聊天室里实现公共聊天,也可以邀几个私交好友私聊,同时提供了两个用户之间能够传送文件。 三、系统截图 转载于我帮你毕业设计需要详细信息可以联系Q 2786639042或者去网站...
  • web即时聊天系统的实现 第【3】页 项目需求分析 ...首先,本项目不是单纯的类似qq的即时通讯,而是社交网站聊天功能。 项目功能 注册、登录功能 私聊功能,可以通过添加好友或者关注的用...
  • 日前,全世界最大的手机聊天工具WhatsApp,悄然推出了安卓手表的客户端,用户可以对着手表说话,实现好友聊天。 据美国科技新闻网站瘾科技的报道,WhatsApp的这一客户端,是最新推出,目前新版本尚未出现在谷歌...
  • 本例说明如何开发一个简单的有文字信息,好友上下线事件等基本功能功能的即时通讯程序,若配合Flash,还可以实现与web文字信息发送互通效果。 PRTX 即时通讯SDK适合软件公司将即时通讯与ERP,OA,CRM等系统整合...
  • IM是这样工作的:当好友列表中的某人在任何时候登录上线并试图通过你的计算机联系你时,IM系统会发一个消息提醒你,然后你能与他建立一个聊天会话并键入消息文字进行交流。从架构上属于典型的C/S架构。  2、 网页...
  •  上面这个是微信的js-SDK页面分享给微信好友聊天列表中显示的视觉效果。  微信JS-SDK Demo :这个是微信网页分享出去的标题。  微信JS-SDK,帮助第三方为用户提供更优质的移动web服务:这个是被分享的这个页面的...
  • 网站的会员可以发表说说,会员编辑完说说后即可发布到平台,可供好友查看,好友可以对看到的说说发表评论,说说的发表者可以对评论者进行回复,会员可以在稍后对自己的说说进行删除处理。 2.实施方案与创新点...
  • 网站即时通讯功能,在线用户可以及时聊天。 注册用户可以在交友网俱乐部发帖回帖和其他会员交流生活、情感、兴趣爱好等心得以及反馈问题等,提供会员交流联系的平台,更有效的增加会员用户之间的联系交流途径。 谁...
  • 提供新闻、文章、产品、下载、商品、案例(图片)、订单、留言、聊天、会员(VIP会员)、简介、招聘、友情连接、内容评论、好友分享、公告、内容加密、批量自动生成HTML静态页面、搜索、公司资质证书、程序封装调用、...
  • WebIM-for-PHPWind插件是为网站社区开发的站... 功能介绍 站内好友聊天 社区访客与管理员聊天 离线好友与离线消息 用户间表情、图片传送 用户间文件传送 通知推送 桌面客户端集成 底栏菜单、快捷按钮定制 界面透明背景
  •  功能介绍站内好友聊天社区访客与管理员聊天离线好友与离线消息用户间表情、图片传送用户间文件传送通知推送桌面客户端集成底栏菜单、快捷按钮定制界面透明背景、缩放支持安装流程1. 解压安装包到PHPWind根目录2. ...
  • 长东设计Beta 0.26安装文件,目前已实现一部分功能,包含互联视窗、任务提醒、我的好友、常用网站、常用软件、我的信息、聊天机器人、OA的一些功能等。
  • 团队介绍的词频统计

    2018-04-09 23:22:00
    为了能让学习网站更加人性化、更贴合实际需求,我们在继承传统学习网站学术讨论、资源共享功能的同时,增加了好友聊天、问问、智能语音输入、智能推荐内容等新特性。 代码 import jieba import collections import ...
  • 网友可以直接通过KK客户端,即轻松实现购买课程、进入教室、课程评价、个人信息设置、添加好友、好友聊天、视频语音等多项操作。 百度传课KK实现了与用户网站账户的绑定,让用户的很多操作通过KK即可实现。大大简化...
  • 主要功能:好友搜索,朋友,FLASH聊天,IM聊天,邮件,3D聊天,论坛,明信片,博客,视频,图片,音乐等. 2.适用范围:个人站长开设社区交友网站.企业内部员工社交平台.以经营为目的的专业社交网站.大型综合网站交友平台. 3....
  • 这是一个非常简单的实现,但是它仍然继承了基本功能,例如创建帖子,评论或添加朋友。 请注意,该项目尚处于初期阶段,到目前为止,我只想显示基本功能和视图。即将有更多事情发生。 现在,我的重点是添加“邀请好友...
  • MeChat Server V5.70.zip

    2019-07-17 18:42:52
    MeChat用web方式实现文字、语音和视频聊天,语音数据可以通过局域网、ADSL、 Internet、NAT。 用途包括: 1.大、中、小网站的语音视频聊天室。 2.远程教育,特别用来学习交流外语。 3.可以作为web方式的电话...
  • Redis从入门到精通

    2019-05-29 22:47:54
    Redis简介 什么是实时系统: 瞬时可以实现某些数据的统计或者是功能实现 ...聊天室的在线好友列表 任务队列(秒杀、抢购、12306) 应用排行榜 网站访问统计 什么是Redis? Redis 是完全开源免费的,遵守B...
  • 聊天室提供强大的视频对聊功能,您可以随心所欲与好友视频通话。超清晰视频对聊给您不一样的体验。 礼物道具 全面俱到 眼花缭乱的虚拟礼物,成为您交朋识友的最佳选择;更有机会获取自己专属的个性礼物道具哦! ...
  • 网友可以直接通过KK客户端,即轻松实现购买课程、进入教室、课程评价、个人信息设置、添加好友、好友聊天、视频语音等多项操作。 传课KK实现了与用户网站账户的绑定,让用户的很多操作通过KK即可实现。大大简化了...
  • 猪八戒:获取猪八戒外包平台上面的聊天窗口,为了实现多对象同时发送信息(未实现完全)。 装机命令:爬取网宿科技内用服务平台接口,对接CDN服务器的异常进行自动化运维。 桌面监控:监控win桌面,对接邮箱平台,...

空空如也

空空如也

1 2 3 4
收藏数 64
精华内容 25
关键字:

网站好友聊天功能实现