双面输入滑块在react中,达到初始范围0后也会向左移动并增加值,为什么?

fkvaft9z  于 2021-09-13  发布在  Java
关注(0)|答案(0)|浏览(263)

我试图了解并修复双面输入滑块的错误

上面的滑块起始位置为0,但由于光标移动不正确,我得到的值为52。达到0后,我可以向左移动
scss:

$border-radius: 20px;

$primary: #709fdc;
$base: #071739;
$shadow-color:  #274684;
$lighter-shadow: rgba($shadow-color, .2);
$white: #fff;
$gray: #8c8c8c;
$lighter-gray: rgba($gray, .1);
$time-line-width: 240px;
$transition: .3s all ease;

@mixin dragIndicator($property, $background, $z-index) {
  #{$property}{
      position: absolute;
      top: 0;
      z-index: $z-index;
      width: 0;
      height: 5px;
      border-radius: 5px;
      background: $background;
      &:hover{
        &::before{
          opacity: 1;
        }
        &::after{
          opacity: 1;
        }
      }
      &::before{
        opacity: 0;
        content: attr(data-content);
        display: block;
        position: absolute;
        top: -40px;
        right: -23px;
        width: 40px;
        padding: 3px;
        text-align: center;
        color: white;
        background: $shadow-color;
        border-radius: $border-radius;
    }
    &::after{
      opacity: 0;
      content:'';
      display: block;
      position: absolute;
      top: -18px;
      right: -8px;
      border-top: 8px solid $shadow-color;
      border-left:8px solid transparent;
      border-right:8px solid transparent;
    }
    #{$property}-drag{
      position: absolute;
      right: -7.5px;
      top: -5px;

      width: 15px;
      height: 15px;

      border-radius: 50%;
      background: $base;
      transition: all .3s;
      &:hover{
        box-shadow: 0 0 0 6px $lighter-shadow;
      }
    }
  }
}

body{
  font-family: 'Rubik', sans-serif;
  color: $base;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  background: $lighter-gray;
  .card{
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    padding: 50px;
    padding-top: 25px;
    margin-top: 40px;
    border-radius: $border-radius;
    box-shadow: 0px 0px 20px 0px $lighter-shadow;
    background: $white;
    overflow: hidden;
    h2{
      margin-bottom: 40px;
    }
    .current-value{
      width: 100%;

      label{
        display: inline-flex;
        width: 50px;
        font-size: 20px;
      }
      input{
          margin: 0;
          max-width: 40px;
          margin-bottom: 5px;
          font-size: 16px;
          color: white;
          padding: 5px;
          padding-left: 15px;
          border: none;
          border-radius: $border-radius;
          background: $shadow-color;
        } 
    }
    .values{
      display: flex;
      justify-content: space-between;
      font-weight: 600;
      margin-top: 30px;
      margin-bottom: 10px;
      width: $time-line-width;
    }
    #slider{
      position: relative;
      margin: 0 auto;
      width: $time-line-width;
      height: 5px;
      background: $primary;
      border-radius: 5px;
      cursor: pointer;

      @include dragIndicator("#min", $primary, 2);
      @include dragIndicator("#max", $shadow-color, 1);
    }
  }
}

.fa-instagram{
  position: absolute;
  color: $base;
  top: 3%;
  right: 2%;
  font-size: 38px;
}
.fa-instagram:hover{
  font-size: 42px;
  color: $shadow-color;
  transition: all .1s linear;
  cursor: pointer;
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
input[type="number"] {
    -moz-appearance: textfield;
}

* :focus{

  outline: none;
  box-shadow: 0 0 0 2px $primary;
}

React代码:

class DoubleRangeSlider extends React.Component {
  state = {
    sliderWidth: 0,
    offsetSliderWidht: 0,
    min: 0,
    max: 200,
    minValueBetween: 10,

    currentMin: 55,
    inputMin: 55,

    currentMax: 100,
    inputMax: 100
  };

 componentDidMount() {
   const { currentMin, currentMax, max } = this.state;

   this.minValue.style.width = (currentMin*100)/max + "%";
   this.maxValue.style.width = (currentMax*100)/max + "%";

   this.setState({
     sliderWidth: this.slider.offsetWidth,
     offsetSliderWidht: this.slider.offsetLeft,
   })
 }

  setMin = (e) => {
    const { min, max, currentMax, minValueBetween } = this.state;
    const inputMin = e.target.value;

    this.setState({
        inputMin
    });

    if((inputMin >= min) && (inputMin <= (currentMax-minValueBetween))){
      this.setState({
        currentMin: parseInt(inputMin)
      }); 

      this.minValue.style.width = (inputMin*100)/max + "%";
    }
  }

  changeMinValue = (e) => {
    e.preventDefault();

    document.addEventListener('mousemove', this.onMouseMoveMin);
    document.addEventListener('mouseup', this.onMouseUpMin);

    document.addEventListener('touchmove', this.onMouseMoveMin);
    document.addEventListener('touchend', this.onMouseUpMin);
  }

  onMouseMoveMin = (e) => {
    const { min, max, currentMax, minValueBetween, sliderWidth, offsetSliderWidht } = this.state;

    const dragedWidht = e.clientX - offsetSliderWidht;
    const dragedWidhtInPercent = (dragedWidht*100)/sliderWidth;
    const currentMin = Math.abs(parseInt((max * dragedWidhtInPercent)/100));

    console.log(e.pageX, e.clientX, offsetSliderWidht);

    console.log(currentMin , (currentMax-minValueBetween));

    console.log((max * dragedWidhtInPercent)/100);

    if( (currentMin >= min) && (currentMin <= (currentMax-minValueBetween))){
      this.minValue.style.width = dragedWidhtInPercent + "%";
      this.minValue.dataset.content = currentMin;

      this.setState({
        currentMin,
        inputMin: currentMin
      })
    }
  }

  onMouseUpMin = () => {
    document.removeEventListener('mouseup', this.onMouseUpMin);
    document.removeEventListener('mousemove', this.onMouseMoveMin);

    document.removeEventListener('touchend', this.onMouseMoveMin);
    document.removeEventListener('touchmove', this.onMouseUpMin);
  }

  setMax = (e) => {
    const { min, max, currentMin, currentMax, minValueBetween } = this.state;

    const inputMax = e.target.value;

    this.setState({
        inputMax
    });

    if((inputMax >= currentMin + minValueBetween) && (inputMax <= max)){

      this.setState({
        currentMax: parseInt(inputMax)
      });
      this.maxValue.style.width = (inputMax*100)/max + "%";
    }

  }

  changeMaxValue = (e) => {
    e.preventDefault();

    document.addEventListener('mousemove', this.onMouseMoveMax);
    document.addEventListener('mouseup', this.onMouseUpMax);

    document.addEventListener('touchmove', this.onMouseMoveMax);
    document.addEventListener('touchend', this.onMouseUpMax);
  }

  onMouseMoveMax = (e) => {
    const { max, currentMin, minValueBetween, sliderWidth, offsetSliderWidht} = this.state; 
    const maxWalueThumb = this.maxValue;
    const dragedWidht = e.clientX - offsetSliderWidht;
    const dragedWidhtInPercent = (dragedWidht*100)/sliderWidth;
    const currentMax = Math.abs(parseInt((max * dragedWidhtInPercent)/100));

    if( (currentMax >= (currentMin + minValueBetween)) && (currentMax <= max)){

      maxWalueThumb.style.width = dragedWidhtInPercent + "%";
      maxWalueThumb.dataset.content = currentMax;
      this.setState({
        currentMax,
        inputMax: currentMax
      })
    }
  }

  onMouseUpMax = () => {
    document.removeEventListener('mouseup', this.onMouseUp);
    document.removeEventListener('mousemove', this.onMouseMoveMax);

    document.removeEventListener('touchend', this.onMouseUp);
    document.removeEventListener('touchmove', this.onMouseMoveMax);
  }

  maxForMin = () => {
    const { currentMax, minValueBetween} = this.state; 
    return currentMax - minValueBetween;
  }

  minForMax = () => {
    const { currentMin, minValueBetween} = this.state; 
    return currentMin + minValueBetween;
  }

  render() {
    const { min, max, currentMin, inputMin, currentMax, inputMax, minValueBetween } = this.state;

    return (
      <div className="card"> 
        <h2>Double range slider</h2>
        <div className="current-value">
          <label htmlFor="min-input">Min: </label>
          <input 
            id="min-input" 
            type="number" 
            onChange={this.setMin} 
            value={inputMin}
            min={min}
            max={this.maxForMin}/>

          <br/>
          <label htmlFor="max-input">Max: </label>
          <input 
            id="max-input" 
            type="number" 
            onChange={this.setMax} 
            value={inputMax}
            min={this.minForMax}
            max={max}/>

        </div>

        <div className="values">
          <div>{ min }</div>
          <div>{ max }</div>
        </div>

        <div ref={ref => this.slider = ref} id="slider">

          <div ref={ref => this.minValue = ref} id="min" data-content={currentMin}>
            <div ref={ref => this.minValueDrag = ref} id="min-drag" onMouseDown ={this.changeMinValue} onTouchStart={this.changeMinValue}></div>
          </div>

          <div ref={ref => this.maxValue = ref} id="max" data-content={currentMax}>
            <div ref={ref => this.maxValueDrag = ref} id="max-drag" onMouseDown={this.changeMaxValue} onTouchStart={this.changeMaxValue}></div>
          </div>

        </div>
      </div>
    )
  }
}

ReactDOM.render(
  <DoubleRangeSlider/>,
  document.getElementById('root')
)

源代码:https://codepen.io/olgakoplik/pen/mdyblme

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题