Prev 和 Next 按钮在断点处无法正常工作
Prev and Next button is not working correctly at the breakpoints
伙计们,我在 react-slick
滑块中遇到了问题。我在滑块上渲染卡片取决于数组长度。我还呈现自定义 next
和 previous
按钮,它们触发 next
和 previous
函数来更改幻灯片。我还希望这个滑块能够响应。这意味着它具有根据定义的设置滚动幻灯片的功能。
我为断点定义的设置:
992
> slidesToScroll = 3
577 - 991
slidesToScroll = 2
0 - 576
slidesToScroll = 1
没有向前滑动时next
按钮将被禁用,没有向后滑动时previous
按钮将被禁用。为实现此功能,有一个名为 afterChange 的函数,它 returns 幻灯片的当前活动索引。所以我在 state
上分配了那个索引。
但我认为我对 next
按钮的逻辑不正确。
我的问题是什么?
有没有办法在 window 调整大小时 refresh
滑块,因为幻灯片没有根据 breakpoints
重置?
即使前面没有幻灯片,next
按钮也不会在断点 (0 - 576)
处禁用。
当用户更改单张幻灯片然后调整大小时 window
要移动到下一张幻灯片,Next
按钮将变为非活动状态。
我认为问题出在我写在 renderArrows
函数中的逻辑中。
看到这个:
Codesandbox:View this
代码:
import React, { useState, useRef } from "react";
import Slider from "react-slick";
// Constant Variables
// Slides scroll behavior on different sizes
const TOTAL_SLIDES = 6;
const DESKTOP_SLIDES_SCROLL = 3;
const TABLET_SLIDES_SCROLL = 2;
const MOBILE_SLIDES_SCROLL = 1;
/**
* It will return the JSX and register the callbacks for next and previous slide.
* @param prevCallback {function} - Go back to the previous slide
* @param nextCallback {function} - Go to the next slide
* @param state {object} - Holds the state of your slider indexes
* @param totalSlides {number} - Holds the total number of slides
* @return {*} - Returns the JSX
*/
const renderArrows = (
prevCallback,
nextCallback,
{ currentIndex, slidesToScroll },
totalSlides
) => {
const cycleDots =
currentIndex === 0 ? 1 : Math.ceil(totalSlides / slidesToScroll);
return (
<div>
<button disabled={currentIndex === 0} onClick={prevCallback}>
Previous
</button>
<button disabled={currentIndex > cycleDots} onClick={nextCallback}>
Next
</button>
</div>
);
};
const App = () => {
// We just have to keep track of the index by keeping it in the state
const [state, setState] = useState({ currentIndex: 0, slidesToScroll: 0 });
// To access underlying DOM object for the slider
const sliderRef = useRef();
// Trigger next method to show the next slides
const next = () => {
sliderRef.current.slickNext();
};
// Trigger previous method to show the previous slides
const previous = () => {
sliderRef.current.slickPrev();
};
// Slider Settings
const settings = {
slidesToShow: 3,
dots: false,
draggable: false,
slidesToScroll: DESKTOP_SLIDES_SCROLL,
arrows: false,
speed: 1300,
autoplay: false,
centerMode: false,
infinite: false,
afterChange: indexOfCurrentSlide => {
setState({
currentIndex: indexOfCurrentSlide,
slidesToScroll: DESKTOP_SLIDES_SCROLL
});
},
responsive: [
{
breakpoint: 992,
settings: {
slidesToShow: 2,
slidesToScroll: TABLET_SLIDES_SCROLL,
afterChange: indexOfCurrentSlide => {
setState({
currentIndex: indexOfCurrentSlide,
slidesToScroll: TABLET_SLIDES_SCROLL
});
}
}
},
{
breakpoint: 576,
settings: {
slidesToShow: 1,
slidesToScroll: MOBILE_SLIDES_SCROLL,
afterChange: indexOfCurrentSlide => {
setState({
currentIndex: indexOfCurrentSlide,
slidesToScroll: MOBILE_SLIDES_SCROLL
});
}
}
}
]
};
return (
<div className="app">
<div>
<h1>Slider Buttons</h1>
{renderArrows(previous, next, state, TOTAL_SLIDES - 1)}
</div>
{/* Slider */}
<Slider {...settings} ref={slider => (sliderRef.current = slider)}>
{[...Array(TOTAL_SLIDES)].map((_, index) => {
return (
<div className="card" key={index}>
<div className="card-img-top">
<svg
className="svg"
width="100%"
height="225"
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="xMidYMid slice"
focusable="false"
>
<rect width="100%" height="100%" fill="#55595c" />
<text x="50%" y="50%" fill="#eceeef" dy=".3em">
Image {index + 1}
</text>
</svg>
</div>
<div className="card-body">
<p className="card-text">
This is a wider card with supporting text below.
</p>
</div>
</div>
);
})}
</Slider>
</div>
);
};
export default App;
我发现 {currentIndex > cycleDots} 有问题。请更改为 {currentIndex >= cycleDots}
看起来一切正常,但禁用了 Next
按钮。我认为它应该已经可以通过更改 disabled
条件来检查滑块所在的幻灯片数量。
在提供的代码沙箱中将 renderArrow
正文更改为此似乎可行:
const lastElementsIndex = totalSlides - slidesToScroll;
return (
<div>
<button disabled={currentIndex === 0} onClick={prevCallback}>
Previous
</button>
<button disabled={currentIndex > lastElementsIndex} onClick={nextCallback}>
Next
</button>
</div>
);
由于断点不同,初始状态与实际值不同步,可能存在评论中指出的特殊情况。使用 onReInit
作为非箭头函数应该可以访问 Slick 滑块本身的 this
对象。从那里,可以检索到正确的 slidesToScroll
:
const settings = {
// ... other settings ...
onReInit: function() {
const slidesToScroll = this.slidesToScroll;
if (slidesToScroll !== state.slidesToScroll) {
setState(state => ({ ...state, slidesToScroll }));
}
},
// ... other settings ...
};
在之前的编辑中,我建议使用 onInit
- 使用 onReInit
也有利于 window 调整大小。因此它也应该在调整大小时正确同步状态。
为了让您的代码正常工作,我做了以下工作:
const renderArrows = (
prevCallback,
nextCallback,
{ currentIndex, slidesToScroll },
totalSlides
) => {
let cycleDots = 0;
if (slidesToScroll !== 0) {
cycleDots =
currentIndex === 0 ? 1 : Math.ceil(totalSlides / slidesToScroll);
} else {
cycleDots = 5;
}
return (
<div>
<button disabled={currentIndex === 0} onClick={prevCallback}>
Previous
</button>
<button disabled={currentIndex >= cycleDots} onClick={nextCallback}>
Next
</button>
</div>
);
};
我不知道您不想在 if-else 语句中将 'cycleDots' 值设置为什么;但是你应该能够用 totalSlides 为负 1 的任何值替换 5;
伙计们,我在 react-slick
滑块中遇到了问题。我在滑块上渲染卡片取决于数组长度。我还呈现自定义 next
和 previous
按钮,它们触发 next
和 previous
函数来更改幻灯片。我还希望这个滑块能够响应。这意味着它具有根据定义的设置滚动幻灯片的功能。
我为断点定义的设置:
992
> slidesToScroll = 3
577 - 991
slidesToScroll = 2
0 - 576
slidesToScroll = 1
没有向前滑动时next
按钮将被禁用,没有向后滑动时previous
按钮将被禁用。为实现此功能,有一个名为 afterChange 的函数,它 returns 幻灯片的当前活动索引。所以我在 state
上分配了那个索引。
但我认为我对 next
按钮的逻辑不正确。
我的问题是什么?
有没有办法在 window 调整大小时
refresh
滑块,因为幻灯片没有根据breakpoints
重置?即使前面没有幻灯片,
next
按钮也不会在断点(0 - 576)
处禁用。当用户更改单张幻灯片然后调整大小时 window 要移动到下一张幻灯片,
Next
按钮将变为非活动状态。
我认为问题出在我写在 renderArrows
函数中的逻辑中。
看到这个:
Codesandbox:View this
代码:
import React, { useState, useRef } from "react";
import Slider from "react-slick";
// Constant Variables
// Slides scroll behavior on different sizes
const TOTAL_SLIDES = 6;
const DESKTOP_SLIDES_SCROLL = 3;
const TABLET_SLIDES_SCROLL = 2;
const MOBILE_SLIDES_SCROLL = 1;
/**
* It will return the JSX and register the callbacks for next and previous slide.
* @param prevCallback {function} - Go back to the previous slide
* @param nextCallback {function} - Go to the next slide
* @param state {object} - Holds the state of your slider indexes
* @param totalSlides {number} - Holds the total number of slides
* @return {*} - Returns the JSX
*/
const renderArrows = (
prevCallback,
nextCallback,
{ currentIndex, slidesToScroll },
totalSlides
) => {
const cycleDots =
currentIndex === 0 ? 1 : Math.ceil(totalSlides / slidesToScroll);
return (
<div>
<button disabled={currentIndex === 0} onClick={prevCallback}>
Previous
</button>
<button disabled={currentIndex > cycleDots} onClick={nextCallback}>
Next
</button>
</div>
);
};
const App = () => {
// We just have to keep track of the index by keeping it in the state
const [state, setState] = useState({ currentIndex: 0, slidesToScroll: 0 });
// To access underlying DOM object for the slider
const sliderRef = useRef();
// Trigger next method to show the next slides
const next = () => {
sliderRef.current.slickNext();
};
// Trigger previous method to show the previous slides
const previous = () => {
sliderRef.current.slickPrev();
};
// Slider Settings
const settings = {
slidesToShow: 3,
dots: false,
draggable: false,
slidesToScroll: DESKTOP_SLIDES_SCROLL,
arrows: false,
speed: 1300,
autoplay: false,
centerMode: false,
infinite: false,
afterChange: indexOfCurrentSlide => {
setState({
currentIndex: indexOfCurrentSlide,
slidesToScroll: DESKTOP_SLIDES_SCROLL
});
},
responsive: [
{
breakpoint: 992,
settings: {
slidesToShow: 2,
slidesToScroll: TABLET_SLIDES_SCROLL,
afterChange: indexOfCurrentSlide => {
setState({
currentIndex: indexOfCurrentSlide,
slidesToScroll: TABLET_SLIDES_SCROLL
});
}
}
},
{
breakpoint: 576,
settings: {
slidesToShow: 1,
slidesToScroll: MOBILE_SLIDES_SCROLL,
afterChange: indexOfCurrentSlide => {
setState({
currentIndex: indexOfCurrentSlide,
slidesToScroll: MOBILE_SLIDES_SCROLL
});
}
}
}
]
};
return (
<div className="app">
<div>
<h1>Slider Buttons</h1>
{renderArrows(previous, next, state, TOTAL_SLIDES - 1)}
</div>
{/* Slider */}
<Slider {...settings} ref={slider => (sliderRef.current = slider)}>
{[...Array(TOTAL_SLIDES)].map((_, index) => {
return (
<div className="card" key={index}>
<div className="card-img-top">
<svg
className="svg"
width="100%"
height="225"
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="xMidYMid slice"
focusable="false"
>
<rect width="100%" height="100%" fill="#55595c" />
<text x="50%" y="50%" fill="#eceeef" dy=".3em">
Image {index + 1}
</text>
</svg>
</div>
<div className="card-body">
<p className="card-text">
This is a wider card with supporting text below.
</p>
</div>
</div>
);
})}
</Slider>
</div>
);
};
export default App;
我发现 {currentIndex > cycleDots} 有问题。请更改为 {currentIndex >= cycleDots}
看起来一切正常,但禁用了 Next
按钮。我认为它应该已经可以通过更改 disabled
条件来检查滑块所在的幻灯片数量。
在提供的代码沙箱中将 renderArrow
正文更改为此似乎可行:
const lastElementsIndex = totalSlides - slidesToScroll;
return (
<div>
<button disabled={currentIndex === 0} onClick={prevCallback}>
Previous
</button>
<button disabled={currentIndex > lastElementsIndex} onClick={nextCallback}>
Next
</button>
</div>
);
由于断点不同,初始状态与实际值不同步,可能存在评论中指出的特殊情况。使用 onReInit
作为非箭头函数应该可以访问 Slick 滑块本身的 this
对象。从那里,可以检索到正确的 slidesToScroll
:
const settings = {
// ... other settings ...
onReInit: function() {
const slidesToScroll = this.slidesToScroll;
if (slidesToScroll !== state.slidesToScroll) {
setState(state => ({ ...state, slidesToScroll }));
}
},
// ... other settings ...
};
在之前的编辑中,我建议使用 onInit
- 使用 onReInit
也有利于 window 调整大小。因此它也应该在调整大小时正确同步状态。
为了让您的代码正常工作,我做了以下工作:
const renderArrows = (
prevCallback,
nextCallback,
{ currentIndex, slidesToScroll },
totalSlides
) => {
let cycleDots = 0;
if (slidesToScroll !== 0) {
cycleDots =
currentIndex === 0 ? 1 : Math.ceil(totalSlides / slidesToScroll);
} else {
cycleDots = 5;
}
return (
<div>
<button disabled={currentIndex === 0} onClick={prevCallback}>
Previous
</button>
<button disabled={currentIndex >= cycleDots} onClick={nextCallback}>
Next
</button>
</div>
);
};
我不知道您不想在 if-else 语句中将 'cycleDots' 值设置为什么;但是你应该能够用 totalSlides 为负 1 的任何值替换 5;