Создание чата на AJAX и jQuery. Часть 2

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 31.10.2015

В прошлый раз мы определили контроллер и модель, а теперь создадим всю остальную часть чата. Вначале определим представления.

Код главного представления Index.cshtml будет выглядеть следующим образом:

@model AjaxChat.Models.ChatModel
@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Чат на Ajax и JQuery</title>
    @Styles.Render("~/Content/Site.css")
</head>
<body>
    <div id="Username">
    </div>
    <div id="LastRefresh">
    </div>
    <div id="container">
        <div id="loginBlock">
            Введите имя :
            <input type="text" id="txtUserName" />
            <button id="btnLogin" value="Войти">Войти</button>
        </div>
    </div>
    <div id="Error">
    </div>
    @Ajax.ActionLink("Login", "Index", new { user = "" }, 
        new AjaxOptions { UpdateTargetId = "container", OnFailure = "LoginOnFailure", OnSuccess = "LoginOnSuccess" }, 
        new { @id = "LoginButton", @style = "visibility:hidden;" })
    
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/scripts/jquery.unobtrusive-ajax.min.js")
    @Scripts.Render("~/Scripts/chat.js")
</body>
</html>

Это представление без мастер-страницы. Элемент div с id="Username" будет отображать ник пользователя. Блок с id="LastRefresh предназначен для отображения времени последнего обновления чата, а div c id="Error" - для вывода ошибок, которые могут возникнуть.

И для собственно логина у нас есть текстовое поле и кнопка. Однако при вводе ника и нажатии на кнопку данные сразу не будут передаваться на сервер, так как это не форма. Реальная отправка данных на сервер будет происходить с помощью ajax-ссылки, которая будет иметь id = "LoginButton":

@Ajax.ActionLink("Login", "Index", new { user = "" }, 
        new AjaxOptions { UpdateTargetId = "container", OnFailure = "LoginOnFailure", OnSuccess = "LoginOnSuccess" }, 
        new { @id = "LoginButton", @style = "visibility:hidden;" })

При нажатии на ссылку будет происходить обновление блока с id="container". За счет этого будет происходить частичное обновление текущей страницы с помощью ajax, а не обычная перезагрузка страницы. Но сами мы на ссылку нажимать не будем. Мы ее даже видеть не будем, так как у нее установлен стиль "visibility:hidden;"

Нажатие будет происходить автоматически в поключаемом в представлении файле chat.js:

$(document).ready(function () {

    // логин
    $("#btnLogin").click(function () {
        var nickName = $("#txtUserName").val();
        if (nickName) {
            // формируем ссылку с параметрами, по которой идет обращение
            var href = "/Home?user=" + encodeURIComponent(nickName);
            href = href + "&logOn=true";
            $("#LoginButton").attr("href", href).click();

            //установка поля с ником пользователя
            $("#Username").text(nickName);
        }
    });
});

//при успешном входе загружаем сообщения
function LoginOnSuccess(result) {

    Scroll();
    ShowLastRefresh();

    //каждые пять секунд обновляем чат
    setTimeout("Refresh();", 5000);

    //отправка сообщений по нажатию Enter
    $('#txtMessage').keydown(function (e) {
        if (e.keyCode == 13) {
            e.preventDefault();
            $("#btnMessage").click();
        }
    });

    //установка обработчика нажатия кнопки для отправки сообщений
    $("#btnMessage").click(function () {
        var text = $("#txtMessage").val();
        if (text) {

            //обращаемся к методу Index и передаем параметр "chatMessage"
            var href = "/Home?user=" + encodeURIComponent($("#Username").text());
            href = href + "&chatMessage=" + encodeURIComponent(text);
            $("#ActionLink").attr("href", href).click();
        }
    });

    //обработчик кнопки выхода из чата
    $("#btnLogOff").click(function () {

        //обращаемся к методу Index и передаем параметр "logOff"
        var href = "/Home?user=" + encodeURIComponent($("#Username").text());
        href = href + "&logOff=true";
        $("#ActionLink").attr("href", href).click();

        document.location.href = "Home";
    });
}

//при ошибке отображаем сообщение об ошибке при логине
function LoginOnFailure(result) {
    $("#Username").val("");
    $("#Error").text(result.responseText);
    setTimeout("$('#Error').empty();", 2000);
}

// каждые пять секунд обновляем поле чата
function Refresh() {
    var href = "/Home?user=" + encodeURIComponent($("#Username").text());

    $("#ActionLink").attr("href", href).click();
    setTimeout("Refresh();", 5000);
}

//Отображаем сообщение об ошибке
function ChatOnFailure(result) {
    $("#Error").text(result.responseText);
    setTimeout("$('#Error').empty();", 2000);
}

// при успешном получении ответа с сервера
function ChatOnSuccess(result) {
    Scroll();
    ShowLastRefresh();
}

//скролл к низу окна
function Scroll() {
    var win = $('#Messages');
    var height = win[0].scrollHeight;
    win.scrollTop(height);
}

//отображение времени последнего обновления чата
function ShowLastRefresh() {
    var dt = new Date();
    var time = dt.getHours() + ":" + dt.getMinutes() + ":" + dt.getSeconds();
    $("#LastRefresh").text("Последнее обновление было в " + time);
}

Чтобы отправить данные по логину и нажать на ссылку, в обработчике нажатия мы прописываем следующие строки:

// формируем ссылку с параметрами, по которой идет обращение
var href = "/Home?user=" + encodeURIComponent(nickName);
href = href + "&logOn=true";
// автоклик по ajax-ссылке
$("#LoginButton").attr("href", href).click();

Поскольку в запросе к серверу передается параметр logOn=true, то метод Index при обработке этого запроса будет отправлять клиенту частичное представление ChatRoom: return PartialView("ChatRoom", chatModel);. Создадим это представление:

@using AjaxChat.Models
@model ChatModel
<div id="RefreshArea">
@{
     Html.RenderPartial("History", Model);
 }
</div>

@Ajax.ActionLink("ActionLink", "Index", new { user = "", logOn = "", logOff = "", chatMessage = "" }, 
new AjaxOptions { UpdateTargetId = "RefreshArea", OnSuccess = "ChatOnSuccess", OnFailure = "ChatOnFailure" }, 
new { @id = "ActionLink", @style = "visibility:hidden;" })

<div id="inputForm">
    <table>
        <tr>
            <td rowspan="2"><textarea id="txtMessage" rows="3"></textarea></td>
            <td><button id="btnMessage" value="Отправить" >Отправить</button></td>
        </tr>
        <tr>
            <td><button id="btnLogOff" value="Выйти">Выйти</button></td>
        </tr>
    </table>
</div>

Это частичное представление, типизированное моделью ChatModel, которая передается из метода Index. Оно содержит поля для ввода и отправки сообщений, а также кнопку выхода из чата.

Кроме того, здесь есть блок div id="RefreshArea", предназначенный непосредственно для вывода сообщений и пользователей. Для рендеринга этой информации в нем идет обращение к частичному представлению History, которое мы сейчас создадим. И также тут есть невидимая ajax-ссылка, обновляющая блок div id="RefreshArea":

@Ajax.ActionLink("ActionLink", "Index", new { user = "", logOn = "", logOff = "", chatMessage = "" }, 
new AjaxOptions { UpdateTargetId = "RefreshArea", OnSuccess = "ChatOnSuccess", OnFailure = "ChatOnFailure" }, 
new { @id = "ActionLink", @style = "visibility:hidden;" })

В вышерассмотренном файле javacript при удачном логине вызывается функция LoginOnSuccess, которая в свою очередь вызывает функцию Refresh():

function Refresh() {
    var href = "/Home?user=" + encodeURIComponent($("#Username").text());

    $("#ActionLink").attr("href", href).click();
    setTimeout("Refresh();", 5000);
}

Эта функция опять же формирует строку запроса с параметрами для ajax-ссылки и производит автоклик на нее. В результате блок div id="RefreshArea" будет обновляться новыми данными каждые пять секунд.

Подобное действие будет происходить также и при нажатии на кнопку отправки сообщения в чат:

var href = "/Home?user=" + encodeURIComponent($("#Username").text());
href = href + "&chatMessage=" + encodeURIComponent(text);
$("#ActionLink").attr("href", href).click();

И поскольку в обоих случаях при передаче параметров в метод Index контроллера параметры logOn и logOff будут не установлены, то метод Index в ответ будет возвращать частичное представление History.cshtml:return PartialView("History", chatModel);

Теперь создадим само частичное представление History.cshtml:

@using AjaxChat.Models
@model ChatModel
<div id="Users">
    <p><b>В чате онлайн: @Model.Users.Count</b></p>
    @foreach (ChatUser user in Model.Users)
    {
        <p>@user.Name</p>
    }
</div>
<div id="Messages">
    @foreach (ChatMessage msg in Model.Messages)
    {
        <p>
            @msg.Date<br />
            @if (msg.User != null)
            {
                <b>@(msg.User.Name + ":")</b> @msg.Text
            }
            else
            {
                <span class="serverMes">@msg.Text</span>
            }
        </p>
    }
</div>

В заключении можно еще как-нибудь стилизовать приложение. В итоге должно получиться примерно так. При запуске мы увидим поле логина:

Создание чата на ASP.NET MVC

И при удачном входе в чат уже сможем читать и посылать сообщения:

Создание чата на jQuery и AJAX
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850