简体   繁体   中英

How can I update the style attribute of a virtual html element with the value of a JavaScript variable?

I am working on this JavaScript image (and text) slider.

I create a list of slides in JavaScript and append it to a div in the DOM:

let slidesHtml = '<ul style="width: ' + slidesListWidth + '; transform: translateX(' + translateAmount + ')">';
 for (let i = 0; i < slidesLen; i++) {
   slidesHtml += '<li style="width: ' + slideWidth + '">' + '<img src="' + slides[i].image + '" alt="' + slides[i].text + '"><span class="text">' + slides[i].text + '</span></li>';
 }
 slidesHtml += '</ul>'
 sliderControls.insertAdjacentHTML('afterend', slidesHtml);

In the code above , translateAmount does not update when the JavaScript variable let translateAmount = 0 changes its value (from 0 to different percentages).

 let slides = [{ text: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iusto fugiat enim voluptate eos placeat quis veniam quod inventore ipsum sapiente vel, earum, ratione neque.", image: "https://picsum.photos/1200/600?gravity=east" }, { text: "Sit quis provident reiciendis sed optio molestias impedit maiores nesciunt!", image: "https://picsum.photos/1200/600?gravity=west" }, { text: "Odio mollitia inventore nostrum quasi labore architecto quis id repudiandae quidem!", image: "https://picsum.photos/1200/600?gravity=north" } ]; let slider = document.getElementById('imageSlider'); let sliderControls = document.getElementById('sliderControls'); let slidesLen = slides.length; let slidesListWidth = slidesLen + '00%'; let slideWidth = (1 / slidesLen * 100) + '%'; let clickCount = 0; let translateAmount = 0; function updateAmount() { translateAmount = clickCount * 1 / slidesLen * 100 + '%'; console.log(translateAmount); } function nextSlide() { if (Math.abs(clickCount) < slidesLen - 1) { clickCount--; } else { clickCount = 0; } updateAmount(); } function prevSlide() { if (clickCount < 0) { clickCount++; } else { clickCount = 1 - slidesLen; } updateAmount(); } let slidesHtml = '<ul style="width: ' + slidesListWidth + '; transform: translateX(' + translateAmount + ')">'; for (let i = 0; i < slidesLen; i++) { slidesHtml += '<li style="width: ' + slideWidth + '">' + '<img src="' + slides[i].image + '" alt="' + slides[i].text + '"><span class="text">' + slides[i].text + '</span></li>'; } slidesHtml += '</ul>' sliderControls.insertAdjacentHTML('afterend', slidesHtml);
 body { margin: 0; padding: 0; } #imageSlider { margin: 0 auto; max-width: 1200px; position: relative; overflow-x: hidden; } #imageSlider ul { list-style-type: none; margin: 0; padding: 0; transition: all 1.0s ease-in-out; } #imageSlider li { display: block; float: left; position: relative; } #imageSlider img { display: block; width: 100%; height: auto; } #imageSlider .text { font-family: Arial, Helvetica, sans-serif; font-size: 13px; text-align: justify; line-height: 1.5; position: absolute; bottom: 0; left: 0; right: 0; padding: 15px; color: #fff; background: rgba(0, 0, 0, 0.15); } .controls span { width: 30px; height: 60px; text-align: center; cursor: pointer; color: #fff; opacity: 0.75; font-size: 48px; position: absolute; top: 50%; margin-top: -30px; z-index: 2; } .controls span:last-child { right: 0; }
 <div id="imageSlider"> <div class="controls" id="sliderControls"> <span onClick="prevSlide()">&lsaquo;</span> <span onClick="nextSlide()">&rsaquo;</span> </div> </div>

How can I fix this bug?

you modify value but not the style of element (it's not data-binded as it is in for example react), so you must take your UL to variable, and then in updateAmount you should do something like

function updateAmount() {
    translateAmount = clickCount * 1 / slidesLen * 100 + '%';
    yourUlElement.style.transform = 'translateX(' + translateAmount + ')';
}

You aren't writing anything to the DOM, you are just setting a JavaScript variable.

In your updateAmount() function you would need to get a reference to the ul element in the DOM and set the style attribute with the updated value.

That said, this is not a very nice implementation. instead of using global variables, perhaps have a go at creating an encapsulated component for this with a local state that you update on click of the next and previous buttons. Also you would improve readability a lot by using template strings instead of all those concatenations.

Many thanks @Kamil Rogala who help fix a bug that eluded my vigilance.

There is the full working slider, for whoever may need it:

 (function() { let slides = [{ text: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iusto fugiat enim voluptate eos placeat quis veniam quod inventore ipsum sapiente vel, earum, ratione neque.", image: "https://picsum.photos/1200/600?gravity=east" }, { text: "Aperiam eligendi animi, suscipit repellendus tempore amet totam excepturi, porro facere nulla dignissimos pariatur doloribus dolorum sunt, et veritatis expedita consectetur.", image: "https://picsum.photos/1200/600?gravity=west" }, { text: "Odio mollitia inventore nostrum quasi labore architecto quis id repudiandae quidem!", image: "https://picsum.photos/1200/600?gravity=north" }, { text: "Iusto fugiat enim voluptate eos placeat quis veniam quod inventore ipsum sapiente vel, earum, ratione neque. Inventore nostrum quasi labore architecto quis id repudiandae quidem!", image: "https://picsum.photos/1200/600?gravity=south" } ]; let slider = document.getElementById('imageSlider'); let sliderControls = document.getElementById('sliderControls'); let slidesLen = slides.length; let slidesListWidth = slidesLen + '00%'; let slideWidth = (1 / slidesLen * 100) + '%'; let clickCount = 0; let translateAmount = 0; function updateAmount() { translateAmount = clickCount * 1 / slidesLen * 100 + '%'; document.getElementById('slidesList').style.transform = 'translateX(' + translateAmount + ')'; } window.nextSlide = function() { if (Math.abs(clickCount) < slidesLen - 1) { clickCount--; } else { clickCount = 0; } updateAmount(); } window.prevSlide = function() { if (clickCount < 0) { clickCount++; } else { clickCount = 1 - slidesLen; } updateAmount(); } let slidesHtml = '<ul id="slidesList" style="width: ' + slidesListWidth + '; transform: translateX(' + translateAmount + ')">'; for (let i = 0; i < slidesLen; i++) { slidesHtml += '<li style="width: ' + slideWidth + '">' + '<img src="' + slides[i].image + '" alt="' + slides[i].text + '"><span class="text">' + slides[i].text + '</span></li>'; } slidesHtml += '</ul>'; sliderControls.insertAdjacentHTML('afterend', slidesHtml); })();
 body { margin: 0; padding: 0; } #imageSlider { margin: 0 auto; max-width: 1200px; position: relative; overflow-x: hidden; } #imageSlider ul { list-style-type: none; margin: 0; padding: 0; transition: all 1.0s ease-in-out; } #imageSlider li { display: block; float: left; position: relative; } #imageSlider img { display: block; width: 100%; height: auto; } #imageSlider .text { font-family: Arial, Helvetica, sans-serif; font-size: 13px; text-align: justify; line-height: 1.5; position: absolute; bottom: 0; left: 0; right: 0; padding: 15px; color: #fff; background: rgba(0, 0, 0, 0.15); } .controls span { line-height: 1; display: inline-block; text-align: center; width: 30px; height: 32px; line-height: 21px; cursor: pointer; color: #fff; font-size: 54px; position: absolute; top: 50%; margin-top: -18px; z-index: 2; opacity: 0; transition: opacity 0.25s ease-in-out; } .controls span:last-child { right: 0; } #imageSlider:hover .controls span { opacity: .75; }
 <div id="imageSlider"> <div class="controls" id="sliderControls"> <span onClick="prevSlide()">&lsaquo;</span> <span onClick="nextSlide()">&rsaquo;</span> </div> </div>

Note: for an instant transition, replace transition: all 1.0s ease-in-out with transition: all 0s .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM