![](/img/trans.png)
[英]Is there any way to efficiently express the Javascript code like the chaining method in JQuery?
[英]Javascript: Chaining on elements like jQuery
我正在嘗試在一定程度上復制jQuery的元素操作。 現在,我發現非常有用的是.first()
選擇器。 我希望能夠鏈接這樣的功能;
getElement(selector).first().hasClass(className);
現在,我得到了2個問題(請注意,我的代碼示例已被最小化,所以請不要對錯誤處理發表任何評論。)
var getElement = function(selector, parent) {
ret = document.querySelectorAll(selector);
this.element = ret;
this.hasClass = function(className) {
className.replace('.', '');
if(this.multiple())
{
console.log('Cannot use hasClass function on multiple elements');
return false;
}
};
this.first = function() {
this.element = this.element[0];
return this;
};
return this;
};
如果我調用我的函數;
var $test = getElement('.something'); //result: nodelist with .something divs
如果我要求結果中的第一個元素;
$test.first(); //Result: First div, perfect!
但是,現在,如果我再次調用$test
,它將用first()
的結果替換elements
屬性,這意味着我“丟失”了我的舊值。 我不想丟失它們,我只想要特定功能的first()
函數。 然后我要$test
再次返回所有元素。 此外,回顧first()
現在將結束undefined
,因為只有1內左元素this
,因為它已經從對象中刪除舊的元素。
現在,我還嘗試通過返回第一個孩子而不是整個類對象來解決這個問題。
this.first = function() {
return this.element[0];
};
但是,我將$test.first().hasClass(className); //Returns ERROR, method hasClass undefined
$test.first().hasClass(className); //Returns ERROR, method hasClass undefined
這是因為.hasClass
存在於原始this
,因為我現在返回該元素,所以不再返回它。
我試圖從jQuery的庫中獲取一些東西,盡管那讓我更加困惑。
我已經搜索了這個主題,但是使用我發現的所有“鏈接方法”解決方案,它們似乎都覆蓋了對象的原始值,這不是我想要的。 另一個解決方案實際上要求我一遍又一遍地重新啟動該對象,這對我來說似乎不是很有效。感謝您的幫助。 我以為我將完全以錯誤的方式進行此操作。
-如果您可以幫助我,請說明您的解決方案為何有效。 我真的覺得,如果我理解了這一點,我對javascript的理解將會進一步擴展。 我只需要解決這個結構性(?)問題。
您外部函數中的this
指的是窗口/全局對象。
而是返回ret
變量本身。
在內部函數(這些函數成為對象的方法)中, this
按照您期望的方式運行。
這是一個替代解決方案,即使調用第first
方法,該方法也允許鏈接:
var getElement = function(selector, parent) { var ret = typeof selector == 'string' ? document.querySelectorAll(selector) : selector; ret.hasClass = function(className) { if(!this.classList) { console.log('Cannot use hasClass function on multiple elements'); return false; } else { return this.classList.contains(className); } }; ret.first = function() { return new getElement(this[0]); }; return ret; }; console.log(getElement('p').length); //2 console.log(getElement('p').first().innerHTML); //abc console.log(getElement('p').first().hasClass('test')); //true console.log(getElement('p').first().hasClass('nope')); //fase console.log(getElement('p').hasClass('test')); //false (multiple elements)
<p class="test"> abc </p> <p> def </p>
類似的方法first()
不能修改this
,應該創建一個新的對象,並返回。 您只能使用return this;
在修改元素而不是返回從元素派生的信息的方法中。
this.first = function() {
return new getElement(this.element[0]);
};
請注意,您必須使用new getElement
來創建對象,而不僅僅是getElement
。
這也需要更改構造函數,因此它可以接受選擇器字符串或元素:
var getElement = function(selector, parent) {
var ret = typeof selector == "string" ? document.querySelectorAll(selector) : [selector];
...
}
您還應該考慮通過將方法放在原型中而不是在每個對象中定義方法,以適當的OO方式進行操作。
var getElement = function(selector, parent) {
var ret = typeof selector == "string" ? document.querySelectorAll(selector) : [selector];
this.element = ret;
};
getElement.prototype.hasClass = function(className) {
className.replace('.', '');
if (this.multiple()) {
console.log('Cannot use hasClass function on multiple elements');
return false;
}
};
getElement.prototype.first = function() {
return new getElement(this.element[0])
};
我認為最簡單的方法是返回一個包含所選節點的新類。 那將是最簡單的解決方案,因為您實際上不想突變任何先前的選擇器。
我舉了一個小例子,使用一些ES6,它使某些事情變得更容易使用,並且還帶有$
來啟動所做的選擇。
您會注意到,首先進行的任何選擇都只是調用本機document.querySelectorAll
但返回一個新的Node
類。 first
和last
方法也都返回這些元素。
最后, hasClass
應該在當前節點選擇中的所有元素上起作用,因此它將迭代當前節點,並檢查其中的所有類, hasClass
返回一個簡單的布爾值,因此您無法繼續在那里進行方法鏈接。
您希望鏈接的任何方法都應:
this
對象(當前節點) this
對象的元素作為新節點,以便可以在此處進行任何進一步的操作 const $ = (function(global) { class Node extends Array { constructor( ...nodes ) { super(); nodes.forEach( (node, key) => { this[key] = node; }); this.length = nodes.length; } first() { return new Node( this[0] ); } last() { return new Node( this[this.length-1] ); } hasClass( ...classes ) { const set = classes.reduce( (current, cls) => { current[cls] = true; return current; }, {} ); for (let el of this) { for (let cls of el.classList) { if (set[cls]) { return true; } } } return false; } } global.$ = function( selector ) { return new Node( ...document.querySelectorAll( selector ) ); }; return global.$; }(window)); let selector = $('.foo'); let first = selector.first(); // expect 1 console.log(first[0].innerHTML); let last = selector.last(); console.log(last[0].innerHTML); // expect 4 console.log( first.hasClass('foo') ); // expect true console.log( first.hasClass('bar') ); // expect false console.log( selector.hasClass('foo') ); // expect true console.log( selector.hasClass('bar') ); // expect true
<div class="foo">1</div> <div class="foo">2</div> <div class="foo bar">3</div> <div class="foo">4</div>
這是我將如何處理的方法:
Search
,其任務是根據輸入查找元素。 使用構造函數是正確的OO編程,並且您還具有在原型中定義一次方法的優點,並且所有實例都可以訪問它們。 this
)是具有數字屬性和長度的類似數組的對象,以便您可以輕松地以傳統方式遍歷每個匹配的元素(使用for
循環, [].forEach
等) 。 getElement
的函數,該函數將使用構造函數並返回結果,而不必始終使用new
關鍵字。 由於該函數返回構造函數的實例,因此您可以像平時那樣鏈接所需的方法。 first
使用構造函數來創建新實例,而不是修改原始實例,因為其作用是返回第一個元素,而不是刪除除第一個元素以外的所有內容。 片段:
;(function () { function Search (value) { var elements = []; /* Check whether the value is a string or an HTML element. */ if (typeof value == "string") { /* Save the selector to the context and use it to get the elements. */ this.selector = value; elements = document.querySelectorAll(value); } else if (value instanceof Element) elements.push(value); /* Give a length to the context. */ this.length = elements.length; /* Iterate over every element and inject it to the context. */ for (var i = 0, l = this.length; i < l; i++) this[i] = elements[i]; } /* The method that returns the first element in a Search instance. */ Object.defineProperty(Search.prototype, "first", { value: function () { return new Search(this[0]); } }); /* The global function that uses the Search constructor to fetch the elements. */ window.getElement = (value) => new Search(value); /* Create a reference to the prototype of the constructor for easy access. */ window.getElement.fn = Search.prototype; })(); /* Get all elements matching the class, the first one, and the first's plain form. */ console.log(getElement(".cls1")); console.log(getElement(".cls1").first()); console.log(getElement(".cls1").first()[0]);
/* ----- CSS ----- */ .as-console-wrapper { max-height: 100%!important; }
<!----- HTML -----> <div id = "a1" class = "cls1"></div> <div id = "a2" class = "cls1"></div> <div id = "a3" class = "cls1"></div>
例:
在此示例中,我將一個名為hasClass
的新方法添加到構造函數的原型中。
/* The method that returns whether the first element has a given class. */ Object.defineProperty(getElement.fn, "hasClass", { value: function (value) { return this[0].classList.contains(value); } }); /* Check whether the first element has the 'cls2' class. */ console.log(getElement(".cls1").first().hasClass("cls2"));
<!----- HTML -----> <script src="//pastebin.com/raw/e0TM5aYC"></script> <div id = "a1" class = "cls1 cls2"></div> <div id = "a2" class = "cls1"></div> <div id = "a3" class = "cls1"></div>
您可以更新getElement
以便在向其發送元素時再次返回。
var getElement = function(selector, parent) { var ret = null if (typeof selector === "string") { ret = document.querySelectorAll(selector); } else { ret = selector } this.element = ret; this.hasClass = function(className) { className.replace('.', ''); if (this.multiple()) { console.log('Cannot use hasClass function on multiple elements'); return false; } }; this.first = function() { this.element = getElement(this.element[0]); return this; }; return this; }; var test = getElement(".foo"); console.log(test.first()) console.log(test.first().hasClass)
<div class="foo">1</div> <div class="foo">2</div> <div class="foo">3</div> <div class="foo">4</div>
您可以使用.querySelectorAll()
,spread元素和Array.prototype.find()
,后者返回數組中的第一個匹配項或undefined
匹配項
const getElement = (selector = "", {prop = "", value = "", first = false} = {}) => { const el = [...document.querySelectorAll(selector)]; if (first) return el.find(({[prop]:match}) => match && match === value) else return el; }; let first = getElement("span", {prop: "className", value: "abc", first: true}); console.log(first); let last = getElement("span"); console.log(all);
<span class="abc">123</span> <span class="abc">456</span>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.