Tôi muốn lấy tất cả các nút văn bản con cháu của một phần tử, dưới dạng một bộ sưu tập jQuery. Cách tốt nhất để làm điều đó là gì?
Tôi muốn lấy tất cả các nút văn bản con cháu của một phần tử, dưới dạng một bộ sưu tập jQuery. Cách tốt nhất để làm điều đó là gì?
Câu trả lời:
jQuery không có chức năng thuận tiện cho việc này. Bạn cần kết hợp contents()
, sẽ chỉ cung cấp các nút con nhưng bao gồm các nút văn bản, với find()
, cung cấp tất cả các phần tử con cháu nhưng không có nút văn bản. Đây là những gì tôi nghĩ ra:
var getTextNodesIn = function(el) {
return $(el).find(":not(iframe)").addBack().contents().filter(function() {
return this.nodeType == 3;
});
};
getTextNodesIn(el);
Lưu ý: Nếu bạn đang sử dụng jQuery 1.7 trở về trước, mã ở trên sẽ không hoạt động. Để khắc phục điều này, thay thế addBack()
bằng andSelf()
. andSelf()
không được ủng hộ addBack()
từ 1.8 trở đi.
Điều này hơi kém hiệu quả so với các phương thức DOM thuần túy và phải bao gồm một cách giải quyết xấu cho việc quá tải contents()
chức năng của jQuery (nhờ @rabidsnail trong các nhận xét để chỉ ra điều đó), vì vậy đây là giải pháp không phải jQuery sử dụng hàm đệ quy đơn giản. Các includeWhitespaceNodes
điều khiển tham số hay không nút văn bản trắng có trong đầu ra (trong jQuery họ sẽ được tự động lọc ra).
Cập nhật: Đã sửa lỗi khi includeWhitespaceNodes bị lỗi.
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()
trước, nếu đó là ý bạn:var div = document.getElementById("foo"); var textNodes = getTextNodesIn(div);
.contents()
anyways ngụ ý nó cũng sẽ tìm kiếm thông qua iframe. Tôi không thấy làm thế nào nó có thể là một lỗi.
Jauco đã đăng một giải pháp tốt trong một bình luận, vì vậy tôi đang sao chép nó ở đây:
$(elem)
.contents()
.filter(function() {
return this.nodeType === 3; //Node.TEXT_NODE
});
jQuery.contents()
có thể được sử dụng jQuery.filter
để tìm tất cả các nút văn bản con. Với một chút thay đổi, bạn cũng có thể tìm thấy các nút văn bản cháu. Không yêu cầu đệ quy:
$(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>
Tôi đã nhận được rất nhiều nút văn bản trống với chức năng lọc được chấp nhận. Nếu bạn chỉ quan tâm đến việc chọn các nút văn bản có chứa khoảng trắng, hãy thử thêm một nodeValue
điều kiện vào filter
hàm của bạn , như đơn giản $.trim(this.nodevalue) !== ''
:
$('element')
.contents()
.filter(function(){
return this.nodeType === 3 && $.trim(this.nodeValue) !== '';
});
Hoặc để tránh các tình huống lạ khi nội dung trông giống như khoảng trắng, nhưng không phải (ví dụ: ­
ký tự dấu gạch nối mềm , dòng mới \n
, tab, v.v.), bạn có thể thử sử dụng Biểu thức chính quy. Ví dụ: \S
sẽ khớp với bất kỳ ký tự không phải khoảng trắng nào:
$('element')
.contents()
.filter(function(){
return this.nodeType === 3 && /\S/.test(this.nodeValue);
});
Nếu bạn có thể đưa ra giả định rằng tất cả trẻ em là Nút yếu tố hoặc Nút văn bản, thì đây là một giải pháp.
Để có được tất cả các nút văn bản con dưới dạng một bộ sưu tập jquery:
$('selector').clone().children().remove().end().contents();
Để có được một bản sao của phần tử gốc với các phần tử không phải là văn bản đã bị xóa:
$('selector').clone().children().remove().end();
Vì một số lý do contents()
không hiệu quả với tôi, vì vậy nếu nó không hiệu quả với bạn, đây là giải pháp tôi đã thực hiện, tôi đã tạo jQuery.fn.descendants
với tùy chọn bao gồm các nút văn bản hoặc không
Sử dụng
Nhận tất cả các hậu duệ bao gồm các nút văn bản và các nút phần tử
jQuery('body').descendants('all');
Nhận tất cả con cháu chỉ trả lại các nút văn bản
jQuery('body').descendants(true);
Nhận tất cả con cháu chỉ trả lại các nút phần tử
jQuery('body').descendants();
Coffeescript gốc :
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)
Phiên bản 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)}
Phiên bản Javascript chưa hoàn thành: http://pastebin.com/cX3jMfuD
Đây là trình duyệt chéo, một Array.indexOf
polyfill nhỏ được bao gồm trong mã.
Cũng có thể được thực hiện như thế này:
var textContents = $(document.getElementById("ElementId").childNodes).filter(function(){
return this.nodeType == 3;
});
Đoạn mã trên lọc các textNodes từ các nút con trực tiếp của một phần tử đã cho.
Đối với tôi, đơn giản cũ .contents()
dường như hoạt động để trả về các nút văn bản, chỉ cần cẩn thận với các bộ chọn của bạn để bạn biết chúng sẽ là các nút văn bản.
Ví dụ, phần này bao bọc tất cả nội dung văn bản của các TD trong bảng của tôi bằng pre
các thẻ và không có vấn đề gì.
jQuery("#resultTable td").content().wrap("<pre/>")
Tôi đã có cùng một vấn đề và giải quyết nó với:
Mã số:
$.fn.nextNode = function(){
var contents = $(this).parent().contents();
return contents.get(contents.index(this)+1);
}
Sử dụng:
$('#my_id').nextNode();
Là thích next()
nhưng cũng trả về các nút văn bản.