Saya ingin mendapatkan semua simpul teks turunan dari elemen, sebagai koleksi jQuery. Apa cara terbaik untuk melakukannya?
Saya ingin mendapatkan semua simpul teks turunan dari elemen, sebagai koleksi jQuery. Apa cara terbaik untuk melakukannya?
Jawaban:
jQuery tidak memiliki fungsi yang mudah untuk ini. Anda perlu menggabungkan contents()
, yang akan memberikan simpul anak saja tetapi termasuk simpul teks, dengan find()
, yang memberikan semua elemen turunan tetapi tidak ada simpul teks. Inilah yang saya buat:
var getTextNodesIn = function(el) {
return $(el).find(":not(iframe)").addBack().contents().filter(function() {
return this.nodeType == 3;
});
};
getTextNodesIn(el);
Catatan: Jika Anda menggunakan jQuery 1.7 atau yang lebih lama, kode di atas tidak akan berfungsi. Untuk memperbaiki ini, ganti addBack()
dengan andSelf()
. andSelf()
tidak digunakan lagi addBack()
sejak 1,8 dan seterusnya.
Ini agak tidak efisien dibandingkan dengan metode DOM murni dan harus menyertakan solusi buruk untuk kelebihan contents()
fungsi jQuery (berkat @rabidsnail dalam komentar untuk menunjukkan hal itu), jadi di sini adalah solusi non-jQuery menggunakan fungsi rekursif sederhana. The includeWhitespaceNodes
kontrol parameter apakah atau tidak node teks spasi termasuk dalam output (di jQuery mereka secara otomatis disaring).
Pembaruan: Fixed bug ketika includeWhitespaceNodes palsu
function getTextNodesIn(node, includeWhitespaceNodes) {
var textNodes = [], nonWhitespaceMatcher = /\S/;
function getTextNodes(node) {
if (node.nodeType == 3) {
if (includeWhitespaceNodes || nonWhitespaceMatcher.test(node.nodeValue)) {
textNodes.push(node);
}
} else {
for (var i = 0, len = node.childNodes.length; i < len; ++i) {
getTextNodes(node.childNodes[i]);
}
}
}
getTextNodes(node);
return textNodes;
}
getTextNodesIn(el);
document.getElementById()
dulu, kalau itu yang Anda maksud:var div = document.getElementById("foo"); var textNodes = getTextNodesIn(div);
.contents()
lagian menyiratkan itu akan mencari melalui iframe juga. Saya tidak melihat bagaimana itu bisa menjadi bug.
Jauco memposting solusi yang baik dalam komentar, jadi saya menyalinnya di sini:
$(elem)
.contents()
.filter(function() {
return this.nodeType === 3; //Node.TEXT_NODE
});
jQuery.contents()
dapat digunakan dengan jQuery.filter
untuk menemukan semua simpul teks anak. Dengan sedikit sentuhan, Anda dapat menemukan simpul teks cucu juga. Tidak diperlukan rekursi:
$(function() {
var $textNodes = $("#test, #test *").contents().filter(function() {
return this.nodeType === Node.TEXT_NODE;
});
/*
* for testing
*/
$textNodes.each(function() {
console.log(this);
});
});
div { margin-left: 1em; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="test">
child text 1<br>
child text 2
<div>
grandchild text 1
<div>grand-grandchild text 1</div>
grandchild text 2
</div>
child text 3<br>
child text 4
</div>
Saya mendapatkan banyak node teks kosong dengan fungsi filter yang diterima. Jika Anda hanya tertarik untuk memilih node teks yang mengandung non-spasi putih, coba tambahkan nodeValue
persyaratan untuk filter
fungsi Anda , seperti sederhana $.trim(this.nodevalue) !== ''
:
$('element')
.contents()
.filter(function(){
return this.nodeType === 3 && $.trim(this.nodeValue) !== '';
});
Atau untuk menghindari situasi aneh di mana konten terlihat seperti spasi, tetapi tidak (misalnya ­
karakter tanda hubung lunak , baris baru \n
, tab, dll.), Anda dapat mencoba menggunakan Ekspresi Reguler. Misalnya, \S
akan cocok dengan karakter non-spasi putih:
$('element')
.contents()
.filter(function(){
return this.nodeType === 3 && /\S/.test(this.nodeValue);
});
Jika Anda dapat membuat asumsi bahwa semua anak adalah Element Nodes atau Text Nodes, maka ini adalah salah satu solusinya.
Untuk mendapatkan semua simpul teks anak sebagai koleksi jquery:
$('selector').clone().children().remove().end().contents();
Untuk mendapatkan salinan elemen asli dengan anak-anak non-teks dihapus:
$('selector').clone().children().remove().end();
Untuk beberapa alasan contents()
tidak bekerja untuk saya, jadi jika itu tidak berhasil untuk Anda, inilah solusi yang saya buat, saya buat jQuery.fn.descendants
dengan opsi untuk memasukkan node teks atau tidak
Pemakaian
Dapatkan semua keturunan termasuk simpul teks dan simpul elemen
jQuery('body').descendants('all');
Dapatkan semua keturunan hanya mengembalikan node teks
jQuery('body').descendants(true);
Dapatkan semua keturunan hanya mengembalikan node elemen
jQuery('body').descendants();
Coffeescript Asli :
jQuery.fn.descendants = ( textNodes ) ->
# if textNodes is 'all' then textNodes and elementNodes are allowed
# if textNodes if true then only textNodes will be returned
# if textNodes is not provided as an argument then only element nodes
# will be returned
allowedTypes = if textNodes is 'all' then [1,3] else if textNodes then [3] else [1]
# nodes we find
nodes = []
dig = (node) ->
# loop through children
for child in node.childNodes
# push child to collection if has allowed type
nodes.push(child) if child.nodeType in allowedTypes
# dig through child if has children
dig child if child.childNodes.length
# loop and dig through nodes in the current
# jQuery object
dig node for node in this
# wrap with jQuery
return jQuery(nodes)
Jatuhkan Versi Javascript
var __indexOf=[].indexOf||function(e){for(var t=0,n=this.length;t<n;t++){if(t in this&&this[t]===e)return t}return-1}; /* indexOf polyfill ends here*/ jQuery.fn.descendants=function(e){var t,n,r,i,s,o;t=e==="all"?[1,3]:e?[3]:[1];i=[];n=function(e){var r,s,o,u,a,f;u=e.childNodes;f=[];for(s=0,o=u.length;s<o;s++){r=u[s];if(a=r.nodeType,__indexOf.call(t,a)>=0){i.push(r)}if(r.childNodes.length){f.push(n(r))}else{f.push(void 0)}}return f};for(s=0,o=this.length;s<o;s++){r=this[s];n(r)}return jQuery(i)}
Versi Javascript yang tidak ditambang: http://pastebin.com/cX3jMfuD
Ini adalah browser silang, Array.indexOf
polyfill kecil termasuk dalam kode.
Bisa juga dilakukan seperti ini:
var textContents = $(document.getElementById("ElementId").childNodes).filter(function(){
return this.nodeType == 3;
});
Kode di atas menyaring textNodes dari anak-anak langsung node anak dari elemen yang diberikan.
jika Anda ingin menghapus semua tag, coba ini
fungsi:
String.prototype.stripTags=function(){
var rtag=/<.*?[^>]>/g;
return this.replace(rtag,'');
}
pemakaian:
var newText=$('selector').html().stripTags();
Bagi saya, old plain .contents()
tampaknya berfungsi mengembalikan node teks, cukup hati-hati dengan pemilih Anda sehingga Anda tahu mereka akan menjadi node teks.
Misalnya, ini membungkus semua konten teks dari TDs di meja saya dengan pre
tag dan tidak memiliki masalah.
jQuery("#resultTable td").content().wrap("<pre/>")
Saya memiliki masalah yang sama dan menyelesaikannya dengan:
Kode:
$.fn.nextNode = function(){
var contents = $(this).parent().contents();
return contents.get(contents.index(this)+1);
}
Pemakaian:
$('#my_id').nextNode();
Seperti next()
tetapi juga mengembalikan node teks.