JSX React HTML5 Input Slider Doesn't Work

后端 未结 5 1566
陌清茗
陌清茗 2021-01-31 02:48

I\'m using React.JS for a build, and am building a range input slider with two choices for a component.

this is my code:



        
相关标签:
5条回答
  • 2021-01-31 03:28

    Here's a solution for making form of multiple sliders or even one single slider with event handler passed we can simply use HTML input of type Range rc-slider and react-input-range don't sent event handler onChange or onAfterChange they sends the slider's value Implicitly, so we can't handle form of sliders or create them on the fly.

    jsfiddle snippet

    For more we can check HTML input Range and CSS provided by CSS-Tricks

    class SlidersExample extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          slidersLabels: ["A", "B", "C", "D"],
          sumOfCustomWeights: 0,
          slidersWeights: []
        };
      }
      componentDidMount() {
        const slidersLabels = this.state.slidersLabels;
        const slidersWeights = [];
        for (var i = 0; i < slidersLabels.length; ++i)
          slidersWeights[slidersLabels[i]] = 0;
        this.setState({ slidersWeights });
      }
    
      render() {
        return (
          <div>
            {this.generateSliders()}
            <span> Total Weights: {this.state.sumOfCustomWeights} </span>
          </div>
        );
      }
      generateSliders() {
        const slidersLabels = this.state.slidersLabels;
        var sliders = [];
        for (var i = 0; i < slidersLabels.length; ++i) {
          sliders.push(
            <div style={{ marginTop: "20px", marginBottom: "20px" }}>
              <span style={{ fontSize: "16px", marginBottom: "6px" }}>
                {" "}
                {slidersLabels[i]} ({this.state.slidersWeights[slidersLabels[i]]})%
              </span>
              <input
                id={slidersLabels[i]}
                type="range"
                defaultValue="0"
                min="0"
                max="100"
                className="slider"
                onChange={this.handleSliderChange.bind(this)}
                step="1"
              />
            </div>
          );
        }
         return sliders;
      }
      handleSliderChange(event) {
        //console.log(event.target.value, " ", event.target.id);
        var id = event.target.id;
        var value = event.target.value;
        const slidersWeights = this.state.slidersWeights;
        slidersWeights[id] = parseInt(value);
        var sumOfCustomWeights = 0;
        const slidersLabels = this.state.slidersLabels;
        for (var i = 0; i < slidersLabels.length; i++)
          sumOfCustomWeights += slidersWeights[slidersLabels[i]];
        this.setState({ slidersWeights, sumOfCustomWeights });
      }
    }
    
    ReactDOM.render(<SlidersExample />, document.querySelector("#app"));
    input[type=range] {
      -webkit-appearance: none;
      margin: 18px 0;
      width: 100%;
    }
    input[type=range]:focus {
      outline: none;
    }
    input[type=range]::-webkit-slider-runnable-track {
      width: 100%;
      height: 8.4px;
      cursor: pointer;
      animate: 0.2s;
      box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
      background: #3071a9;
      border-radius: 1.3px;
      border: 0.2px solid #010101;
    }
    input[type=range]::-webkit-slider-thumb {
      box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
      border: 1px solid #000000;
      height: 36px;
      width: 16px;
      border-radius: 3px;
      background: #ffffff;
      cursor: pointer;
      -webkit-appearance: none;
      margin-top: -14px;
    }
    input[type=range]:focus::-webkit-slider-runnable-track {
      background: #367ebd;
    }
    input[type=range]::-moz-range-track {
      width: 100%;
      height: 8.4px;
      cursor: pointer;
      animate: 0.2s;
      box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
      background: #3071a9;
      border-radius: 1.3px;
      border: 0.2px solid #010101;
    }
    input[type=range]::-moz-range-thumb {
      box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
      border: 1px solid #000000;
      height: 36px;
      width: 16px;
      border-radius: 3px;
      background: #ffffff;
      cursor: pointer;
    }
    input[type=range]::-ms-track {
      width: 100%;
      height: 8.4px;
      cursor: pointer;
      animate: 0.2s;
      background: transparent;
      border-color: transparent;
      border-width: 16px 0;
      color: transparent;
    }
    input[type=range]::-ms-fill-lower {
      background: #2a6495;
      border: 0.2px solid #010101;
      border-radius: 2.6px;
      box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
    }
    input[type=range]::-ms-fill-upper {
      background: #3071a9;
      border: 0.2px solid #010101;
      border-radius: 2.6px;
      box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
    }
    input[type=range]::-ms-thumb {
      box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
      border: 1px solid #000000;
      height: 36px;
      width: 16px;
      border-radius: 3px;
      background: #ffffff;
      cursor: pointer;
    }
    input[type=range]:focus::-ms-fill-lower {
      background: #3071a9;
    }
    input[type=range]:focus::-ms-fill-upper {
      background: #367ebd;
    }
    
    #app{
      margin-right: 100px;
      margin-left: 100px;
      margin-bottom: 100px;
      }
    <!DOCTYPE html>
    <html>
    <body>
    
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <div id="app"> </div>
    </body>
    </html>

    This solution working perfectly with me ;)

    Using CodeSandbox

    0 讨论(0)
  • 2021-01-31 03:33

    User interactions have no effect because an <input> with value prop is considered as controlled. It means that displayed value is controlled entirely by render function. So to actually update input value you should use the onChange event. Example:

    getInitialState: function() {
      return {value: 3};
    },
    handleChange: function(event) {
      this.setState({value: event.target.value});
    },
    render: function() {
      return (
        <input 
          id="typeinp" 
          type="range" 
          min="0" max="5" 
          value={this.state.value} 
          onChange={this.handleChange}
          step="1"/>
      );
    }
    

    You can also use defaultValue instead of value. In this case <input> is considered as uncontrolled and any user interactions are immediately reflected by element itself without invoking render function of your component.

    More on this in official documentation

    0 讨论(0)
  • 2021-01-31 03:46

    Try this:

    onInput() {
        var input = document.getElementById("typeinp");
        var currentVal = input.value;
        this.setState({
          value: currentVal
        })
    }
    
    <input id="typeinp" type="range" min="0" max="5" step="1" defaultValue="3" onInput={this.onInput.bind(this)}/>
    

    I suggest changing value="3" to defaultValue="3", otherwise I think value is hardcoded to "3" and may be difficult or impossible to change. The onInput function finds the value and adds it to state so the data can be passed to another component or function. There's likely a more elegant solution to your problem, but the above should work.

    0 讨论(0)
  • 2021-01-31 03:47

    I hope the above solutions might have resolved your issue, I have one simple approach using hooks.

    const RangeSlider = () => {
    
      const [rangeval, setRangeval] = useState(null);
    
      return (
        <div>
          <input type="range" className="custom-range" min="199" max="3999" 
           onChange={(event) => setRangeval(event.target.value)} />
          <h4>The range value is {rangeval}</h4>
        </div>
      );
    };
    
    export default RangeSlider;

    0 讨论(0)
  • 2021-01-31 03:50

    I think previous answers fix your problem. However, I'd say the solution doesn't need to involve React states.

    The only reason behind your frozen input slider is that you've hardcoded its value to 3, as @Colin Whitmarsh suggests.

    Simply, this works:

    <input id="typeinp" type="range" min="0" max="5" defaultValue="3" step="1"/>
    

    Now, you probably need its output to do something. You can use onChange={this.handleChange} as @xCrZx states in his answer. But inside handleChange you don't necessarily have to update your state. Depending on your logic, you could avoid increasing the complexity of your state and simply code your logic inside handleChange.

    If you avoid updating the state, you'll probably save some renders and your performance will improve.

    0 讨论(0)
提交回复
热议问题