2012-09-03 19 views
5

我試圖做一個jQuery UI的日曆使Ajax調用被點擊時的日期上, 但我前幾天遇到了一個問題。 我發現的代碼,理應做到這一點的一個片段,但我發現它使用jQuery的自定義選擇。該代碼給了我一個錯誤,所以我開始挖掘自定義選擇器,以瞭解更多關於它們。到目前爲止,我還沒有找到爲什麼我會得到這種奇怪的行爲。jQuery的定製選擇,「不確定」

這裏是一個圖片希望清楚的事情了,我將更多地解釋它 enter image description here

我在控制檯

$('.ui-datepicker-calendar td a:test(3)') 

已經輸入後,你看,我meta2和stack2中未定義還有一件奇怪的事情,爲什麼index2返回一個#document,它應該包含元素數組的索引。

此外,該元件(EL2)甚至不是正確的元素。 看看,我叫

$('.ui-datepicker-calendar td a:test(3)')

這應該選擇所有從日曆的日期,並在第一循環中,執行console.log應打印出此

<td class=" ui-datepicker-week-end " data-handler="selectDay" data-event="click" data-month="8" data-year="2012"><a class="ui-state-default" href="#">1</a></td> 

而是我得到的第一個「一」的標籤在整個文檔中,在這種情況下,它的一個前一個月(所看到的圖片)。

如果任何人都可以在這種情況下,灑下一盞小燈,請做。 哦,還有一件事我forgout約

meta2,它應該包含這個

[ 
    ':test(argument)', // full selector 
    'test',   // only selector 
    '',    // quotes used 
    'argument'   // parameters 
] 
在我的情況下,其不確定

,並再次...

我將分享我的javascript代碼我希望它幫助

<script> 
    $(function() 
    { 
     $.expr[":"].test = function(el2,index2,meta2,stack2) 
     { 
      debugger; 
      console.log(el2); 
      console.log(index2); 
      console.log(meta2); 
      console.log(stack2); 
     } 
    }) 

    $(function() 
    { 
     function getJsonDate(year, month) 
     { 
      $.getJSON('dates.php?year='+year+'&month='+month, function(data) 
      { 
       var i = 0; 
       for (i = 0; i < data.data.length; i++) 
       { 
        debugger; 
        var myDay = data.data[i]['d']; 
        $('.ui-datepicker-calendar td a:exactly('+data.data[i]['d']+')') 
        .css({color: '#f00'}) 
        .attr('href',data.data[i]['link']) 
        .parent().attr('onclick',''); 
       } 
      }); 
     } 
     $.expr[":"].exactly = function(el, index, meta, stack) 
     { 
      debugger; 
      console.log(el); 
      console.log(index); 
      console.log(meta); 
      console.log(stack); 
      var s = meta[3]; 
      if (!s) return false; 
      return eval("/^" + s + "$/i").test($(el).text()); 
     }; 
     $('#datepicker').datepicker(
     { 
      inline: true, 
      onSelect: function(dateText, inst) 
      { 
       Date.prototype.toString = function() {return isNaN (this) ? 'NaN' : [this.getDate(), this.getMonth(), this.getFullYear()].join('/')} 
       d = new Date(dateText); 
       getJsonDate(d.getFullYear(), d.getMonth()+1); 
      }, 
      onChangeMonthYear: function(year, month, inst) 
      { 
       //alert(year); 
       //alert(month); 
       getJsonDate(year, month); 
      } 
     }); 
    }); 
</script> 
+0

我跑到今天早上花了2h相同的問題,對我來說元仍然是未定義的。以前工作完美,請保持更新,如果你會找到一些東西。謝謝。 –

+0

你好@JakubKuchar,我沒有設法使它工作,所以我做了一個解決方法,並選擇了我需要的其他方式的元素。但我仍然很想知道答案。 – Jordashiro

+3

在jQuery 1.8中更新了Sizzle,導致了對自定義選擇器創建的重要語法更改。請查看Sizzle文檔以獲取更多信息。 https://github.com/jquery/sizzle/wiki/Sizzle-Documentation它看起來像是如果你升級到jQuery 1.8.1,舊的選擇器將再次工作。 –

回答

6

最短的解釋是「jQuery的1.8.0中有一個bug,升級到1.8.1修復」,但是這並不完全回答一切。

的jQuery 1.8.x的有顯著升級後的「花俏」,引擎,這是它使用選擇。自定義選擇器的調用方式已作爲此更改的一部分進行了更改,但更改了許多選擇器的處理方式。關於規則處理順序的各種假設不再成立,等等。在各種使用情況下,它的速度也明顯更快。

即使升級到1.8.1,在處理您提供的示例時,您仍然會發現與1.7.2(1.8.x之前版本中的最新版本)相比,它們看起來有點不同。這解釋了您在選擇「頁面上的第一個<a>元素」時看到的內容。也就是說:你對自定義選擇器如何工作的期望並不是它們實際工作的方式,如果你允許循環繼續(而不是在第一次迭代中調用'調試器'),你會發現它實際上正在經歷全部 <a>元件)。簡而言之:Sizzle不能保證各種規則將被調用的順序,只是結果將匹配所有規則。

如果您確定您的自定義規則效率低於其他規則(可能是因爲您確定其他規則可能會嚴重減少匹配元素的數量),則可以通過選擇它們來強制這些規則先運行,然後調用.find()上的元素只是子集,例如:

$(".ui-datepicker-calendar").find("td a:test(3)"); 

至於「棧」被未定義,凱文·乙指出,雖然1.8.1更新恢復向後兼容性,API已經改變了,它看起來像「堆棧」不再傳遞到僞。這很有意義,實際上,由於測試可能被調用的順序改變。也就是說:堆棧在到達時是空的,因爲「查看是否有任何<a>元素與此僞選擇器匹配」是第一個被處理的規則。測試應該始終是自包含的,所以堆棧不會真的非常有用(可能只會導致混淆)。

因此,如果1.8.1恢復向後兼容性,那麼創建僞選擇器的前向兼容方法是什麼?正如您在the documentation for Sizzle's pseudo-selectors中看到的,從jQuery 1.8開始創建僞選擇器的首選方法是「createPseudo」方法($ .expr.createPseudo),它更喜歡使用閉包而不是「meta」參數。因此,對於你具體的例子,做他們的「新」的方式將是:

$.expr[":"].test = $.expr.createPseudo(function(tomatch) 
{ 
     return function(el2) 
     { 
      debugger; 
      console.log(el2); // not much else to see here 
     }; 
}) 

其中「tomatch」是參數爲:測試(...)選擇。正如你所看到的,在這個新的語法中,你正在尋找的額外參數不再是必需的。至於一些更有益的:

$.expr[":"].exactly = $.expr.createPseudo(function(s) 
{ 
    return function(el) 
    { 
     if(!s) return false; 
     return eval("/^" + s + "$/i").test($(el).text()); 
    }; 
}); 

這個版本的「精確」應該是兼容1.8+,是做事的首選*方法。

我認爲,即使在jQuery版本/ api中出現凹凸,您提供的代碼仍然不會完全按照您的要求來執行,因爲datepicker很容易在插件的突發奇想中重建。還有一個短暫的時刻,你可以知道所需的元素確實按照預期突出顯示,所以選擇器本身看起來正在工作。

一個完整的例子如下,基於您提供的樣本。您可以通過更改在1.7.2,1.8.0和1.8.1之間使用的jQuery版本來查看行爲差異。對於不同版本的兼容性,$ .expr.createPseudo的測試已添加到僞選擇器功能分配中。請注意,所有「調試器」語句已被註釋掉,因爲在datepicker中的所有日期鏈接的每次迭代中都有一個斷點變得非常乏味,並且getJSON調用已被模擬以允許測試是自包含的。

<html> 
<head> 
    <title>jQuery custom selector, "undefined"</title> 
    <!-- <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script> --> 
    <!-- <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.js"></script> --> 
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.js"></script> 
    <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.js"></script> 
    <link rel="stylesheet" 
     href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/themes/base/jquery-ui.css" /> 
    <script> 
    $(function() 
    { 
     $.expr[":"].test = $.expr.createPseudo ? 
      $.expr.createPseudo(function(tomatch) 
      { 
       return function(el2) 
       { 
//     debugger; 
        console.log(el2); 
       }; 
      }) : 
      function(el2,index2,meta2,stack2) 
      { 
    //   debugger; 
       console.log(el2); 
       console.log(index2); 
       console.log(meta2); 
       console.log(stack2); 
      }; 
    }) 

    $(function() 
    { 
     function getJsonDate(year, month) 
     { 
      //$.getJSON('dates.php?year='+year+'&month='+month, function(data) 
      //{ 
       var data = {data:[ 
        {d:1,link:"a"}, 
        {d:15,link:"b"}, 
        {d:25,link:"c"} 
       ]}; 
       var i = 0; 
       for (i = 0; i < data.data.length; i++) 
       { 
//     debugger; 
        var myDay = data.data[i]['d']; 
        $('.ui-datepicker-calendar td a:exactly('+data.data[i]['d']+')'). 
         css({color: '#f00'}). 
         attr('href',data.data[i]['link']). 
         parent().attr('onclick',''); 
       } 
      //}); 
     } 

     $.expr[":"].exactly = $.expr.createPseudo ? 
      $.expr.createPseudo(function(s) 
      { 
       return function(el) 
       { 
        if(!s) return false; 
        return eval("/^" + s + "$/i").test($(el).text()); 
       }; 
      }) : 
      function(el, index, meta, stack) 
      { 
//    debugger; 
       console.log(el); 
       console.log(index); 
       console.log(meta); 
       console.log(stack); 
       var s = meta[3]; 
       if (!s) return false; 
       return eval("/^" + s + "$/i").test($(el).text()); 
      }; 

     $('#datepicker').datepicker(
     { 
      inline: true, 
      onSelect: function(dateText, inst) 
      { 
       Date.prototype.toString = function() { 
        return isNaN (this) ? 
         'NaN' : 
         [this.getDate(), this.getMonth(), this.getFullYear()].join('/') 
       } 
       d = new Date(dateText); 
       getJsonDate(d.getFullYear(), d.getMonth()+1); 
      }, 
      onChangeMonthYear: function(year, month, inst) 
      { 
       //alert(year); 
       //alert(month); 
       getJsonDate(year, month); 
       return false; 
      } 
     }); 
    }); 
    </script> 
    <script> 
    (function($){$(function(){ 
     $("<input />"). 
      attr({type:"button", value: "run test selector"}). 
      click(function(){ 
       $(".ui-datepicker-calendar td:test(3) a"); 

       // Or, if you are certain that your test will be less-efficient than an exclusion based 
       // on parents, you could do: 
       // $(".ui-datepicker-calendar").find("td a:test(3)"); 
      }). 
      appendTo("body"); 
    })}(window.jQuery)); 
    </script> 
</head> 
<body> 
    <a href="#ignoreThisLink">.</a> 
    <a href="#ignoreThisToo">.</a> 
    <p> 
     (first, click the input box to cause the datepicker to initialise) 
    </p> 
    <input type="text" id="datepicker" /> 
</body> 
</html> 

我希望這有助於闡明一些事情。

*我說這是「首選」方法,但您仍在使用「eval」。這是非常灰心的,因爲它很慢,可能會導致意外/令人驚訝/危險的結果。一個更好的辦法來構建基於字符串的正則表達式將

return (new RegExp("^" + s + "$", "i")).test($(el).text()); 

但即使這樣有問題,如「S」可能含有正則表達式特殊字符。在這種特殊情況下,雖然正則表達式甚至沒有必要的,東西都可以通過更有效地進行測試:

return String(s).toUpperCase() === $(el).text().toUpperCase(); 

你甚至可以節省更多的滾動轉化爲關閉,給你全功能:

$.expr[":"].exactly = $.expr.createPseudo(function(s) 
{ 
     if(!s) return function(){ return false; }; 
     s = String(s).toUpperCase(); 

     return function(el) 
     { 
      return (s === $(el).text().toUpperCase()); 
     }; 
}); 
4

jquery ui datepicker具有這種功能的掛鉤。您不應該嘗試定位組成日期的DOM元素,而應該將其綁定到選擇一個元素的行爲。 jsFiddle

$('#datepicker').datepicker({ 
    onSelect: function(dateText, inst){ 
     //awesome ajax stuff based on dateText 
    } 
});​ 

編輯發表評論:,如果你需要的款式在特定日期,那麼你應該通過繪製之前,將一個自定義類瞄準它。 jsFiddle

$('#datepicker').datepicker({ 
    beforeShowDay: function(date){ 
     return [true, 'date-' + date.getDate() ]; 
    } 
}); 
+0

是的,沒錯。但我需要和我使用自定義jquery選擇器突出日期..例如。 –

+0

當然,您可以在使用'beforeShowDay'回調繪製日期之前將自定義類應用於日期,然後只定位該類。底線,首先總是使用jQuery UI API,它們是廣泛的。 – Sinetheta