zoukankan      html  css  js  c++  java
  • python2.0_day22_web聊天室二

    上节内容已经实现了客户端使用长轮询的方式获取消息的功能.
    但是还没有展现到前端.本节内容将实现
    1.展现消息到前端窗口.
    2.客户端之间发送图片和文件.
    3.文件上传时显示进度条

    下面我们来实现上面3个功能.
    1.展现消息到前端窗口.在展示前我们要解决一个问题.
    问题1:我们先看看前端现在虽说能点击左边好友列表,发送消息给选择的好友,但是右边的消息窗口却一直不变.
    如下.我给大神发一个111, 显示在这个window窗口,我在给小雨发一个 还是显示在这个窗口.这个肯定是不对的.应该实现得像webQQ和微信一样.点击到指定好友时,只显示和这个好友的消息纪录.
    引入


    那么我们先来解决这个问题
    后端实现思路: 1.将所有的消息存到数据库里,切换到指定用户的时候,从数据库里把消息展示出来.这种方式是后台做的.对于聊天好像不太实用,占用空间.
    前端实现思路: 1.为每一个好友创建一个消息窗口的div,默认都是hide隐藏.当选择指定的好友时,removeClass(hide)即可.这种方式可以,实现起来也不难.
    2.使用jquery中的data.每一个元素有一个data属性,可以给data属性设置值也可以取 data属性的值.如图
    引入


    这种方式可以使用.老师觉得这个data属性有些鸡肋!为什么说是鸡肋呢?因为你都用了jquery了,使用给消息窗口这个div元素设置data属性.存储 用户id:聊天内容 ,这个和创建一个字典没有任何区别.
    3. 在js中创建一个全局字典.存储 消息类型:用户id:聊天内容 ,切换不同好友的时候,先把现有的消息内容dump到字典,然后loads 新好友的内容.
    我们就采用前端实现思路的第3种方式. 在js中创建一个字典.
    那么问题来了,从哪里入手.
    当然从请求源开始.点击切换用户的函数.


    我们看这个函数要做哪些?如图


    功能是要实现如上图,但是顺序要调整下.我们应该在更改title之前把消息存起来.所以合理的函数应该是下面这样的.



    结构理清楚了.开始实现.
    现写一个全局字典,字典写到哪里都行.这里我们就写在$(document).ready(function{}) 的上面,如图:

        接下来先把老的信息存到这个全局字典.新的消息取出来.
    代码实现如图:

        这时候我们来访问测试下:


    这样我们就解决了问题1了.下面我们就把接收到的消息展示在前端
    首先看下现在收到消息的处理方法:
    function GetNewMsgs(){
    $.getJSON("{% url 'get_new_msgs' %}",function(callback){
    console.log(callback);
    GetNewMsgs();
    });
    }
    只是打印.现在前端看下:

      所以我们展示数据要有以下几步:
    1.遍历上图中array[3]这个数组
    2.分析每一个object里的from
    3.判断如果from消息来源是我正在聊的对象也就是chat-box-window正在打开的对象,就把消息append到chat-box-window的html中
    如果不是正在打开的聊天对象,那么就把消息append到全局字典消息from来源的ID下.
    4.在消息展示之前还要把每一个object拼接成html的代码.
    就是把饭回来的object 字典,整理成html代码

        鉴于把object字典整理成html代码,需要一定的代码量,那我们就把这个写成一个函数.叫做ParseNewMsgs(),于是GetNewMsgs()函数如下:

        上图说是for循环字典,其实不是的,这里后端返回来的是一个object的列表.for循环列表时取到的是下表
    我们这里要温故下html中for循环的知识了.自己看
    最终代码如下

        然后前端接收信息看下结果如图:

        接下来就是把拼接html.
    我们先处理正在聊天对象发过来的消息拼接.代码如图:

        我们先来测试下:

        我们看上图聊天已经展示到消息窗口了,但还存在上图所述问题.
    除了上面的问题,你如果是在windows下进行测试,会经常出现一方发给另外一方能收到,而另外一方发给你收不到.
    查看后台你会发现一个规律,页面刷新一次,然后在发送消息,后台就会有断开报错.报错原因就是socket断开了,你在发送消息.
    这个原因可能是windows,具体不详.记住就好.在Linux下没有这种问题.
    我们来看看前端代码改的两处.

    下面我们来拼接处理,不是正在聊的对象,如何把消息存储在全局字典里.

        我们测试看下结果:
    首先大神的账户和小雨聊.这时候说明大神聊天的对象不是"测试账户",如图

        在用测试账户给大神发信息如图:

        这时候大神的账户把聊天对象切换到测试账户,看看能不能收到消息,如图

        我们看成功了.那么我们还要实现一个功能,就是显示新消息的个数.如图:

        实现思路:
    <li contact-type='single' contact-id='{{friend.id}}' onclick="OpenChatWindow(this)" class="list-group-item">
    <span class="badge">14</span>
    <span class="contact-name">{{friend.name}}</span>
    </li>
    我们可以把 <span class="badge">14</span> 默认添加hide隐藏样式,另外把缺省14改成0.

        我们找到了元素,记得是元素,不是docment对象,所以不能是使用jquery的方法.要把找到的元素变成docment对象,之前我们用过就是加上$()即可
    于是我们可以这样实现:

        你可能会问既然元素都找到了,为啥还要转换成docment类呢?
    因为我们要用的不是这个li元素 ,而是li元素下的span元素,我们要对这个元素进行更改.

        我们总结下:
    var li_ele = $(".list-group li[contact-type='single']").filter("li[contact-id='3']")[0]
    $(li_ele).find(".badge")
    我们接下来就是对这找到的内容进行操作.

        接下来我们发送测试看看效果.

        至此消息数量的提示已经完成.但是当我们切换有消息的好友的时候,是不是应该把消息数从新改成 hide并且数量改成0.
    因此我们应该修改OpenChatWindow()函数来实现

        接下来测试如下:


    至此单对单的聊天的几本功能实现了,下面我们来实现下群组聊天是该如何实现?
    群组聊天和单人聊天有什么不一样.
    后台,处理后发给群里所有人
    前端,收消息时前端展示时逻辑有些不一样
    我们1对1 时,消息展示在好友处是根据后台返回的object 字典里的from id取到的.
    而群组我们就不能根据from id来取了.而是根据to 的id来取到群组的id,from只是发消息的人.
    因此我们改动两处,1,是sendmsg调用的后台视图函数send_msg.
    2.是前端获取消息里的消息拼接处理方法
    function GetNewMsgs(){
    $.getJSON("{% url 'get_new_msgs' %}",function(callback){
    console.log(callback);
    ParseNewMsgs(callback); //重点是要改这个函数
    GetNewMsgs();
    });
    }
    我们先来修改后台的视图函数,我们先看看现在send_msg视图函数是怎么处理消息的.

      我们把视图函数修改成如下:

      后端的视图函数就做这些修改.
    接下来就是前端取数据了.
    前端取数据需要注意的就是 消息object里的key to是消息展示的位置.from只是显示在群租聊天框的人员姓名.
    我们先看下目前的消息处理函数

      于是把前端函数改成如下:

      下面我们进行测试

      至此分组聊天的功能我们已经实现了.
    但是有一个问题我们要解决,就是在消息框中显示的发消息的人是ID而不是人员名称。这里要改成人员名称。
    简单,我们可以在发送消息时,消息字典里加入发送人员的from_name属性。
    如下:

      然后,前端在拼接消息时也修改如下:


    上面的问题解决了,几本是可以聊天了,但是实际测试下 来感觉会丢失消息,原因可能是socket的也可能是长轮询的方式有点问题,具体没有深入研究。
    先不管,我们在来实现一个功能,文件上传.
    思路: 上传用post 用ajax .后台处理的URL和和处理消息的URL是同一个。为什么可以是同一个。因为对于用户来说都是发送消息。
    那么我们就要修改后台处理get_msgs()函数了。判断前端传来的是图片还是文本信息。如果是文本就不用说了,存到队列中。
    如果是图片那么就把图片的url存到信息中。为了好判断是图片还是文本,我们就在object消息字典中再加一个key,来表示发送消息到底是什么类型。

    那么我们开始动手,顺序依然是从请求源开始。 触发这个上传文件请求的是哪里。是在消息页面中。我们想图片就不在消息里写入了。我们在emoj处写一个文件上传的前端代码。
    如图:

      代码如下:

      显示的样式很不好看,如下:

      看到小图标的样式了把,但是上面加了input的样子很丑,jquery里肯定有具有input type="file"的代码,并且好看点的。
    我们稍微调整下,让它不那么难看,然后在实现功能。

      然后在看看样子:

      然后把上面代码加上onclock事件
    <div class="chat-box-emoj">
    <!--emoj-->
    <div class="col-md-3">
    <input name="filename" type="file">
    </div>
    <div class="col-md-2">
    <span class="glyphicon glyphicon-upload" onclick="FileUpload()"></span>
    </div>
    </div>
    接下来我们就来写 FileUpload()函数,写之前我们来会想下:
    我们在bbs系统里上传图片用的form表单。form表单会有一个问题,就是上传成功后会刷新页面。
    这里我们当然不希望它刷新页面了。那么应该怎么办?就是不用form表单二用ajax异步提交文件。
    什么是ajax异步提交文件。之前ajax不支持提交文件。那时候采用在页面用一个afreem,就是在页面里搞一个其他页面框架,内连东西。这个内连框架和服务器端保持长连接,总之浪费资源又恶心。
    但是现在jquery的ajax支持异步传输文件了。
    我们就把下面这段代码作为,ajax异步上传文件的范例记住。不会就来找把。
    在写之前,我们来回忆下,之前在使用form上传文件时,前端form又两点需要注意的:1.必须是post形式才能上传文件 2。必须又一个enctype="multipart/form-data" 才能进行文件上传。
    如图:

        同样我们用ajax上传是不是也要又这两个限制条件?是的,顺便我们来说明下ajax如何实现异步文件上传的。
    首先我们知道form是可以上传文件的。那么ajax实现文件上传的思路就是,在js中实例化一个form对象,把相关数据都塞进这个form实例中。
    然后在通过ajax把这个form对象传到服务器上。
    于是范例代码如下:

        看看上图,思路是不是清晰了很多
    下面我们来看看到底塞进formdata实例中的是什么东西。
    首先要知道 $("#file_test")其实查找的是input type="file"这个标签。所以我们先给之前代码的input加一个id="file_upload"
    <input id="file_upload" name="filename" type="file">
    然后访问,打印下看看到底是个什么东西,

        就是把上面的对象给放到formdata实例里。
    上图内容要仔细看了。对于理解后面的操作有帮助。
    我们在看下ajax异步上传文件代码中有一句需要理解的:

        而上面我们提到的form表单提交后台的两个条件。就是通过下图中的两处实现的。你就记住这是必须加的

        最终前端ajax上传文件的代码如下:
    function UploadFile(){
    var formDate = new FormData();
    console.log($("#file_upload")[0].files[0]);
    formDate.append('file',$('#file_upload')[0].files[0]);

    $.ajax({
    url: "{% url 'file_upload' %}",
    type: 'POST',
    data : formDate,
    processDate: false, //tell jQuery not to process the data
    // 默认提交的post或者get请求会把后面的参数压缩成url参数专用的urlinto的格式,然后发送给后台。
    // 但是我们这里发送的是文件,所以就上面的设置就告诉浏览器不用压缩了
    contentType: false, //tell jQuery not to set contentType
    // 不要加什么请求头,说白了就是原来是什么样就是什么样,不要给formDate加其他内容了。
    success: function(data){
    console.log(data);
    //alert(data);
    }
    });
    }
    这个时候你就通过ajax提交了,提交后后台如何处理呢?必定它和form 提交的方式不一样。
    下面是不是该修改URL了, 请求源 -> url -> 视图函数 -> 前端html
    urlpatterns = [
    # url(r'^$/', views.acc_login,name='login' ), 这种写法错误,r'^$/'要改成r'^$'
    url(r'^$', views.dashboard,name='chat_dashboard' ),
    url(r'^msg_send/$',views.send_msg,name='send_msg' ),
    url(r'^new_msgs/$',views.get_new_msgs,name='get_new_msgs' ),
    url(r'^file_upload/$',views.file_upload,name='file_upload' ),
    ]
    然后在views.py中写一个file_upload视图
    def file_upload(request):
    print(request.POST)
    return HttpResponse('dddddd')
    先上传一个文件,查看下打印结果:
    function UploadFiles(){
    var formData = new FormData();
    console.log($('#file_upload')[0].files[0]);
    formData.append('file',$('#file_upload')[0].files[0]);
    $.ajax({
    url: "{% url 'file_uploads' %}",
    type: 'POST',
    data : formData,
    processDate: false, //tell jQuery not to process the data
    contentType: false, //tell jQuery not to set contentType
    success: function(data){
    console.log(data);
    //alert(data);
    }
    });
    }
    结果我们测试有报错,chrome报错如下:

        火狐浏览器报错如下:

        按照火狐浏览器报出的错误查找到一片文章如下:


    平时做表单都是跳转提交的,但是今天要做一个ajax图片异步上传,

    网上搜索了下,方法都比较老了,居然还有用flash的,

    普通的表单上传通过jquery的serialize()转换成querystring后就可以直接ajax post 上传,但是碰到文件上传就不奏效了,型号html5有个方法FormData()可以实现上传,

    我写的代码如下:

    function upThumbSubmit() {
    if(!window.FormData) { 
    alert('your brower is too old');
    return false;
    }
    var formData = new FormData($( "#upForm" )[0]);

    $.ajax({
    url:'?c=api&a=upload',
    type:'post',
    data:formData,
    dataType:'json',
    success:function(data){
    alert(data);
    return false;

    }
    });


    }

    但是报错了,错误如下

    TypeError: 'append' called on an object that does not implement interface FormData.

    既然浏览器明明显示支持formdata,为何这里显示append不是formdata接口呢?

    答案只可能是jquery重载了formdata

    在里面加上2个option,就好了,正确代码如下

    function upThumbSubmit() {
    if(!window.FormData) { 
    alert('your brower is too old');
    return false;
    }
    var formData = new FormData($( "#upForm" )[0]);

    $.ajax({
    url:'?c=api&a=upload',
    type:'post',
    data:formData,
    processData: false,
    contentType: false,
    dataType:'json',
    success:function(data){
    alert(data);
    return false;

    }
    });


    }
    才发现自己写错了,如下:

      这个小错误,我整了3小时。
    还好解决了,更改后,上传文件测试,看看后台打印什么?

      结果为空,那是不是ajax没把文件传过来。当然不是,是文件不能用request.POST获取,而是用request.FILES
    更改视图函数如下:
    def file_upload(request):
    print(request.POST,request.FILES)
    print("22222")
    return HttpResponse('dddddd')
    在此上传打印如下:

      我们看文件句柄已经传给后台了。那么接下来就修改视图函数把文件存下来就行了。
    def file_upload(request):
    print(request.POST,request.FILES)
    file_obj = request.FILES.get('file')
    new_file_name = "uploads/%s"%file_obj.name
    with open(new_file_name,"wb+") as new_file_obj:
    for chunk in file_obj.chunks():
    new_file_obj.write(chunk)
    return HttpResponse('--upload success---')
    后台异步接收文件,请参照《python2.0_day21_bbs系统评论自动加载+文章创建》一节中的解释。
    然后我们前端上传,看看后端uploads目录下有没有该文件。如图

      哈哈,文件已经上传成功了。
    现在是实现了异步上传文件。但是我们是不是想看到文件上传的进度。如何实现呢?
    接下来还有两个功能,一个是上传文件的进度条显示,
    一个是把图片显示到聊天窗口,这里不想看了。2周后再补上。因为我已经等不及看主机管理章节了。因为那是我现在能用到的
    废话不多说,咱开始。



















  • 相关阅读:
    [每日一题系列] LeetCode 1071. 字符串的最大公因子
    [每日一题系列] LeetCode 1013. 将数组分成和相等的三个部分
    git diff (19)
    WinDbg探究CLR底层(1)
    使用LINQ、Lambda 表达式 、委托快速比较两个集合,找出需要新增、修改、删除的对象
    转MySQL遇到的语法差异及解决方案
    批量拼脚本神器-NimbleText
    Visual Studio 2017中使用正则修改部分内容
    如何使用ILAsm与ILDasm修改.Net exe(dll)文件
    在Windows上安装Elasticsearch v5.4.2
  • 原文地址:https://www.cnblogs.com/zhming26/p/6084659.html
Copyright © 2011-2022 走看看