Prev 和 Next 按钮在断点处无法正常工作
Posted
技术标签:
【中文标题】Prev 和 Next 按钮在断点处无法正常工作【英文标题】:Prev and Next button is not working correctly at the breakpoints 【发布时间】:2020-11-07 04:57:40 【问题描述】:各位,我在react-slick
滑块中遇到了问题。我在滑块上渲染一张卡片取决于数组长度。我还在渲染自定义 next
和 previous
按钮,它们触发 next
和 previous
函数来更改幻灯片。我也希望这个滑块能够响应。这意味着它具有根据定义的设置滚动幻灯片的功能。
我为断点定义的设置:
992
> slidesToScroll = 3
577 - 991
slidesToScroll = 2
0 - 576
slidesToScroll = 1
当没有向前滑动时next
按钮将被禁用,当没有向后滑动时previous
按钮将被禁用。为了实现这个功能,有一个名为 afterChange 的函数,它返回幻灯片的当前活动索引。所以我将该索引分配给state
。
但我认为我对next
按钮的逻辑不正确。
我有什么问题?
在调整窗口大小时有什么方法可以refresh
滑块,因为幻灯片没有根据breakpoints
重置?
即使没有向前滑动,next
按钮也不会在断点 (0 - 576)
处被禁用。
当用户更改单张幻灯片然后调整窗口大小时
要移至下一张幻灯片,Next
按钮将变为非活动状态。
我认为问题在于我写在 renderArrows
函数中的逻辑。
看到这个:
代码沙盒: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"
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="xMidYMid slice"
focusable="false"
>
<rect 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;
【问题讨论】:
【参考方案1】:看起来一切正常,但禁用了 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>
);
由于初始状态与实际值不同步,具体取决于断点,因此可能存在 cmets 中指出的特殊情况。使用 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
还可以在调整窗口大小时进行拍摄。因此,它也应该在调整大小时正确同步状态。
【讨论】:
感谢您的回答。我想问一下currentIndex = 0
、totalSlides = 2
和slidesToScroll = 0
。所以在这种情况下,3 slides
已经出现,那么lastElementsIndex
的值将是2
。下一个按钮不会被禁用,因为我们的条件将返回 false 即 0 > 2
你将如何处理它?
当slidesToScroll = 0
- 这是什么意思?在我看来,用户根本不应该滚动/看不到任何幻灯片?
对不起,我没听懂你的意思。这是 Codesandbox 链接see here 在此示例中,您可以看到全局变量中的幻灯片总数为3
,而在Desktop break-point
中已经出现了 3 张幻灯片,并且前面没有幻灯片。所以应该禁用下一个按钮。
啊,好吧,现在我看到了第二个问题。对不起!在链接代码中,state
与滑块开始接收的状态不同步。 slidesToScroll
仅在滑块更改时更新为正确的值,因此稍后更新。您可以使用 onInit
属性来同步它。我会更新答案【参考方案2】:
这是我为使您的代码正常工作所做的:
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;
【讨论】:
【参考方案3】:我在 currentIndex > cycleDots 中发现了一个问题。请改成 currentIndex >= cycleDots
【讨论】:
你能帮帮我吗?您知道调整窗口大小时刷新滑块的任何方法吗?以上是关于Prev 和 Next 按钮在断点处无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章
Flickity carousel:将 prev 和 next 按钮包装在自定义 div 中