我将创建一个类似the MacDonalds one的滑块:
目的是使滑块适合所包含的元素,然后单击向右或向左按钮时,滑块将朝一侧或另一侧,如果用户已到达一侧或另一侧,则返回另一侧。
问题是我的滑块完全不一致,不能正确响应事件触发,并且状态管理也很麻烦,所以我想知道如何改进我的应用程序,
我的滑块没有流畅的行为,在此演示中,请当心使用StackOverflow的浏览器上的脚本错误,但JSFiddle成功读取了脚本:
let scopeProps= 5
class App extends React.Component{
state={
// number of items in he slider
totalSliderItem:0,
// deplacement range to handle the sliding => default to scopeProps
moveRange: scopeProps,
// range of sliderView => default to scopeProps
boxScope:scopeProps,
// unitWidth of each box item => scopeProps/ number of item desired inside a box view
unitWidth:0,
// number of item outside box view localize at the right of box
outsideBoxRight:0,
// number of item outside box view localize at the left of box
outsideBoxLeft:0
}
componentDidMount(){
// set CSS variable
// § call body variable
let root= document.body;
// § update css variable --slider-container-scope
root.style.setProperty('--slider-container-scope', scopeProps);
// § update css variable CSS variable --unit-width
// call metacontainer ref
let SliderMetaContainer= this.refs.sliderMetaContainer
// get metacontainer width
let metaContainerWidth=SliderMetaContainer.getBoundingClientRect().width
let unitWidth= metaContainerWidth/scopeProps
root.style.setProperty('--unit-width', unitWidth + "px") ;
// set number of items contained in slider
let sliderContainer= this.refs.sliderContainer
let sliderContainerLength= sliderContainer.childElementCount
console.log("sliderContainerRef length: ", sliderContainerLength);
// initial number of items localized outside box view == all box overcosm slider scope
let outsideBoxRight=sliderContainerLength-scopeProps
// initialize state after componentDidMount
this.setState({
totalSliderItem:sliderContainerLength,
outsideBoxRight,
unitWidth
})
}
// when user click a button to move => handleSlideMove()
handleSlideMove=(direction)=>{
console.log("window: ", window)
console.log("in handleSlideMove")
// appreciate number of item outsideBox depending of direction targeted
let outsideBoxUnit= direction==="left" ? -(this.state["outsideBoxLeft"]) : this.state["outsideBoxRight"];
// direction => if(outsideBox(direction)<=0 ==> call boundary
if(outsideBoxUnit <= 0){
// go to other boundary
let boundaryRange = this.state.totalSliderItem - this.state.boxScope;
this.boundaryMove(boundaryRange, direction)
}
// else make a move further in the slider
else this.furtherMove(outsideBoxUnit, direction)
}
// if click on boundary => go to other side
boundaryMove=(boundaryRange, direction)=>{
console.log("in boundaryMove")
// each category has a specific unitWidth
let unitWidth=this.state.unitWidth
let boxScope=this.state.boxScope
// set other boundary range
let moveRange= boundaryRange
let move= unitWidth * moveRange
// console.log("unitWidth, boxScope, outsideBoxUnit: ", unitWidth, boxScope, outsideBoxUnit);
// set movement range
// let move= outsideBoxUnit < boxScope? unitWidth * outsideBoxUnit: unitWidth * boxScope
// console.log("move: ", move);
// handle movement direction
if(direction==="left") move= -move
console.log("move value: ", move)
// trigger movement
document.body.style.setProperty('--item-left', move + "px");
this.updateItemRepartition(moveRange)
}
// if remain slide space forward => explore further the slide
furtherMove=(outsideBoxUnit, direction)=>{
console.log("in furtherMove")
// each category has a specific unitWidth
let unitWidth=this.state.unitWidth
console.log("line 109, unitWidth: ", unitWidth)
let boxScope=this.state.boxScope
let move
let moveRange = outsideBoxUnit < boxScope? outsideBoxUnit: boxScope
// handle movement direction
move= unitWidth * moveRange
// if(direction==="left") move=move
console.log("outsideBoxUnit line 104: ", outsideBoxUnit)
console.log("move value: ", move)
// trigger movement
document.body.style.setProperty('--item-left', move + "px");
this.updateItemRepartition(moveRange, direction)
}
// update how many items are outside the box view from each side
updateItemRepartition=(moveRange, direction)=>{
// get boxScope
let boxScope=this.state.boxScope
// appreciate if the number to use for update should be boxScope _ outsideBox
let range= moveRange < boxScope? moveRange : boxScope
// update outsideBox value according to movement direction
this.setState( currentState =>{
// move to left => increase right outsideBoxItem _ decrease left outsideBoxItem
let updateBoxRight= direction === "left" ?
currentState.outsideBoxRight + range
:
currentState.outsideBoxRight - range
// move to righ => increase left outsideBoxItem _ decrease right outsideBoxItem
let updateBoxLeft= direction !== "left" ?
currentState.outsideBoxLeft + range
:
currentState.outsideBoxLeft - range
// debugging => appreciate number to evaluate if update would be relevant
console.log(
"currentState.outsideBoxLeft, currentState.outsideBoxRight, range: ",
currentState.outsideBoxLeft, currentState.outsideBoxRight, range
)
// update component state
return ({
outsideBoxRight:updateBoxRight,
outsideBoxLeft:updateBoxLeft
})
})
}
render(){
return (
<div className="page">
Awesome containers here!
<button onClick={() => this.handleSlideMove("left")} >
move left
</button>
<div ref="sliderMetaContainer" className="slider_metacontainer">
<div ref="sliderContainer" className="slider_container">
<div className="slider_item">
1
</div>
<div className="slider_item">
2
</div>
<div className="slider_item">
3
</div>
<div className="slider_item">
4
</div>
<div className="slider_item">
5
</div>
<div className="slider_item">
6
</div>
<div className="slider_item">
7
</div>
<div className="slider_item">
8
</div>
<div className="slider_item">
9
</div>
<div className="slider_item">
10
</div>
<div className="slider_item">
11
</div>
<div className="slider_item">
12
</div>
<div className="slider_item">
13
</div>
<div className="slider_item">
14
</div>
<div className="slider_item">
15
</div>
</div>
</div>
<button onClick={() => this.handleSlideMove("right")} >
move right
</button>
</div>
)
};
}
ReactDOM.render(<App />, document.querySelector("#app"))
:root{
--slider-container-scope: 0;
--unit-width: 0;
--item-left:0;
}
.page {
text-align: center;
display:flex;
width:100%;
flex-direction: column;
align-items:center;
justify-content: center;
}
.slider_metacontainer{
width: 400px;
background: #444;
display: flex;
overflow: auto;
margin: 10vh 0;
}
.slider_container{
position:relative;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: nowrap;
left:var(--item-left);
transition: left 0.5s ease-out;
}
.slider_item{
width: var(--unit-width);
height:25vh;
}
.slider_item:nth-child(3n-2) { background-color: #EF5350; }
.slider_item:nth-child(3n-1) { background-color: #2E7D32; }
.slider_item:nth-child(3n) { background-color: #03A9A4; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
任何了解如何处理滑条的提示都将非常有用,
谢谢!!
最佳答案
更新了小提琴,
Fiddle
尝试更改scopeProps
的任何值<= totalSliderItem/2
,您会注意到其中的区别。
还要摆脱那个烦人的滚动条,
overflow: hidden;
到元素
slider_metacontainer
代码说明:
state={
totalSliderItem:0, // number of items in he slider
unitWidth:0, // width of one unit in px
currentPosition:0, // current position
updatedTotal:0// total number of elements after adding remaining elements
}
这是不言自明的
let remainder = sliderContainerLength % scopeProps
if( remainder != 0 ) updatedTotal += (scopeProps - remainder)
for (let i = 0; i < remainder; i++) {
$(sliderContainer).append('<div className="slider_item"></div>');
}
如果
scopeProps
不能将totalSliderItem
与剩余的0
精确地相除,这将添加剩余的元素,您将需要包括jQuery文件才能使其工作。handleSlideMove=(direction)=>{
let cP;
if(direction === 'left'){
cP = this.state.currentPosition + scopeProps;
if(cP == this.state.updatedTotal ){
this.state.currentPosition = 0 ;
document.body.style.setProperty('--item-left', 0 + "px");
}else{
this.state.currentPosition = cP ;
document.body.style.setProperty('--item-left', -cP*this.state.unitWidth + "px");
}
}else{
cP = this.state.currentPosition - scopeProps;
if(this.state.currentPosition == 0){
this.state.currentPosition = this.state.updatedTotal - scopeProps;
document.body.style.setProperty('--item-left', - this.state.currentPosition*this.state.unitWidth + "px");
}else{
this.state.currentPosition = cP;
document.body.style.setProperty('--item-left', - cP*this.state.unitWidth + "px");
}
}
}
对于向左移动,将
scopeProps
添加到currentPosition
,如果此值等于updatedTotal
,则将滑块移回原始位置,即如下所示向左极移,this.state.currentPosition = 0 ;
document.body.style.setProperty('--item-left', 0 + "px");
否则将此值乘以
unitWidth
,更新currentPosition
并按如下所示移至右侧的下一组,this.state.currentPosition = cP ;
document.body.style.setProperty('--item-left', -cP*this.state.unitWidth + "px");
同样,对于向右移动,从
scopeProps
中减去currentPosition
,如果currentPosition
等于0
,则按如下所示将滑块移至最右端,this.state.currentPosition = this.state.updatedTotal - scopeProps;
document.body.style.setProperty('--item-left', - this.state.currentPosition*this.state.unitWidth + "px");
否则将相减后的值乘以
unitWidth
,更新currentPosition
并按如下所示移至左下一组,this.state.currentPosition = cP;
document.body.style.setProperty('--item-left', - cP*this.state.unitWidth + "px");
检查Fiddle以获得完整代码。