JavaScript模板和事件处理

4

我曾经提出过一个有关如何避免在JS中编写HTML的问题,然后一些人告诉我可以使用JavaScript模板,例如jQuery/template插件等。

在生成静态HTML时,这是一个不错的思路,例如:

<ul id="productList"></ul>

<script id="productTemplate" type="text/x-jquery-tmpl">
    <li><a>${Name}</a> (${Price})</li>
</script>

<script type="text/javascript">
    var products = [
        { Name: "xxx", Price: "xxx" },
        { Name: "yyy", Price: "xxx" },
        { Name: "zzz", Price: "xxx" }
    ];

    // Render the template with the products data and insert
    // the rendered HTML under the "productList" element
    $( "#productTemplate" ).tmpl( products )
        .appendTo( "#productList" );
</script>

然而,当我试图将某些事件绑定到生成的html时,我遇到了一些问题。

例如,我有一个页面,用户可以通过价格/名称/位置搜索一些产品。

所以我有三个函数:

searchByPrice(lowPrice,highPrice,productType,currentPage)
searchByName(name,productType,currentPage);
searchByLocation(location,currentpage);

以上所有的功能在服务器端都有相关的方法,并且它们将使用 XML 格式返回产品。

由于它们将返回如此多的项目,因此我必须对它们进行分页,"currengPage" 用于告诉服务器端应返回哪些结果。

当客户端从服务器端获取结果后,现在可以使用 JavaScript 在 div 中显示它们,并在可能的情况下创建分页栏。

在了解模板之前,我会使用这种方式(我最讨厌的方式,尽力避免):

function searchByPrice(lowPrice,highPrice,productType,currentPage){
    var url="WebService.asmx/searchByPrice?low="+lowPrice="&high="+highPrice+"&curPage="+currentPage;
    //code to create the xmlHttp object
    xmlhttp.open("GET",url,true);
    xmlhttp.onreadystatechange=function(){
        if (xmlhttp.readyState==4 && xmlhttp.status==200){
            var i=0;
            var Prohtml="";
            var proList=parseProductList(xmlhttp.responseText);
            for(i=0;i<prolist.length;i++){
                Prohtml+="<li><a href='#'>"+prolist[i].name+"</a> ("+prolist[i].price"+)</li>";
            }


            //generate the paging bar:
            var totleResult=getTotleResultNumber(xmlhttp.responseText);
            if(totleResult>10){
                var paghtml="<span>";
                //need the paging
                var pagNum=totleResult/10+1;
                for(i=1;i<=pagenum;i++){
                    paghtml+="<a onclick='searchByPrice(lowPrice,highPrice,productType,currentPage+1)'>i</a>";
                    //here the synax is not right,since I am really not good at handle the single or doule '"' in this manner.

                    //also if in the searchByName function,the click function here should be replaced using the searchByName(...)


                }

            }
        }
    }

}

在这个示例中,使用模板生成“Prohtml”非常容易,因为它们没有事件处理,但是对于“paghtml”,不同的搜索类型具有不同的点击功能。那么,如何处理呢?
2个回答

3
首先,您可以简单地使用$.get()$.ajax()来进行AJAX调用。
其次,您可以使用.live().delegate()将事件绑定到不存在的元素上。
第三,您可以使用锚元素中的数据属性作为传递事件处理程序参数的方式,请参见.data()
因此,要重写您的函数,您可能需要像以下这样做:
function searchByPrice(event) {
    $this = $(this);
    var lowPrice = $this.data('lowPrice'),
        highPrice = $this.data('lowPrice'), 
        productType = $this.data('productType'),
        currentPage = $this.data('currentPage');

    var url = "WebService.asmx/searchByPrice?low=" + lowPrice = "&high=" + highPrice + "&curPage=" + currentPage;

    $.get(url, function(data, textStatus, jqXHR) {
        var i = 0;
        var Prohtml = "";
        var proList = parseProductList(data);
        for (i = 0; i < prolist.length; i++) {
            Prohtml += "<li><a href='#'>" + prolist[i].name + "</a> (" + prolist[i].price "+)</li>";
        }

        //generate the paging bar:
        var totleResult = getTotleResultNumber(data);
        if (totleResult > 10) {
            var paghtml = "<span>";

            //need the paging
            var pagNum = totleResult / 10 + 1;
            for (i = 1; i <= pagenum; i++) {
                paghtml += '<a class="pagelink" ' +
                    'data-lowPrice="' + lowPrice + '" ' +
                    'data-highPrice="' + highPrice + '" ' +
                    'data-productType="' + productType + '" ' +
                    'data-currentPage="' + (currentpage + 1) + '">' + i + '</a>';
                //here the synax is not right,since I am really not good at handle the single or doule '"' in this manner.

                //also if in the searchByName function,the click function here should be replaced using the searchByName(...)

            }
        }
    });
}


$(document).ready(function(){
    $("a.pagelink").live('click', searchByPrice);
});

3

两种方式之一:

使用document.createElement或一个小的(如果你要做很多这样的事情),而不是构建HTML字符串来创建DOM元素,这将允许您以通常的方式立即附加事件。

或者

为需要使用事件处理程序的每个元素提供唯一的ID,并建立一个事件列表,在HTML被插入文档后再将其附加到元素上。

E.g.:

var eventHandlers = []
  , eventCount = 0;

for (i = 1; i <= pagenum; i++) {
    var id = "search" + eventCount++;
    html += "<a id='" + id + "'>" + i + "</a>";
    eventHandlers.push([id, 'click',
                        handler(searchByPrice, lowPrice, highPrice, productType, currentPage + i)])
}

// Later...
someElement.innerHTML = html;
registerEvents(eventHandlers);

其中 registerEvents 是:

function registerEvents(eventHandlers) {
  for (var i = 0, l = eventHandlers.length; i < l; i++) {
    var eventHandler = eventHandlers[i],
        id = eventHandler[0],
        eventName = eventHandler[1],
        func = eventHandler[2];
    // Where addEvent is your cross-browser event registration function
    // of choice...
    addEvent(document.getElementById(id), eventName, func);
  }
}

handler只是一种快速关闭所有传入参数的方法:

/**
 * Creates a fnction which calls the given function with any additional
 * arguments passed in.
 */
function handler(func) {
  var args = Array.prototype.slice.call(arguments, 1);
  return function() {
    func.apply(this, args);
  }
}

我在DOMBuilder库的HTML生成部分使用类似于这样的方法(但在必要时自动添加唯一ID),它提供了一个方便的方法,用于从定义的内容生成HTML,并将其插入到给定元素中的innerHTML中,并注册任何存在的事件处理程序。它定义内容的语法独立于输出模式,这使得你可以在大多数情况下无缝切换DOM和HTML输出。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接