2015-12-08 2 views
1

Что является лучшей ненавязчивой альтернативой сделать перекрестный псевдоним браузера для querySelector и querySelectorAll для обоего document и ElementquerySelector и querySelectorAll псевдоним

Самых прямым способом может быть

window.$ = function(selector){return document.querySelector(selector)} 
window.$$ = function(selector){return document.querySelectorAll(selector)} 

Конечно это будет не допускать цепочки, поскольку возврат функции всегда относится к document

$('.parent-class').$$('.child-classes') 

Мой лучший выбор до сих пор

window.$ = document.querySelector.bind(document); 
window.$$ = document.querySelectorAll.bind(document); 
Element.prototype.$ = Element.prototype.querySelector; 
Element.prototype.$$ = Element.prototype.querySelectorAll; 

Таким образом, мы имеем право делать предыдущий сбой выбора, хотя я не уверен, о плохих последствиях, которые это может принести, кто-нибудь есть намек/объяснение, которое может предоставлять?

У кого-нибудь есть хорошая ненавязчивая альтернатива?

+0

* как функция return всегда ссылается на документ * Что это значит? * нам разрешено делать предыдущий неудачный селектор, * Что это значит? Во всяком случае, что вы пытаетесь достичь? Сохранить несколько нажатий клавиш? –

+0

«поскольку функция return всегда ссылается на документ» - означает, что в первом примере, когда мы возвращаем функцию с document.qs, результат, очевидно, всегда ссылается на документ. «нам разрешено делать предыдущий неудачный селектор» - означает, что предыдущий неудачный селектор ($ ('. Parent-class'). $$ ('. Child-classes')) работает прикованным и с контекстом. Да, пытаясь сохранить нажатия клавиш и читаемость. – 0Ds0

ответ

4

ненавязчивым альтернатива

сделать обертку, чтобы не расширять другие/родные структуры, назвать это что-то вряд ли к конфликту

var Σ = (function() { 
    function Found(nodes) { 
     this.nodes = nodes; 
    } 
    function find(selector) { 
     var nodes; 
     if (this instanceof Found) { 
      nodes = Array.prototype.map.call(this.nodes, e => Array.prototype.slice.call(e.querySelectorAll(selector))); 
      nodes = Array.prototype.concat.apply([], nodes); 
      return new Found(nodes); 
     } 
     if (this === window) 
      return new Found(Array.prototype.slice.call(document.querySelectorAll(selector))); 
     return new Found(Array.prototype.slice.call(this.querySelectorAll(selector))); 
    } 
    Found.prototype.find = find; 
    return find; 
}()); 

Так что вы могли бы сделать что-то вроде

Σ('.answer').find('pre').nodes; 

Чтобы получить все узлы <pre> (которые являются биты кода) в ответах здесь. Вы можете цепью .find столько, сколько хотите.


кросс-браузер

Что с JQuery?

+0

голосование за кросс-браузерную часть. –

3

Лучшая ненавязчивая альтернатива не сделать такой псевдоним. Это еще одна вещь, о которой нужно помнить. Другое дело, что люди, смотрящие на ваш код, изучают, вероятно, нарушают функции автозаполнения и синтаксиса IDE, а также загрязняют прототипы.

Однако, если вы хотите перейти по этому пути, тем не менее, это займет специальную технику, чтобы связать что-либо от $$ и Element.$$, так как они возвращают списки узлов. Во-первых, мы сделаем $$ возвращать массив:

window.$$ = function(sel) { 
    return Array.prototype.slice.call(document.querySelector(sel)); 
} 

И то же самое для Element.$$. Теперь мы можем увеличить в Array прототип:

Array.prototype.$ = function(sel) { 
    var result = []; 
    for (var i = 0; i < this.length; i++) { 
    var sub = this[i].querySelector(sel); 
    if (sub) result.push(sub); 
    } 
    return result; 
}; 

идти вперед и переписать это с помощью map и/или filter и т.д., если это подходит для вашей фантазии.

Теперь вы можете сделать:

$$('.class1').$('span') 

Кроме того, вы можете определить версию $$ на Array, следующим образом:

Array.prototype.$$ = function(sel) { 
    var result = []; 
    for (var i = 0; i < this.length; i++) { 
    var elts = this[i].querySelectorAll(sel); 
    for (var j = 0; j < elts.length; j++) { 
     result.push(elts[j]); 
    } 
    } 
    return result; 
; 

Это объединяет все нодлисто в результате querySelectorAll вызовов на каждый члене входного нодлиста в один массив.

Если вы хотите цепи что-то вроде setAttribute, вам необходимо определить версии для обоих Element и Array:

Element.prototype.setAttributeChainable = function() { 
    this.setAttribute.apply(this, arguments); 
    return this; 
} 

Array.prototype.setAttributeChainable = function() { 
    for (var i = 0; i < this.length; i++) { 
    this[i].setAttribute.apply(this[i], arguments); 
    } 
    return this; 
} 

Чтобы сделать это не в состоянии молча, когда $ не находит ничего, организовать для того, чтобы вернуть пустой массив в этом случае:

window.$ = function(sel) { 
    return document.querySelector(sel) || []; 
}; 

и то же самое для Element.$.

Теперь вы можете сделать

$$('.class1') . 
    $$('span') . 
    setAttributeChainable('style', 'color:blue') . 
    $('a') . 
    setAttributeChainable('href', 'google.com'); 

Теперь продолжайте это упражнение с другим API, которые вы хотите сделать змеевидное и/или применимый к узлу списка.

Если у вас есть возражения против добавления прототипа Array, вам нужно будет найти другой подход.

+2

Ничего себе, вопрос, задающий мнения, получил мнение, что оп не нравится. –

2

Я также использую подход bind для создания псевдонима.

var $ = document.querySelector.bind(document); 
var $$ = document.querySelectorAll.bind(document); 

Для элемента я использую функцию и apply так, что он будет вести себя так, как если бы вы назвали его «VanillaJS» путь.

Element.prototype.$ = function() { 
    return this.querySelector.apply(this, arguments); 
}; 

Element.prototype.$$ = function() { 
    return this.querySelectorAll.apply(this, arguments); 
}; 

Вот пример:

var $ = document.querySelector.bind(document); 
 
var $$ = document.querySelectorAll.bind(document); 
 

 
Element.prototype.$ = function() { 
 
    return this.querySelector.apply(this, arguments); 
 
}; 
 

 
Element.prototype.$$ = function() { 
 
    return this.querySelectorAll.apply(this, arguments); 
 
}; 
 

 
alert($('.foo').innerHTML); 
 
alert('There are ' + $$('.foo').length + ' `.foo` nodes'); 
 

 
var parent = $('.parent'); 
 
alert(parent.$('.child').innerText); 
 
alert('There are ' + parent.$$('.child').length + ' children');
<!DOCTYPE html> 
 
<html> 
 

 
<head> 
 
    <meta charset="utf-8"> 
 
    <title>JS Bin</title> 
 
</head> 
 

 
<body> 
 
    <div class=foo>It works!</div> 
 
    <div class=foo>It worked again!</div> 
 
    <div class=parent>Parent 
 
    <div class=child>Child</div> 
 
    <div class=child>Another Child</div> 
 
    </div> 
 
</body> 
 

 
</html>

Вы должны создать что-то совсем немного более сложный, если вы хотите цепочки. Возможно, вы захотите проверить Bliss для облегченной (~ 3kb) библиотеки, которая поддерживает цепочку, но больше похожа на VanillaJS, чем на jQuery.

+0

Но ваш 'Element.prototype. $ = Function() { возвращает this.querySelector.применять (это, аргументы); }; 'в точности эквивалентен« Element.prototype »OP. $ = Element.prototype.querySelector;'. Собственно, это тонко отличается; ваш будет вызывать 'querySelector', определенный непосредственно в элементе, если он существует. –

Смежные вопросы