我将创建一个类似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以获得完整代码。

09-25 16:51