User:Zuhui/SI26/Storybook/Code to work 2: Difference between revisions
No edit summary |
|||
(One intermediate revision by the same user not shown) | |||
Line 18: | Line 18: | ||
</p> | </p> | ||
<div id=" | <div id="space"> | ||
<div class="do"></div> | <div class="do"></div> | ||
<div class="tigers | <div class="tigers"></div> | ||
<div class="melt | <div class="melt"></div> | ||
<div class="like"></div> | <div class="like"></div> | ||
<div class="butter | <div class="butter"></div> | ||
<div class="in"></div> | <div class="in"></div> | ||
<div class="the"></div> | <div class="the"></div> | ||
<div class="forest | <div class="forest"></div> | ||
<div class="questionmark"></div> | <div class="questionmark"></div> | ||
</div> | </div> | ||
Line 337: | Line 337: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br> | <br> | ||
<br> | <br> | ||
Latest revision as of 09:25, 15 March 2025
Html structure
<body>
<p id="sentence">
<span class="word_do">do</span>
<span class="word_tigers">tigers</span>
<span class="word_melt">melt</span>
<span class="word_like">like</span>
<span class="word_butter">butter</span>
<span class="word_in">in</span>
<span class="word_the">the</span>
<span class="word_forest">forest</span>
<span class="word_questionmark">?</span>
</p>
<div id="space">
<div class="do"></div>
<div class="tigers"></div>
<div class="melt"></div>
<div class="like"></div>
<div class="butter"></div>
<div class="in"></div>
<div class="the"></div>
<div class="forest"></div>
<div class="questionmark"></div>
</div>
<script src="java1.js"></script>
</body>
now all the divs are also siblings, so they will listen to same command that controls the spans(words)
Javascript
basic variables
let sentence = document.getElementById("sentence")//this is added from the first version, in the first version, I didn’t define "sentence", so there was no way to know where to put the words back from removedWords in "bringBack"function.
let words = Array.from(document.querySelectorAll("#sentence span"));
let removedWords = [];
randomly removing, bringing words back function
function removeRandomWord () {
if (words.length > 1) {
let pickRandom = Math.floor(Math.random() * words.length);
let remove = words.splice(pickRandom,1)[0]; //had to add "[0]" to pull the first word out from the array
removedWords.push(remove);
remove.remove(); //.remove() method removes the element from the DOM.
}
}
function bringbackRandomWord () {
if (removedWords.length > 0) {
let pickRandom = Math.floor(Math.random() * removedWords.length);
let bringBack = removedWords.splice(pickRandom,1)[0];
words.push(bringBack);
sentence.innerHTML = sentence.innerHTML + " "; //try to add space between the spans but this doesn't work at the moment.
sentence.appendChild(bringBack); //opposite of remove() is appendChild()
}
}
- ↳ how do I add a space (" ") after each word that is brought back?
sentence.innerHTML += " ";
- ↳ this works only the first time shrinking the browser, but when i try again, it stops working. then at some point, it starts adding more words. as if the words are duplicating itself
- I think
appendChild()
should be a way to go. Just like how I brought the spans back with that method. But using it with properties like innerHTML, innerText, textContent, doesn’t work.
- ↳ throwing spaghetties on the wall approach using those 3 properties around the line did work at some point in terms of adding spaces in between my spans, but the browser rendered all my spans as [object HTMLSpanElement]. technically doesn’t work, but it’s something.
- ↳ so [object HTMLSpanElement] means it broke the structure of my spans and turned them into raw text within sentence.innerHTML
- ↳ this means the original span elements are no longer treated as elements, but instead they got converted into plain text.
- ↳ my spans are DOM node/elements, they should not be rendered as raw text. I need to use DOM methods again for appendchild() instead of DOM properties to control the elements directly with js.
DOM
JavaScript Creating New HTML Elements (Nodes) there's a fantastic example here!!
createTextNode() w3c
insertBefore() w3c
insertBefore() example w3c
sentence.appendChild(document.createTextNode(" "));
it works.
two innerWidth variables and "resize" eventlistener
let prevWidth = window.innerWidth;
first define prevWidth as innerWidth outside of the eventlistener
window.addEventListener("resize", () => {
let currWidth = window.innerWidth;
let widthChange = Math.abs(prevWidth - currWidth);
console.log(widthChange)
if (currWidth < prevWidth && widthChange > 100) {
removeRandomWord();
prevWidth = currWidth;
}
else if (prevWidth < currWidth && widthChange > 100) {
bringbackRandomWord();
prevWidth = currWidth;
}
//instead of updating prevWidth at the very end of the function, update it inside each if statement
//previous version was updating currWidth to prevWidth, i thought i was saving the currWidth to prevWidth but it works other way around.
});
break
synchronizing spans and divs
added basic variables for the divs
let sentence = document.getElementById("sentence");
let space = document.getElementById("space");
let words = Array.from(document.querySelectorAll("#sentence span"));
let figures = Array.from(document.querySelectorAll("#space div"));
let removedWords = [];
let removedDivs = [];
adding the matching div under function removeRandom()
with Joseph's help,
function removeRandom () {
if (words.length > 1) {
let pickRandom = Math.floor(Math.random() * words.length);
let removingWords = words.splice(pickRandom,1)[0];
removedWords.push(removingWords);
removingWords.remove();
var findSameName = removingWords.classList[0].replace("word_","");
let matchingDiv = document.querySelector("#space div." + findSameName);
removedDivs.push(matchingDiv);
matchingDiv.remove();
}
}
code explained:
just like how Array.from()
converts a NodeList to an array, which allowing the use of array methods,classList
provides DOMToeknList, which allows the use of tokenlist methods.
var findSameName = removingWords.classList[0].replace("word_","");
- ↳
element.classList[0]
takes the first class name out from the DOMTokenList, and then use theclassList.replace()
method to modify the name.
let matchingDiv = document.querySelector("#space div." + findSameName);
- ↳
document.querySelector
to find a single, specific element in the DOM- ↳ using CSS selector
+
inside the parentheses
- ↳ using CSS selector
adding the matching div under function bringBackRandom()
function bringBackRandom () {
if (removedWords.length > 0) {
let pickRandom = Math.floor(Math.random() * removedWords.length);
let bringBackWord = removedWords.splice(pickRandom, 1)[0];
words.push(bringBackWord);
sentence.appendChild(bringBackWord);
sentence.appendChild(document.createTextNode(" "));
var findSameName = bringBackWord.classList[0].replace("word_","");
let matchingDiv = removedDivs.find(div => div.classList.contains(findSameName));
figures.push(matchingDiv);
space.appendChild(matchingDiv);
}
}
find() mdn
findIndex() mdn
iterative methods (using callbacks) mdn
classList.contains() mdn
Callback function
code explained:
let matchingDivv = removedDivs.find(div => div.classList.contains(findSameName));
find()
is one of the iterative methods
- ↳ "Iterative methods always use a callback function to loop through each item in an array and process it."
- ↳ but find() doesn't always use callback function
findIndex()
also works, but you need an extra line to remove/retrieve the element from the array usingsplice()[0]
how callback works here:
- in
removedDivs
array, find thedivs
that containsfindSameName
token - if the syntax returns
false
, it moves on to the nextdiv
- if the syntax returns
true
, it returns thatdiv
and stops.
instead of "=>"
seems like the arrow function is mostly used for convenience because it omits function
and return
when there's only one return, but it's still confusing to write it myself
let matchingDiv = removedDivs.find(function(div) {return div.classList.contains(findSameName)});
Working code
let sentence = document.getElementById("sentence");
let space = document.getElementById("space");
let words = Array.from(document.querySelectorAll("#sentence span"));
let figures = Array.from(document.querySelectorAll("#space div"));
let removedWords = [];
let removedDivs = [];
function removeRandom () {
if (words.length > 1) {
let pickRandom = Math.floor(Math.random() * words.length);
let removingWords = words.splice(pickRandom,1)[0];//had to add "[0]" to pull the word out from the array
//console.log(removingWords);
removedWords.push(removingWords);
removingWords.remove(); //.remove() method removes the element from the DOM.
//now find the same named divs
var findSameName = removingWords.classList[0].replace("word_","");
//console.log(findSameName);
let matchingDiv = document.querySelector("#space div." + findSameName);//only need one matching div
//console.log(matchingDiv);
removedDivs.push(matchingDiv);
matchingDiv.remove();
//console.log(removedDivs);
}
}
function bringBackRandom () {
if (removedWords.length > 0) {
let pickRandom = Math.floor(Math.random() * removedWords.length);
let bringBackWord = removedWords.splice(pickRandom, 1)[0];
words.push(bringBackWord);
sentence.appendChild(bringBackWord);
sentence.appendChild(document.createTextNode(" ")); //this works, needed a method that directly manipulates the dom tree
//now bring back the matching divs
var findSameName = bringBackWord.classList[0].replace("word_","");
let matchingDiv = removedDivs.find(div => div.classList.contains(findSameName));
//console.log(matchingDiv);
figures.push(matchingDiv);
space.appendChild(matchingDiv);
//console.log(removedDivs);
}
}
//save the innerWidths into two variables
let prevWidth = window.innerWidth;
//when the innerWidth is reduced by more than 100px, remove one random word
window.addEventListener("resize", () => {
let currWidth = window.innerWidth;
let widthChange = Math.abs(prevWidth - currWidth);
//console.log(widthChange)
if (currWidth < prevWidth && widthChange > 100) {
removeRandom();
prevWidth = currWidth;
}
else if (prevWidth < currWidth && widthChange > 100) {
bringBackRandom();
prevWidth = currWidth;
}
//instead of updating prevWidth at the very end of the function once, update it inside each if statement
});