前言
對於習慣了 ASP.NET MVC Razor 模板引擎的人來說,比如我,一直在尋找前端 Javascript 端的 Razor 模板工具。這之前,我也了解到很多Javascript 端的模板工具,比如:jquery.tmpl、Knockout、front.js 等等。園子里很多大牛推薦 Knockout,比如:蔣金楠(Artech)老師、湯姆大叔(TomXu)。個人覺得 Knockout 太強大了,強大到入門都是那么的困難,我看了官網上的幾個例子,最后還是放棄了,覺得太復雜了,殺雞還需要用牛刀嗎?且並不是所有的“綁定”都要交給前端的,比如 Hello World 那個例子,FirstName、LastName、FullName 這些本該由服務器端直接輸出的東西,何必又要交給 Knockout 呢。團隊成員入門難就不適合了(PS:也許是我本人太笨,自黑一下,呵呵...)。在園子里搜了 kino.razor 一下,正好還沒有人來寫文來介紹它,於是就有了本文。kino.razor 正如官方的介紹:
kino.razor - an easy to use,razor style javascript template tool
它是一個簡單易用、Razor 風格的 Javascript 模板工具。用過之后感覺確實如此。
開始實戰
1. 首先我們來建立一個名為 Message 的模型類。
public class Message { public Guid SenderKey { get; set; } public int SenderUserId { get; set; } public string SenderName { get; set; } public string Content { get; set; } private DateTime _date { get; set; } public DateTime Date { get { return _date; } set { _date = value; _formattedDate = _date.ToLongDateString() + " " + _date.ToLongTimeString(); } } private string _formattedDate; public string FormattedDate { get { return _formattedDate; } } }
2. 建立一個名為 MessageRepository 的數據訪問類。
public class MessageRepository { // 為了演示,不保存到數據庫了 private static readonly IList<Message> dbMessage = new List<Message>() { new Message{ SenderKey = Guid.NewGuid(), SenderUserId = 1, SenderName = "張學友", Date = DateTime.Now, Content = "你好,請問今天星期幾?" }, new Message{ SenderKey = Guid.NewGuid(), SenderUserId = 2, SenderName = "李世民", Date = DateTime.Now, Content = "今天真的很冷!" }, new Message{ SenderKey = Guid.NewGuid(), SenderUserId = 3, SenderName = "王大山", Date = DateTime.Now, Content = "吃早飯了么?" }, new Message{ SenderKey = Guid.NewGuid(), SenderUserId = 4, SenderName = "劉德華", Date = DateTime.Now, Content = "要不我們今晚去游泳吧?" }, new Message{ SenderKey = Guid.NewGuid(), SenderUserId = 5, SenderName = "郭富城", Date = DateTime.Now, Content = "雙手的溫柔是你的錯!" }, }; public static IList<Message> GetAll() { return dbMessage; } public static Message AddMessge(int senderUserId, string senderName, string content) { var message = new Message { SenderKey = Guid.NewGuid(), SenderUserId = senderUserId, SenderName = senderName, Date = DateTime.Now, Content = content }; dbMessage.Add(message); return message; } }
為了演示,就增加了 2 個方法,一個得到所有的消息,另一個插入消息,不保存到數據庫了。
3. 建立一個名為 SysConst 的系統常用的資源
/// <summary> /// 系統常用的資源 /// </summary> public class SysConst { /// <summary> /// 默認的發送者ID /// </summary> public static readonly int DefaultSenderUserId = 3; /// <summary> /// 默認的發送者姓名 /// </summary> public static readonly string DefaultSenderUserName = "王大山"; }
4. 建立 Default.aspx 頁面或者 View.cshtml
首先在 Default.aspx.cs 頁面中獲取所有的消息,保存在 Messages 屬性中,供 Default.aspx 頁面調用。PS:沒有用服務器控件,才出此策。
public partial class Default : System.Web.UI.Page { /// <summary> /// 保存獲取的消息集合,供頁面調用 /// </summary> protected IList<Message> Messages { get; private set; } protected void Page_Load(object sender, EventArgs e) { if(!IsPostBack) { LoadData();// 調用加載數據的方法 } } /// <summary> /// 加載數據 /// </summary> private void LoadData() { Messages = MessageRepository.GetAll(); } }
5. 在頁面引用 css 和 js
<link href="css/bootstrap.min.css" rel="stylesheet" type="text/css" /> <link href="css/chat.css" rel="stylesheet" type="text/css" /> <script src="js/jquery-1.8.2.min.js" type="text/javascript"></script> <script src="js/kino.razor.min.js" type="text/javascript"></script>
6. 完成靜態頁面布局
效果圖:
代碼:
<div id="chat"> <div class="chat_content" style="height: 485px"> <!-- 這里是需要循環的項 --> <script type="text/template" id="temp-message-gallery"> @for(var i = 0; i < list.length; i++ ) { <div class="@list[i].msgClass"> <div class="chat_mes_title clearfix"> <span class="date" style="display: inline">@list[i].message.FormattedDate</span> <span class="name" style="display: inline">@list[i].message.SenderName</span> </div> <div class="clear"></div> <div class="chat_mes_text clearfix"> @list[i].message.Content </div> </div> } </script> </div> </div> <div class="chat_form"> <form action="#"> <button class="btn btn-success" type="button" id="sendmessage"> 發送 </button> <div class="chat_field"> <textarea id="msg" placeholder="請輸入消息"></textarea> </div> </form> </div>
不知道大家注意到那段注釋“這里是需要循環的項”下面的代碼沒有,是不是很熟悉,很爽?千萬不要以為這是用 ASP.NET MVC Razor 寫的服務器端代碼,呵呵,這就是按照 kino.razor 模板的規則來寫的,是客戶端代碼!!!!!!
其中 @list[i].msgClass 是樣式輸出,判斷這條消息是否是當前登錄用戶發的,如果不是,樣式就是“chat_message”。如果是,樣式就是“chat_message chat_mes_my”。
其中 @list[i].message 就是我們定義的 Message 模型類對應的 json 對象。
7. 把后台 Default.aspx.cs 傳遞過來的 List<Message> 序列化成 json 數組。
<% int currentUserId = SysConst.DefaultSenderUserId; // 當前用戶的 ID const string defaultClass = "chat_message"; // 默認樣式 const string mineClass = "chat_mes_my"; // 發送者是自己時的樣式 List<dynamic> list = new List<dynamic>(); if (this.Messages != null && this.Messages.Count > 0) { foreach (var msg in this.Messages) { string msgClass = msg.SenderUserId == currentUserId ? defaultClass + " " + mineClass : defaultClass; // 上面是判斷這條消息是否是當前登錄用戶發的,如果是,則添加一個樣式 list.Add(new { msgClass = msgClass, message = msg }); } } string json = new JavaScriptSerializer().Serialize(list); %>
上面是為了展示歷史消息,而做的。為了區分消息的發送者是否是自己,就自己新建了一個 dynamic 的集合,用來保存樣式值、消息對象。最后把這個 dynamic 的集合序列化成 json,放到下一步(第 8 步)中。
8. 用 kino.razor 來呈現 json 集合
<script type="text/javascript"> // 顯現所有消息的方法 function renderAllMessage(dataArray) { var htmlTempl = $("#temp-message-gallery").html();// 找到模板 var resultContent = kino.razor(htmlTempl, { list: dataArray }); // 上面就是把 json 數組傳遞給 kino.razor。list 就是我們在模板 // 中用到的變量名 $(".chat_content").append(resultContent);// 找到容器 DIV,附加 setScrollTop(); } $(document).ready(function() { // 把當前服務器的消息實體集合序列化成 JSON,然后呈現。 renderAllMessage(<%= json %>); }); // 把滾動條設置到最下,以便呈現最新的消息。 function setScrollTop() { var chatContent = $(".chat_content"); // 找到容器 DIV var scrollHeightValue = chatContent.get(0).scrollHeight; var heightValue = chatContent.height();// 得到容器的高度 var scrollTopValue = scrollHeightValue - heightValue; chatContent.scrollTop(scrollTopValue); } </script>
注釋都已經加上了,如果還不明白,請在評論里反饋,讓筆者 知道,相互學習,謝謝!
做到這里,運行,就可以看到效果了。
9. 給 發送 按鈕綁定點擊事件
代碼:
<script type="text/javascript"> $('#sendmessage').click(function () { var content = $.trim($('#msg').val()); if (content.length == 0) { alert("請輸入消息!"); return; } if (content.length > 1000) { alert("每次發送的消息不能超過 1000 字!"); return; } $('#msg').attr("disabled", "disabled"); $.ajax({ type: "POST", url: "/post-message.ashx", data: { content: content }, success: function (data) { // 返回成功后,調用呈現單條消息的方法 renderSingleMessage(data); $('#msg').removeAttr("disabled").val('').focus(); }, error: function (msg) { alert("發送失敗,請稍后再提交!"); $('#msg').removeAttr("disabled").focus(); } }); }); // 呈現單條消息 function renderSingleMessage(msg) { var msgClass = '<%= defaultClass %>'; var currentUserId = <%= currentUserId %>; if (msg.SenderUserId == currentUserId) { msgClass += ' <%= mineClass %>'; } var list = []; list[0] = { msgClass: msgClass, message: msg }; renderAllMessage(list);// 調用呈現所有消息的方法 } </script>
在 renderSingleMessage 中判斷當前消息是否是本人添加的(目前發送者肯定是自己,后期會做成聊天室的形式,基於 ASP.NET SignalR 來做。),如果是,則什么樣式,如果不是,則又是什么樣式。最后把 json 對象傳遞給上面已經定義了的 renderAllMessage 函數用來呈現。
10. 在 ashx 保存消息
新建一個名為“post-message.ashx” 的一般處理程序,完成如下代碼:
public class post_message : IHttpHandler { public void ProcessRequest(HttpContext context) { string content = context.Request.Form["content"];// 獲取消息內容 var message = MessageRepository.AddMessge(SysConst.DefaultSenderUserId, SysConst.DefaultSenderUserName, content); // 保存消息 string json = new JavaScriptSerializer().Serialize(message); context.Response.ContentType = "text/json"; context.Response.Write(json); } public bool IsReusable{get{return false;}} }
至此,流程已經走完。如果還不明白,請在評論里反饋,讓筆者 知道,相互學習,謝謝!
總結
完整的流程如下:
oo1:
002:
003:
004:
也許你還會喜歡:
一個輕量級 Javascript 模板引擎 front.js【二】
謝謝瀏覽!