如何解决遍历数组时在实现 Carousel 时遇到困难
我想使用来自我的 Vidoes Array 的数据实现轮播,我无法获得所需的输出,而是同时渲染了 Array 中的所有视频
<div id="carouselExampleSlidesOnly" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-inner">
{Videos}
</div>
</div>
This is my Videos array
const Videos = VIDEOS.map((vid) => {
if(vid.name=="Video1"){
vari=true;
}
return (
<div
className={vari?"carousel-item active":"carousel-item"}
style={{ width: "25vw",height: "5vh",background: "#F1F1F1",margin:"auto" }}
>
<img src="..." class="card-img-top" alt={vid.name}></img>
</div>
);
});
解决方法
几天前我刚刚完成了这个。但还没有缩短、优化和添加视频支持
这是我的代码:
import React,{ useEffect,useState } from 'react';
import "./MediaViewer.css";
import { useGlobalObj,globalObj } from 'logic/zergski-global-object';
// content JSON
import { mediaJSON } from 'logic/content-collections';
// components
import Anchor from 'shared/Anchor';
let current = 'can1';
let canvas = {
can1: {
pos: 'center',trans: true,source: mediaJSON[0].src,},can2: {
pos: 'right',source: mediaJSON[1].src,can3: {
pos: 'left',trans: false,source: mediaJSON[mediaJSON.length-1].src,}
}
// iterator
// TODO! add settings
const iterator = ( array,setState,initIndex ) => {
let index = initIndex;
let count = array.length - 1; // content count
let nextSource = index+2; // next imagesource to load
let nextCanvas = 0; // canvas position
let nextImageSource = nextCanvas - 1;
return {
next() {
index = index === count ? 0 : ++index;
nextSource = index+1 > count ? 0 : index+1;
Object.entries(canvas).forEach( c => {
canvas[c[0]].pos = c[1].pos === 'center' ? 'left' : c[1].pos === 'right' ? 'center' : 'right';
c[1].pos === 'center' && (current = c[0]);
if ( c[1].pos === 'right' ) {
canvas[c[0]].trans = false;
canvas[c[0]].source = mediaJSON[nextSource].src;
} else {
canvas[c[0]].trans = true;
}
});
setState({
...canvas,counter: index+1,});
},prev() {
index = index === 0 ? count : --index;
nextSource = index-1 < 0 ? count : index-1;
Object.entries(canvas).forEach( c => {
canvas[c[0]].pos = c[1].pos === 'center' ? 'right' : c[1].pos === 'left' ? 'center' : 'left';
c[1].pos === 'center' && (current = c[0]);
if ( c[1].pos === 'left' ) {
canvas[c[0]].trans = false;
canvas[c[0]].source = mediaJSON[nextSource].src;
} else {
canvas[c[0]].trans = true;
}
});
setState({
...canvas,});
}
}
}
var lastTouch = 0;
var content = Object.create(null);
// component for viewing images,videos and documents
const MediaViewer = props => {
const mediaViewer = {
display: 'hidden',contentIndex: 0,initialState: { display: 'hidden' },}
const [ viewerState,setViewerState ] = useGlobalObj({ mediaViewer });
const [ state,setState ] = useState({
...canvas,counter: 1,});
const [ touchState,setTouchState ] = useState({
touch: false,movement: 0,});
if ( viewerState.display === 'show' ) {
document.body.classList.add('scroll-lock');
setTimeout(()=>{
globalObj.mediaViewer.setState({ display: 'visible' });
},50)
}
useEffect(() => {
const { display,index } = viewerState;
if ( display === 'show' ) {
content = iterator( mediaJSON,index );
current = 'can1';
canvas = {
can1: {
pos: 'center',source: mediaJSON[index].src,can2: {
pos: 'right',source: mediaJSON[index === mediaJSON.length-1 ? 0 : index+1].src,can3: {
pos: 'left',source: mediaJSON[index === 0 ? mediaJSON.length-1 : index-1].src,}
}
setState({
...canvas,})
}
},[viewerState]);
const handleClose = () => {
globalObj.mediaViewer.setState({ display: 'hide' });
setTimeout(()=>{
globalObj.mediaViewer.setState({ display: 'hidden' });
},400)
document.body.classList.remove('scroll-lock');
}
// input handlers
const handleMovement = ( delta,touch=false ) => {
let nextMovement = touchState.movement - delta;
canvas[current].trans = false;
canvas[current].movement = nextMovement;
setTouchState({ movement: nextMovement });
}
// touch
const handleTouchStart = (e) => {
lastTouch = e.nativeEvent.touches[0].clientX;
}
const handleTouchMove = (e) => {
const delta = lastTouch - e.nativeEvent.touches[0].clientX;
lastTouch = e.nativeEvent.touches[0].clientX;
handleMovement(Math.floor(delta),true);
}
const handleTouchEnd = (e) => {
touchState.movement < -50 ? content.next() : touchState.movement > 50 && content.prev();
lastTouch = 0;
canvas[current].trans = true;
setTouchState({ movement: 0 });
}
return (
<div className={ `Media-Viewer ${ viewerState.display }` }
onTouchStart={ handleTouchStart }
onTouchMove={ handleTouchMove }
onTouchEnd={ handleTouchEnd }
>
<img className={ `Media-Viewer-Content ${ state.can1.pos }` } alt={ '' }
src={ state.can1.source }
style={{
transform: current === 'can1' ? `translateX(${ touchState.movement }px)` : '',transitionDuration: `${ canvas.can1.trans ? '' : '0s' }`,}}
/>
<img className={ `Media-Viewer-Content ${ state.can2.pos }` } alt={ '' }
src={ state.can2.source }
style={{
transform: current === 'can2' ? `translateX(${ touchState.movement }px)` : '',transitionDuration: `${ canvas.can2.trans ? '' : '0s' }`,}}
/>
<img className={ `Media-Viewer-Content ${ state.can3.pos }` } alt={ '' }
src={ state.can3.source }
style={{
transform: current === 'can3' ? `translateX(${ touchState.movement }px)` : '',transitionDuration: `${ canvas.can3.trans ? '' : '0s' }`,}}
/>
<div className="Modal-User-Interface-Wrapper">
<div className="Information-Box">
<h4>{ `${ state.counter }/${ mediaJSON.length }` }</h4>
</div>
<Anchor
altClass="icon"
fileName="cross.svg"
style={{ position: 'absolute',top: '0',right: '0',opacity: '.5' }}
clicked={ handleClose }
/>
<Anchor
altClass="icon"
fileName="arrow.svg"
style={{ transform: 'rotate(180deg)' }}
clicked={ ()=>content.prev() }
/>
<Anchor
altClass="icon"
fileName="arrow.svg"
clicked={ ()=>content.next() }
/>
</div>
</div>
);
}
export default MediaViewer;
和 CSS
.Media-Viewer {
display: flex;
position: fixed;
justify-content: space-around;
align-items: center;
height: calc(100*var(--vh));
width: 100vw;
height: 100vh;
top: 0; left: 0;
overflow: hidden;
z-index: 10;
transition: opacity .4s ease;
}
.Media-Viewer.hide,.Media-Viewer.show {
opacity: 0;
}
.Media-Viewer.hidden {
display: none;
}
.Media-Viewer-Content {
display: flex;
position: absolute;
height: 100%;
width: 100%;
object-fit: contain;
top: 0; left: 0;
z-index: 9;
transition: transform .4s ease;
will-change: transform;
}
.Media-Viewer-Content.center {
transform: translate3d(0,0);
}
.Media-Viewer-Content.right {
transform: translate3d(100vw,0);
}
.Media-Viewer-Content.left {
transform: translate3d(-100vw,0);
}
.Modal-User-Interface-Wrapper {
display: flex;
position: relative;
justify-content: space-between;
align-items: center;
width: calc( 100vw - (100vw - 300px) / 10 );
opacity: .6;
height: calc(100*var(--vh));
z-index: 10;
transition: opacity 1.2s ease;
transition-delay: 4s;
}
.Media-Viewer .Anchor {
display: flex;
position: relative;
height: 3.5rem;
width: 3.5rem;
padding: 1rem .7rem 1rem 1rem;
opacity: .1;
margin-bottom: 1.7rem;
border-radius: 4rem;
cursor: pointer;
transition: opacity,background-color .7s ease;
z-index: 10;
transition-duration: .44s;
}
.Media-Viewer .Anchor:hover,.Media-Viewer:active .Modal-User-Interface-Wrapper,.Media-Viewer-Content:active .Modal-User-Interface-Wrapper {
opacity: .9;
transition-duration: .1s;
transition-delay: 0s;
}
.Media-Viewer .Anchor:hover {
opacity: .7;
background-color:rgba(0,0.089);
}
/* overlay */
.Media-Viewer::before {
content: '';
position: absolute;
height: 100vh;
width: 100vw;
top: 0;
z-index: 8;
background-color: rgba(0,0.932);
backdrop-filter: blur(7px);
-webkit-backdrop-filter: blur(10px);
z-index: -1;
}
.Information-Box {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: .4rem; right: 0; left: 0;
margin: 0 auto;
height: 2.7rem;
width: calc(3rem + 10vw);
background: rgb(220,148,87);
background: linear-gradient(133deg,rgba(32,28,24,0.719) 0%,rgba(43,32,26,0.582) 100%);
border-radius: .6rem;
z-index: 10;
}
.Information-Box h4 {
position: absolute;
color: #fff;
font-size: .85rem;
font-weight: 700;
text-shadow: 1px 2px 5px rgb(1,4,5);
}
也许你会在这里找到一些有用的东西..
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。