[jQuery]將marquee plugin封裝成User Control

  • 14412
  • 0

[jQuery]將marquee plugin封裝成User Control

需求說明

  1. 需要類似跑馬燈的方式,呈現一組一組的訊息。
  2. 訊息太長時,不要破壞版面。
  3. 因為訊息數量不固定,為避免訊息尚未呈現完畢即更新訊息,所以更新訊息的時間點不使用timer定時更新。而是當最後一則訊息呈現完畢後,才撈最新資料。
  4. 當沒有資料時,應定時檢查是否有最新訊息。
  5. 當只有一筆資料時,也應定時檢查是否有最新訊息。
  6. 為避免檢查與更新資料影響頁面,採非同步的方式處理。
  7. 方便各個頁面使用,將其封裝成user control,只要設定資料來源網址就可以使用。


使用的plugin
跑馬燈的呈現,是我們的一個重點,這邊我使用了Marquee jQuery Plug-in v1.0.01,效果可以參考這裡

  1. 訊息長度超過div寬度,則類似跑馬燈,文字內容往左跑
  2. 每則訊息呈現完畢,往上翻呈現下一則訊息
  3. 訊息可以有分組的概念
  4. 呈現每一個訊息時,可以有相關的event handler callback function可以增加自己要處理的邏輯。


Sample code

  1. DashBoard.ascx
    <style type="text/css">
        .marquee .author
        {
            display: none;
        }
    </style>
    <div id="marquee-author" class="marquee-author">
    </div>
    <div id="divMarquee">
    </div>
  2. DashBoard.ascx.cs
    public partial class Portal_UserControl_DashBoard_DashBoard : System.Web.UI.UserControl
    {
        /// <summary>
        /// Gets or sets the ajax data source path.
        /// </summary>
        /// <value>
        /// The ajax data source path.
        /// </value>
        public string AjaxDataSourcePath { get; set; }
    
        /// <summary>
        /// Handles the Init event of the Page control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected void Page_Init(object sender, EventArgs e)
        {
            this.IncludeJavaScript();
            this.IncludeCSS();
        }
    
        /// <summary>
        /// Includes the CSS.
        /// </summary>
        private void IncludeCSS()
        {
            HtmlGenericControl marqueeCss = this.InitStyleSheet("~/portal/css/jquery.marquee.css");
            this.Page.Header.Controls.Add(marqueeCss);
        }
    
        /// <summary>
        /// Inits the style sheet.
        /// </summary>
        /// <param name="href">The href.</param>
        /// <returns>html control, type為css</returns>
        private HtmlGenericControl InitStyleSheet(string href)
        {
            HtmlGenericControl css = new HtmlGenericControl("link");
            css.Attributes.Add("href", ResolveUrl(href));
            css.Attributes.Add("type", "text/css");
            css.Attributes.Add("rel", "stylesheet");
    
            return css;
        }
    
        /// <summary>
        /// Includes the java script.
        /// </summary>
        private void IncludeJavaScript()
        {
            HtmlGenericControl jquery = this.InitJavaScript("~/portal/js/jquery-1.4.4.min.js");
            this.Page.Header.Controls.Add(jquery);
    
            HtmlGenericControl marquee = this.InitJavaScript("~/portal/js/jquery.marquee.js");
            this.Page.Header.Controls.Add(marquee);
            
            if (string.IsNullOrEmpty(this.AjaxDataSourcePath))
            {
                ////若AjaxDataSourcePath沒有值,則設定預設路徑
                this.AjaxDataSourcePath = "~/portal/UserControl/DashBoard/DashBoardWithMarquee.ashx";
            }
    
            ScriptManager.RegisterStartupScript(this.Page, this.Page.GetType(), "DashBoradDataSource", string.Format("var dashBoardPath = '{0}';", ResolveUrl(this.AjaxDataSourcePath)), true);
    
            HtmlGenericControl dashBoard = this.InitJavaScript("~/portal/UserControl/DashBoard/DashBoard.js");
            this.Page.Header.Controls.Add(dashBoard);
        }
    
        /// <summary>
        /// Inits the java script.
        /// </summary>
        /// <param name="src">The SRC.</param>
        /// <returns>html control, type為javascript</returns>
        private HtmlGenericControl InitJavaScript(string src)
        {
            HtmlGenericControl script = new HtmlGenericControl("script");
            script.Attributes.Add("src", ResolveUrl(src));
            script.Attributes.Add("type", "text/javascript");
    
            return script;
        }
    }
  3. DashBoardWithMarquee.ashx
    將要呈現的訊息組合成<ul>與<li>,這邊的例子是用Dictionary<string, List<string>>來存放各群組的訊息內容。
    public class DashBoardWithMarquee : IHttpHandler
    {
    
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            var result = this.GetMessage();
            context.Response.Write(result);
        }
    
        private string GetMessage()
        {
            var messageCollection = new Dictionary<string, List<string>>();
            var now = DateTime.Now.ToString();
            messageCollection.Add("訊息群組1", new List<string> { now, "訊息1", "訊息2特別長訊息2特別長訊息2特別長訊息2特別長訊息2特別長訊息2特別長訊息2特別長訊息2特別長訊息2特別長訊息2特別長", "訊息3" });
            messageCollection.Add("訊息群組2", new List<string> { now, "訊息A", "訊息B" });
    
            var divSb = new System.Text.StringBuilder();
    
            foreach (var item in messageCollection)
            {
    
                var divContent = new System.Text.StringBuilder();
                foreach (var message in item.Value)
                {
                    string liValue = string.Format(@"<li><span class=""author"">{0} :</span>{1}</li>", item.Key, message);
                    divSb.AppendLine(liValue);
                }
            }
    
            string result = string.Empty;
            if (messageCollection.Count != 0)
            {
                result = string.Format(@"<ul id=""marquee"" class=""marquee"">{0}</ul>", divSb.ToString());
            }
    
            return result;
        }
    
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
  4. DashBoard.js
    var rotateTime = 10000;
    $(document).ready(function () {
        MarqueeBinding();
        //每10秒檢查一次是否需要重撈資料
        window.setInterval(checkMarquee, rotateTime);
    });
    
    function checkMarquee() {
        var liLength = $('#divMarquee').find('li').length;
        //當裡面的<li>個數為0或1的時候,需重新撈資料
        if (liLength < 2) {
            MarqueeBinding();
        }
    }
    
    function MarqueeBinding() {
        //重撈資料,先將div內容清空
        $('#divMarquee').html('');    
        //透過$(selector).load()來非同步的呼叫.ashx更新資料
        $('#divMarquee').load(dashBoardPath, "", function (d) {
            if (d.length == 0) {
                $('#marquee-author').html('');
            }
            else {
                var $liCounter;
                $("#marquee").marquee({
                    //因為每到最後一個<li>呈現結束的時候,要重新撈資料,所以只需要loop一次
                    loop: 1
    			        , init: function ($marquee, options) {
    			            $liCounter = 1;
    			            if ($marquee.is("#marquee")) options.yScroll = "bottom";
    			        }
    
    			        , beforeshow: function ($marquee, $li) {
    			            var $author = $li.find(".author");
    			            if ($author.length) {
    			                $("#marquee-author").html("<span style='display:none;'>" + $author.html() + "</span>").find("> span").fadeIn(850);
    			            }                        
    			        }
    
    			        , show: function () {
    			        }
    
    			        , aftershow: function ($marquee, $li) {
    			            var liLength = $marquee.find('li').length;
    			            //當<li>不只一個,且現在show的為最後一個<li>時,則重新繫結資料
    			            if ($liCounter > 1 && $liCounter == liLength) {
    			                MarqueeBinding();
    			            }
    			            else {
    			                var $author = $li.find(".author");
    			                if ($author.length) $("#marquee-author").find("> span").fadeOut(250);
    			            }
    			            $liCounter++;
    			        }
                });
            }
        });
    }

只要直接在.aspx上,拉進這個User Control,設定好資料來源的url,就可以使用了。


結論

相關重點整理

  1. marquee plugin的使用,將<ul>與<li>以跑馬燈方式呈現。透過相關event的callback function來控制畫面呈現方式與資料處理,在最後一個<li>呈現後,遞迴呼叫自己這個初始化跑馬燈的function。
  2. 透過$(selector).load()來非同步讀取資料與更新selector內的html,重新啟動(初始化)跑馬燈。
  3. 透過window.setInterval來定時檢查是否需要撈最新的資料。

Source code :MarqueeSample.zip


blog 與課程更新內容,請前往新站位置:http://tdd.best/