Knockout : 实现复杂的web聊天窗体

    公司以前一个同事写的这个聊天的窗体,由于是采用了html拼接的方式,外加处理的时候没有合理的划分职责,导致页面js代码量非常庞大(1500行左右)。现在这哥们离职了,苦的是我们剩下的人,不多说,我先去擦把泪。

  

    公司基本没周都要求给web聊天加各种各样的功能,然后各种不能忍,权衡之后只能选择重构代码,可怜的娃娃啊。。。。

  

    本次完全采用Knockout重构,基础的东西就不多说了,学习Knockout请移步大叔的blog(多谢大叔无私分享)    http://www.cnblogs.com/TomXu/archive/2011/11/21/2257154.html

  

 

  上web聊天界面截图:

  view代码:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>后台聊天</title>
    <link rel="stylesheet" href="css/jquery.qqFace-min.css" />
    <link rel="stylesheet" href="css/index0923.css" />
    <style type="text/css">
        /*  style="display:none;"  */
    </style>
</head>

<body>
    <div class="chatDiv" id="chatDiv" style="border:1px solid #ededed;">
        <!-- 单聊 -->
        <div id="singleChat">
            <!-- 聊天联系人列表 -->
            <div class="chatLp">
                <!--div class="title"><a href="###" class="clearAll">清空</a></div-->
                <div class="title">
                    <a href="###" class="sendAll l">群发</a>
                    <a href="javascript:void(0);" class="delete r" data-bind="click:function(){viewModel.clearArray();}"></a>
                </div>
                <ul class="chatList" data-bind="template:{ name: 'demo',foreach:viewModel.viewModelArray}">
                    <!--<li><i class="ico icoOne"></i><i class="come"></i><span class="txt">八卦台湾</span></li>
                    <li class="select"><i class="ico icoOne"></i><span class="txt">八卦台湾</span></li>
                    <li><img class="ico" src="images/img.png"/><span class="txt">八卦台湾</span></li>-->

                </ul>
            </div>
            <div class="chatRp">
                <div class="chatName" data-bind="template:{ name: 'title',foreach:viewModel.selectViewModel}">

                </div>
                <!-- 对话内容 -->
                <div class="content">
                    <div id="chatMain" class="chatMain" style="overflow-y: scroll;" tabindex="5001" data-bind="template:{ name: 'content',foreach:viewModel.selectModel}">

                    </div>
                    <div class="speakInp">
                        <span class="spaeakBtn biaoq"></span>
                        <span class="spaeakBtn edit"></span>
                        <textarea class="textarea-txt" style="overflow: hidden;" data-bind="value:textContent"></textarea>
                        <a class="sub_btn" href="javascript:void(0);" data-bind="click:function(){viewModel.msgPush();}">发送</a>
                    </div>
                </div>
            </div>
            <div class="clearB"></div>
        </div>
    </div>
    <div>
        <button data-bind="click:add">Add</button>
    </div>
    <script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
    <script type="text/javascript" src="js/jquery.qqFace-min.js"></script>
    <script type="text/javascript" src="js/jquery.nicescroll.min.js"></script>
    <script src="js/jquery.tmpl.js"></script>
    <script src="js/knockout-2.0.0.debug.js"></script>
    <script type="text/x-jquery-tmpl" id="demo">

        <li data-bind="click:function() {viewModel.select($data)},css:{select:$data.data()==viewModel.selectModel()},
    event: { mouseover:function(){ viewModel.showCloseIco($data,true);}, mouseout: function(){ viewModel.showCloseIco($data,false);} }">

            <img class="ico" data-bind="css:{icoOne:$data.data().length>0}" src="${ico}"></img>
            <span class="txt">${name}</span>
            <i class="icodelete" data-bind="click:function () {viewModel.remove($data)},style:{display:$data.isShow()== true?'inline':'none'}"></i>
        </li>

    </script>

    <script type="text/x-jquery-tmpl" id="content">
        <div class="anotherIetm" data-bind="css:{selfIetm:$data.msgtype  }">
            <div class="icoP"><img src="${ico}" class="ico"></div>
            <div class="contentP">
                <span class="name">${name}</span>
                <div class="speakCon">
                    <span class="jiao"></span>
                    <div class="mainCont">${msg}</div>
                    <div class="clearB"></div>
                </div>
            </div>
            <div class="clearB"></div>
        </div>
    </script>

    <script type="text/x-jquery-tmpl" id="title">
        <span class="left">${name}</span>
        <span class="right">
            <span>您的身份:[${serverId}]</span>
        </span>
        <div class="clearB"></div>
    </script>

    <script src="ChatModel.js"></script>
    <script src="ChatViewModel.js"></script>
</body>
</html>

Model代码:

/// <reference path="js/knockout-2.0.0.debug.js" />
function LeftObject(ico, name, serverid) {
    this.ico = ico;
    this.name = name;
    this.isShow = ko.observable();
    this.data = ko.observableArray();
    this.serverId = serverid;
}


function MsgContent(msgtype, msg, name, ico) {
    this.msgtype = msgtype;
    this.msg = msg;
    this.name = name;
    this.ico = ico;
}

ViewModel代码:

/// <reference path="js/knockout-2.0.0.debug.js" />
//======================左边用户列表操作===========================
var num = 0;
var viewModel = {
    add: function () {
        num = num + 1;
        viewModel.viewModelArray.push(new LeftObject("http://www.baidu.com/img/bdlogo.png", "Test" + num,"客服-应用主"));
        if (viewModel.selectModel().length == 0) {
            viewModel.selectModel(viewModel.viewModelArray()[viewModel.viewModelArray().length - 1].data());
            viewModel.selectViewModel(viewModel.viewModelArray()[viewModel.viewModelArray().length - 1]);
        }
    },
    push: function () {
        if (viewModel.selectModel()) {
            viewModel.selectModel.push({ content: num, isSend: (num % 2 == 1) })
        }
    },
    viewModelArray: ko.observableArray()
};
viewModel.remove = function (e) {
    viewModel.viewModelArray.remove(e);

    if (viewModel.selectModel() == e.data()) {
        viewModel.selectModel([]);
    }
    viewModel.selectModel(viewModel.viewModelArray()[0].data());
    viewModel.selectViewModel(viewModel.viewModelArray()[0]);
}
viewModel.select = function (e) {
    viewModel.selectModel(e.data());
    viewModel.selectViewModel(e);
}
viewModel.selectModel = ko.observableArray();
viewModel.selectViewModel = ko.observable();

viewModel.showCloseIco = function (e,isShow) {
    e.isShow(isShow);
    //alert(e.isShow());
}

viewModel.clearArray = function () {
    viewModel.viewModelArray([]);
}

//===========================分割线 下面是聊天窗口操作函数===========================================

viewModel.msgAccept = function (data) {
    viewModel.selectModel.push(new MsgContent(true, data, "自己", "images/ico.png"));
}

viewModel.msgSend = function (data) {
    viewModel.selectModel.push(new MsgContent(false, data, "别人", "images/img.png"));
}
viewModel.textContent = ko.observable();
//模拟发送
viewModel.msgPush = function (data) {

    if (viewModel.viewModelArray().length == 0) {
        return;
    }
    var d = parseInt( Math.random()*10 % 2);
    data = viewModel.textContent();
    viewModel.textContent('');
    if (d == 0) {
        viewModel.msgSend(data);
    } else {
        viewModel.msgAccept(data);
    }
}

//=====================================================================
ko.applyBindings(viewModel);

 

posted @ 2014-11-25 18:13  Liffey  Views(383)  Comments(0Edit  收藏  举报