Simplest Solution
I am trying to answer Hide second line of text with CSS with a JS version
Why does the second line disappear from my loop? Is the textnode stuck to the BR for some reason?
I want to hide the BR and subsequent lines but I do not move the second line to the span
Expected result is when BR is encountered, it and all following nodes are moved to the span and at the end the span is appended to the div where the br used to be, making the second line red in this case
I played with cloneNode which worked better but I wanted to move the nodes, not clone them. I also thought about substring the innerHTML but was worried that the various rendering and toString of BR is not reliable
Input:
<div class="site-info">The quick brown fox <br>Jumps over the lazy dog</div>
Expected output:
<div class="site-info">The quick brown fox <span class="hide"><br>Jumps over the lazy dog</span></div>
Attempt:
var si = document.querySelector(".site-info")
var nodes = si.childNodes;
var span = document.createElement("span");
span.className="hide"
var found = false;
nodes.forEach(n => {
console.log(n.tagName || "No tag",n.wholeText || "No text")
if (n.tagName==="BR") { // first br found
found = true;
}
if (found) { // from now on to end of all nodes
span.appendChild(n) // n.cloneNode(true)
}
});
si.appendChild(span)
.hide { color:red }/* display: none }*/
<div class="site-info">The quick brown fox <br>Jumps over the lazy dog</div>
Simplest Solution
I am trying to answer Hide second line of text with CSS with a JS version
Why does the second line disappear from my loop? Is the textnode stuck to the BR for some reason?
I want to hide the BR and subsequent lines but I do not move the second line to the span
Expected result is when BR is encountered, it and all following nodes are moved to the span and at the end the span is appended to the div where the br used to be, making the second line red in this case
I played with cloneNode which worked better but I wanted to move the nodes, not clone them. I also thought about substring the innerHTML but was worried that the various rendering and toString of BR is not reliable
Input:
<div class="site-info">The quick brown fox <br>Jumps over the lazy dog</div>
Expected output:
<div class="site-info">The quick brown fox <span class="hide"><br>Jumps over the lazy dog</span></div>
Attempt:
var si = document.querySelector(".site-info")
var nodes = si.childNodes;
var span = document.createElement("span");
span.className="hide"
var found = false;
nodes.forEach(n => {
console.log(n.tagName || "No tag",n.wholeText || "No text")
if (n.tagName==="BR") { // first br found
found = true;
}
if (found) { // from now on to end of all nodes
span.appendChild(n) // n.cloneNode(true)
}
});
si.appendChild(span)
.hide { color:red }/* display: none }*/
<div class="site-info">The quick brown fox <br>Jumps over the lazy dog</div>
Expected result NOTE: color:red will be display:none in real version, resulting in the second line appearing WITH the BR if display:none is removed by code
.hide { color:red }
<div class="site-info">The quick brown fox <span class="hide"><br>Jumps over the lazy dog</span></div>
Share
Improve this question
edited Aug 16, 2019 at 9:39
mplungjan
asked Aug 16, 2019 at 8:25
mplungjanmplungjan
179k28 gold badges182 silver badges240 bronze badges
1
- What's with the downvote? – mplungjan Commented Jul 23, 2023 at 8:49
5 Answers
Reset to default 3When you do a console.log(nodes)
before the the loop you will notice that the span is already included as a childNode.
That seems to mess with the logic of span.appendChild
while looping through the nodes.
Edit: As per the ments, when calling appendChild
for the br
tag, the elements gets removed from the DOM which alteres the reference inside the nodes
array and causes the two text nodes to bine as they are not seperated anymore. So the loop will not reach the former 3rd iteration anymore as that array element does not exist anymore.
If you pull the logic for appending the nodes outside the loop it works:
var si = document.querySelector(".site-info")
var nodes = si.childNodes;
var span = document.createElement("span");
span.className = "hide"
var found = false;
let childs = [];
nodes.forEach((n, i) => {
if (n.tagName === "BR") {
found = true;
}
if (found) {
childs.push(n);
}
});
if (childs.length > 0) {
childs.forEach((n) => {
span.appendChild(n);
});
si.appendChild(span);
}
.hide {
color: red
}
<div class="site-info">The quick brown fox <br>Jumps over the lazy dog</div>
That being said I actually haven't found a reason for that happening so there might be a more elegant solution to that.
We already have an accepted answer working around the problem. But we found out that the real issue is the removal of the br
element during the iteration messes with the original childNodes array.
Originally it is
<div>
A quick brown fox
<br>
Jumps over the lazy dog
</div>
which is divided into 3
nodes.
During the original code, which removes the br
element and inserts it to a new span. What happens is that the two separate childNodes bine into one.
<div>
A quick brown fox
<!-- <br> is removed -->
Jumps over the lazy dog
</div>
Such that a 3rd iteration never happens, since the length of the nodes goes from 3
to 2
The resulting HTML bees
<div>
A quick brown fox
Jumps over the lazy dog
<span><br/></span>
</div>
Since we cannot move from the beginning, we can in this case move from the end
var si = document.querySelector(".site-info")
var nodes = si.childNodes;
var span = document.createElement("span");
span.className="hide"
for (var i=nodes.length-1; i>=0; i--) {
var n = nodes[i];
console.log(n.tagName || n.wholeText)
span.insertBefore(n,span.firstChild)
if (n.tagName=="BR") break;
};
si.appendChild(span)
.hide { color:red }/* display: none }*/
<div class="site-info">The quick brown fox <br>Jumps over the lazy dog</div>
Each time appendChild
is being called, the element is moved to the span
, that changes the nodes
's size. Instead we could make a deep clone of all nodes ans maintain a variable c
to keep in check how many nodes to skip as nodesCopy
will vary with loop and nodes
won't:
var si = document.querySelector(".site-info")
var nodes = [];
var nodesCopy = si.childNodes;
si.childNodes.forEach(element => nodes.push(element.cloneNode(true)));
var c = 0;
var span = document.createElement("span");
span.className = "hide"
var found = false;
console.log(nodes.length);
nodes.forEach((n, i) => {
console.log(n.tagName || "No tag", n.wholeText || "No text");
if (n.tagName === "BR") {
found = true;
}
if (found) {
c++;
si.removeChild(nodesCopy[i - c + 1]);
span.appendChild(n);
}
});
console.log(nodes.length);
si.appendChild(span);
.hide {
color: red
}
/* display: none }*/
<div class="site-info">The quick brown fox <br>Jumps over the lazy dog</div>
Well, your code seems to be doing exactly what you tell it to do. In this case: Loop over all the childnodes, if a <br>
is found append it to the newly created <span>
and add the <span>
to the .site-info
div.
And so your output bees this:
<div class="site-info">The quick brown fox Jumps over the lazy dog<span class="hide"><br></span></div>
Edit: You could take a different approach by checking the string for occurrences of the <br>
tag, cut the string and paste the selection into a literal string like so:
var si = document.querySelector(".site-info");
var html = si.innerHTML;
var index = html.indexOf('<br>');
var selection = html.slice(index, html.length);
si.innerHTML = html.substring(0, index) + '<span class="hide">' + selection + '</span>';
// Log the output
console.log(si.innerHTML);
.hide { color:red }/* display: none }*/
<div class="site-info">The quick brown fox <br>Jumps over the lazy dog</div>
This does need some validation though, but does do what you are looking for.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745312964a4622084.html
评论列表(0条)