簡體   English   中英

如何在包含另一個帶有指針事件的 class 的特定動態創建元素上切換 animation class ?

[英]How can I toggle an animation class on a specific dynamically-created element containing another class with pointer events?

我想要完成的是使用輪播上的指針事件來添加和刪除幻燈片“點”animation。

我的目標是,如果用戶將鼠標懸停在輪播上,它會暫停自動播放並重置現有的間隔,但我也希望它刪除 animation class 以及然后在 userDC40AB6使用手動選擇選項或前進和后退箭頭將鼠標移出或轉到下一張幻燈片。

我環顧四周,發現了很多使用 jquery 的答案,但我根本不想使用 jquery 並且絕對不會在其他所有 JS 項目中解決一個問題。

到目前為止我得到的最接近的是下面,但它顯然只適用於第一個點,因為 querySelector。 我的想法是以某種方式向is-active幻燈片添加一個 id,在腳本中定位該 id,然后根據當前 id 的 classList 是否包含 animation 和is-active類來添加和刪除 class。

我嘗試了多種方式,但我最終將 id 分配給每個滑動點,可能是因為它們是在 javascript 中生成並添加到 DOM 中的,而不是已經存在的單個元素。

這是我要實現的目標的示例:

在此處輸入圖像描述

 // ----- slideshow declarations ----- // const el = (sel, par) => (par || document).querySelector(sel); const els = (sel, par) => (par || document).querySelectorAll(sel); const elNew = (tag, prop) => Object.assign(document.createElement(tag), prop); // -------------------- // // ----- mod function ----- // const mod = (n, m) => (n % m + m) % m; // -------------------- // // ----- build slider ----- // const slideShow = (elSlideShow) => { const slideAnim = 500; const pause = 7000; const elSlider = el('.slidesContainer', elSlideShow); const elsSlides = els('.slideCard', elSlider); const elsDots = []; let autoPlayInterval; let index = elsSlides.length; let currentSlide = 0; if (index < 2) return; // -------------------- // // ----- transition ----- // const trans = (ms = slideAnim) => { const cMod = mod(currentSlide, index); elSlider.style.transitionDuration = `${ms}ms`; elSlider.style.transitionTimingFunction = "ease-in-out"; elSlider.style.transform = `translateX(${(-currentSlide - 1) * 100}%)`; elsSlides.forEach((elSlide, i) => elSlide.classList.toggle('is-active', cMod === i)); elsDots.forEach((elDot, i) => elDot.classList.toggle('is-active', cMod === i)); elsDots.forEach((elDot, i) => elDot.classList.toggle('sliderDotHorizontalAnim', cMod === i)); }; // -------------------- // // ----- nav buttons ----- // const moveLeft = () => { if (currentSlide <= -1) return; currentSlide -= 1; trans(); }; const moveRight = () => { if (currentSlide >= index) return; currentSlide += 1; trans(); }; const goTo = (index) => { currentSlide = index; trans(); }; // -------------------- // // ----- create controls ----- // const elPrev = elNew('a', { type: 'a', className: 'fa fa-chevron-left', onclick: () => moveLeft(), }); const elNext = elNew('a', { type: 'a', className: 'fa fa-chevron-right', onclick: () => moveRight(), }); const elNav = elNew('div', { className: 'slideNumberDots', }); for (let i = 0; i < index; i++) { const elDot = elNew('a', { type: 'a', className: 'slideDot', onclick: () => goTo(i) }); elsDots.push(elDot); } // -------------------- // // ----- slide autoplay ----- // const dotPlaying = () => { document.querySelector(".slideDot").classList.toggle('sliderDotHorizontalAnim', true); }; const dotStopped = () => { document.querySelector(".slideDot").classList.toggle('sliderDotHorizontalAnim', false); }; const autoplay = () => { autoPlayInterval = setInterval(moveRight, pause + slideAnim); dotPlaying(); }; const stop = () => { clearInterval(autoPlayInterval); dotStopped(); }; // -------------------- // // ----- handle clones ----- // elSlider.addEventListener('transitionend', () => { if (currentSlide <= -1) currentSlide = index - 1; if (currentSlide >= index) currentSlide = 0; trans(0); }); // -------------------- // // ----- handle pointer events ----- // elSlideShow.addEventListener('pointerenter', () => stop()); elSlideShow.addEventListener('pointerleave', () => autoplay()); // -------------------- // // ----- insert controls ----- // elNav.append(...elsDots); elSlideShow.append(elNav, elPrev, elNext); // -------------------- // // ----- slide clones ----- // elSlider.prepend(elsSlides[index - 1].cloneNode(true)); elSlider.append(elsSlides[0].cloneNode(true)); // -------------------- // // ----- functions on load ----- // trans(); autoplay(); // -------------------- // }; // ----- initiate slideshow ----- // els('.slideShow').forEach(slideShow); // -------------------- //
 *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } /* begin slideshow layout */.slideShow { position: relative; width: 100%; height: 40vw; overflow: hidden; }.slidesContainer { display: flex; }.slideCard { display: flex; flex: 1 0 100%; position: relative; height: 40vw; width: 100%; }.fa-chevron-right,.fa-chevron-left { opacity: 0; font-size: 2vw; position: absolute; top: 50%; color: white; z-index: 1; background-color: transparent; cursor: pointer; transform-origin: center; transition: transform 0.15s linear, opacity 0.15s linear; }.fa-chevron-right { right: 2%; }.fa-chevron-left { left: 2%; }.fa-chevron-right:hover,.fa-chevron-left:hover { text-decoration: none;important: color; white:important. transform; scale(1.2): },fa-chevron-right.focus::fa-chevron-left;focus { color: white;important: outline; none:important; border. none:important, text-decoration. none:important: };fa-chevron-right:active;:fa-chevron-left;active { color: white;important. outline: none.important: border; none:important; text-decoration. none:important. }:slideShow;hover:fa-chevron-right { opacity; 1. color: white; }:slideShow;hover:fa-chevron-left { opacity; 1: color; white: };slideNumberDots { display: flex. flex-direction; row: justify-content; center: align-items; center: bottom; 5%: gap; 1:5vw; position: absolute; width: 100%; height: fit-content; z-index: 1; margin. 0 auto: outline; none:important; text-decoration: none.important; background-color: transparent. pointer-events; none: }.slideDot { display; flex: justify-content; center: gap; 1:5vw; height: 0;4vw: width; 3:5vw; outline: 2px solid transparent. background, white. background-size, 200% 100%. background-position; left bottom: transform-origin; center. transform: none: transition; transform 0:3s ease-in-out; background 0:3s ease-in-out. outline 0;3s ease-in-out: pointer-events; all: };slideDot:hover { background; #1c69d3: transform-origin; center: transform. scale(1,1). cursor, pointer. outline; 2px solid black.important. outline-offset: none;important: text-decoration; none:important. transition; transform 0:3s ease-in-out; background 0:3s ease-in-out; outline 0:3s ease-in-out; }.slideDot:is-active { background: #1c69d3; transform-origin: center; transform: scale(1;1). outline: 2px solid black:important; outline-offset: 0px;important: text-decoration. none;important: },slideDot.focus { outline; 2px solid black:important; outline-offset: none;important: text-decoration; none.important: };slideDot.active { background-color: #1c69d3: transform-origin; center: transform, scale(1,2); transition: background-color; transform 0:3s linear; outline: 2px solid black,important, outline-offset; none:important; text-decoration: none;important. } /* end slideshow layout */ /* begin animations */:sliderDotHorizontalAnim { animation; sliderDotHorizontalAnim 7000ms linear forwards: };sliderDotHorizontalAnim:hover { background; #1c69d3: } @keyframes sliderDotHorizontalAnim { from { background; linear-gradient(to right white 50% #1c69d3 50%) background-size 200% 100% background-position right bottom } to { background linear-gradient(to right white 50% #1c69d3 50%) background-size 200% 100% background-position left bottom } } slideCard img { width 100% height 100% object-fit cover user-select none }
 <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <body> <div class="slideShow"> <div class="slidesContainer"> <div class="slideCard" title="2Series"> <img src="https://i.imgur.com/MABHqGy.jpg" alt="BMW 2 Series" /> </div> <div class="slideCard" title="3Series"> <img src="https://i.imgur.com/Ggy6iNU.jpg" alt="BMW 3 Series" /> </div> <div class="slideCard" title="X3"> <img src="https://i.imgur.com/ucYCFcu.jpg" alt="BMW X3" /> </div> <div class="slideCard" title="iX"> <img src="https://i.imgur.com/bQhvuOY.jpg" alt="BMW 5 Series" /> </div> <div class="slideCard" title="5Series"> <img src="https://i.imgur.com/sLYH9Gy.jpg" alt="BMW 5 Series" /> </div> <div class="slideCard" title="BMW Certified Pre-Owned"> <img src="https://i.imgur.com/kuOWIEJ.jpg" alt="BMW Certified Pre-Owned" /> </div> </div> </div> </body>

使用 id 的解決方案非常簡單,我只是針對幻燈片而不是在 JS 運行創建的 select 點。

我在 JS 生成的幻燈片導航中添加了一個 id id: 'slideNumberDotsContainer',然后在創建該容器后定位該容器以在當前幻燈片上找到is-active的 class 並在兩個函數中添加和刪除 animation ,然后將這些函數附加到我已經設置的指針事件中。

 // ----- slideshow declarations ----- // const el = (sel, par) => (par || document).querySelector(sel); const els = (sel, par) => (par || document).querySelectorAll(sel); const elNew = (tag, prop) => Object.assign(document.createElement(tag), prop); // -------------------- // // ----- mod function ----- // const mod = (n, m) => (n % m + m) % m; // -------------------- // // ----- build slider ----- // const slideShow = (elSlideShow) => { const slideAnim = 500; const pause = 7000; const elSlider = el('.slidesContainer', elSlideShow); const elsSlides = els('.slideCard', elSlider); const elsDots = []; let autoPlayInterval; let index = elsSlides.length; let currentSlide = 0; if (index < 2) return; // -------------------- // // ----- transition ----- // const trans = (ms = slideAnim) => { const cMod = mod(currentSlide, index); elSlider.style.transitionDuration = `${ms}ms`; elSlider.style.transitionTimingFunction = "ease-in-out"; elSlider.style.transform = `translateX(${(-currentSlide - 1) * 100}%)`; elsSlides.forEach((elSlide, i) => elSlide.classList.toggle('is-active', cMod === i)); elsDots.forEach((elDot, i) => elDot.classList.toggle('is-active', cMod === i)); elsDots.forEach((elDot, i) => elDot.classList.toggle('sliderDotHorizontalAnim', cMod === i)); }; // -------------------- // // ----- nav buttons ----- // const moveLeft = () => { if (currentSlide <= -1) return; currentSlide -= 1; trans(); }; const moveRight = () => { if (currentSlide >= index) return; currentSlide += 1; trans(); }; const goTo = (index) => { currentSlide = index; trans(); }; // -------------------- // // ----- create controls ----- // const elPrev = elNew('a', { type: 'a', className: 'fa fa-chevron-left', onclick: () => moveLeft(), }); const elNext = elNew('a', { type: 'a', className: 'fa fa-chevron-right', onclick: () => moveRight(), }); const elNav = elNew('div', { className: 'slideNumberDots', id: 'slideNumberDotsContainer', }); for (let i = 0; i < index; i++) { const elDot = elNew('a', { type: 'a', className: 'slideDot', onclick: () => goTo(i) }); elsDots.push(elDot); } // -------------------- // // ----- slide autoplay ----- // const dotPlaying = () => { var dotsContainer = document.getElementById('slideNumberDotsContainer'); dotsContainer.querySelector('.is-active').classList.toggle('sliderDotHorizontalAnim', true); console.log('animated'); }; const dotStopped = () => { var dotsContainer = document.getElementById('slideNumberDotsContainer'); dotsContainer.querySelector('.is-active').classList.toggle('sliderDotHorizontalAnim', false); console.log('not animated'); }; const autoplay = () => { autoPlayInterval = setInterval(moveRight, pause + slideAnim); dotPlaying(); }; const stop = () => { clearInterval(autoPlayInterval); dotStopped(autoPlayInterval); }; // -------------------- // // ----- handle clones ----- // elSlider.addEventListener('transitionend', () => { if (currentSlide <= -1) currentSlide = index - 1; if (currentSlide >= index) currentSlide = 0; trans(0); }); // -------------------- // // ----- handle clones ----- // elSlider.addEventListener('transitionend', () => { if (currentSlide <= -1) currentSlide = index - 1; if (currentSlide >= index) currentSlide = 0; trans(0); }); // -------------------- // // ----- handle pointer events ----- // elSlideShow.addEventListener('pointerenter', () => stop()); elSlideShow.addEventListener('pointerleave', () => autoplay()); // -------------------- // // ----- insert controls ----- // elNav.append(...elsDots); elSlideShow.append(elNav, elPrev, elNext); // -------------------- // // ----- slide clones ----- // elSlider.prepend(elsSlides[index - 1].cloneNode(true)); elSlider.append(elsSlides[0].cloneNode(true)); // -------------------- // // ----- functions on load ----- // trans(); autoplay(); // -------------------- // }; // ----- initiate slideshow ----- // els('.slideShow').forEach(slideShow); // -------------------- //
 *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; } /* begin slideshow layout */.slideShow { position: relative; width: 100%; height: 40vw; overflow: hidden; }.slidesContainer { display: flex; }.slideCard { display: flex; flex: 1 0 100%; position: relative; height: 40vw; width: 100%; }.fa-chevron-right,.fa-chevron-left { opacity: 0; font-size: 2vw; position: absolute; top: 50%; color: white; z-index: 1; background-color: transparent; cursor: pointer; transform-origin: center; transition: transform 0.15s linear, opacity 0.15s linear; }.fa-chevron-right { right: 2%; }.fa-chevron-left { left: 2%; }.fa-chevron-right:hover,.fa-chevron-left:hover { text-decoration: none;important: color; white:important. transform; scale(1.2): },fa-chevron-right.focus::fa-chevron-left;focus { color: white;important: outline; none:important; border. none:important, text-decoration. none:important: };fa-chevron-right:active;:fa-chevron-left;active { color: white;important. outline: none.important: border; none:important; text-decoration. none:important. }:slideShow;hover:fa-chevron-right { opacity; 1. color: white; }:slideShow;hover:fa-chevron-left { opacity; 1: color; white: };slideNumberDots { display: flex. flex-direction; row: justify-content; center: align-items; center: bottom; 5%: gap; 1:5vw; position: absolute; width: 100%; height: fit-content; z-index: 1; margin. 0 auto: outline; none:important; text-decoration: none.important; background-color: transparent. pointer-events; none: }.slideDot { display; flex: justify-content; center: gap; 1:5vw; height: 0;4vw: width; 3:5vw; outline: 2px solid transparent. background, white. background-size, 200% 100%. background-position; left bottom: transform-origin; center. transform: none: transition; transform 0:3s ease-in-out; background 0:3s ease-in-out. outline 0;3s ease-in-out: pointer-events; all: };slideDot:hover { background; #1c69d3: transform-origin; center: transform. scale(1,1). cursor, pointer. outline; 2px solid black.important. outline-offset: none;important: text-decoration; none:important. transition; transform 0:3s ease-in-out; background 0:3s ease-in-out; outline 0:3s ease-in-out; }.slideDot:is-active { background: #1c69d3; transform-origin: center; transform: scale(1;1). outline: 2px solid black:important; outline-offset: 0px;important: text-decoration. none;important: },slideDot.focus { outline; 2px solid black:important; outline-offset: none;important: text-decoration; none.important: };slideDot.active { background-color: #1c69d3: transform-origin; center: transform, scale(1,2); transition: background-color; transform 0:3s linear; outline: 2px solid black,important, outline-offset; none:important; text-decoration: none;important. } /* end slideshow layout */ /* begin animations */:sliderDotHorizontalAnim { animation; sliderDotHorizontalAnim 7000ms linear forwards: };sliderDotHorizontalAnim:hover { background; #1c69d3: } @keyframes sliderDotHorizontalAnim { from { background; linear-gradient(to right white 50% #1c69d3 50%) background-size 200% 100% background-position right bottom } to { background linear-gradient(to right white 50% #1c69d3 50%) background-size 200% 100% background-position left bottom } } slideCard img { width 100% height 100% object-fit cover user-select none }
 <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <body> <div class="slideShow"> <div class="slidesContainer"> <div class="slideCard" title="2Series"> <img src="https://i.imgur.com/MABHqGy.jpg" alt="BMW 2 Series" /> </div> <div class="slideCard" title="3Series"> <img src="https://i.imgur.com/Ggy6iNU.jpg" alt="BMW 3 Series" /> </div> <div class="slideCard" title="X3"> <img src="https://i.imgur.com/ucYCFcu.jpg" alt="BMW X3" /> </div> <div class="slideCard" title="iX"> <img src="https://i.imgur.com/bQhvuOY.jpg" alt="BMW 5 Series" /> </div> <div class="slideCard" title="5Series"> <img src="https://i.imgur.com/sLYH9Gy.jpg" alt="BMW 5 Series" /> </div> <div class="slideCard" title="BMW Certified Pre-Owned"> <img src="https://i.imgur.com/kuOWIEJ.jpg" alt="BMW Certified Pre-Owned" /> </div> </div> </div> </body>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM