1 个页面上的多个 Material UI 个滑块共享颜色道具

Multiple Material UI Sliders on 1 page sharing color props

我创建了一个组件“SliderBox”,其中 returns 一个 div 和一个 Material UI 滑块,它实现了 createMuiTheme,还有一个输入组件。

组件“SliderBox”将 onHover 方法应用于 parent div 以更改组件颜色的状态。基本上,我将 colorA 从红色变为蓝色,将 colorB 从蓝色变为红色。不幸的是,当在“SliderBox”的一个实例上调用此函数时,它会将颜色更改应用于每个“Slider”。颜色变化在内部进行管理,在“SliderBox”组件之外不受影响。

图 A 是默认状态下三个“SliderBox”组件的视图。

图 B 是三个“SliderBox”组件的视图,而最上面的组件的光标悬停在它上面。请注意,颜色变化似乎适用于所有三个“Slider”组件,但不适用于它们的包含组件“SliderBox”

尝试过的解决方案 我尝试向两个“SliderBox”组件添加唯一的键值,但行为没有变化。

我尝试使用标题和 Math.random() 添加唯一键值到 child“滑块”组件,没有看到任何变化。

我试图将一个唯一的键值传递给每个标记为“sliderKey”的“SliderBox”组件,然后我将键添加为“props.sliderKey”,这并没有显示错误行为的任何变化。

我试图将“Slider”组件与“SliderBox”组件分开,以便它returns在“SliderBox”而不是“Slider”内部实现的“CustomSlider”组件有些变化是注意到闪烁的颜色值发生变化,但所有 Slider 组件仍然共享相同的值。

我什至在实现“SliderBox”的顶层 parent 组件中添加了一个基础“Slider”组件,并且还应用了应用于“SliderBox”组件的 child 的样式到“SliderBox”组件的 parent 组件中的“Slider”组件。

假设 根据我的测试,我假设问题出在“SliderBox”组件中实现的“createMuiTheme”函数。我无法更改“createMuiTheme”,因为它在“overrides:MuiSlider:root:'& .MuiSlider-valueLabel':'& *':”中具有非常独特的 属性 backgroundColor 和颜色,这让我可以更改缩略图的文字颜色,如图 A 和 B 所示。缩略图的文字颜色对我的网站至关重要。我不能使用带有白色文本的缩略图的“滑块”组件。

我的另一个假设是从“import {Slider} from '@material-ui/core';”返回的组件进口。我的信念之一是“@material-ui/core”没有返回一个唯一的组件,或者他们可能没有将唯一的键应用于他们的组件,这导致在实现多个“滑块”组件时出现颜色溢出。

个人缺点 我相信,如果我在 JavaScript class 中实现我的滑块,我可能能够纠正这种错误行为,但我从未使用过“扩展组件”,所以我希望其他用户遇到并解决了以前这个问题。

不完全是我想要的 material UI 答案...但是我在使用 Material Ui 组件方面有很多负面经验,所以我徒劳地等待我的问题的答案,去制作了我自己的表格。

我的版本易于理解且完全可定制...我什至实现了 css 大多数 post 认为不存在的变量。

从现在开始,我将 post 我的可靠代码,这样任何人都可以复制和粘贴并避免暴虐 material UI 和缺乏可定制性。

码友注意事项 这是我的代码。如果您不喜欢我的命名约定、挂钩使用等,那么您可以随意使用它并编写您自己的版本。但我不会欣赏你对此的看法。我正在为其他受输入范围困扰的人分享我的代码

我的组件的示例图片::

SliderBar.jsx::

import React, {useState, useEffect} from "react";
import "./SliderBar.css";

export default function SliderBar(props){
  const backgroundColor = props.backgroundColor?props.backgroundColor:"#000";
  const textColor = props.textColor?props.textColor:"#fff";
  const hoverColor = props.hoverColor?props.hoverColor:"#888";
  const initialState = props.value?props.value:0;
  const min = props.min?props.min:0;
  const max = props.max?props.max:20;
  const bubbleClassName = props.bubbleClassName?props.bubbleClassName:("SliderBar-bubble-"+(Math.floor(Math.random()*100000001)));
  const bubbleSize = props.bubbleSize?props.bubbleSize:"30px";
  const cssValueChanger = {};

  const [sliderValue, sliderUpdate] = useState(initialState);
  const [textColorValue, textColorUpdate] = useState(textColor);
  const [oppositeColorValue, oppositeColorUpdate] = useState(backgroundColor);
  const [thumbColorValue, thumbColorUpdate] = useState(hoverColor)
  cssValueChanger["--color"] = props.hoverColor?props.hoverColor:thumbColorValue;

  useEffect(()=>{
    const element = document.querySelector(`.${bubbleClassName}`);

    if(element){
      const newVal = Number(((props.value?props.value:sliderValue - min) * 100) / (max - min));
      element.innerHTML = props.value?props.value:sliderValue;

      // Sorta magic numbers based on size of the native UI thumb
      element.style.left = `calc(${newVal}% + (${8 - newVal * 0.15}px))`;
    }
  });

  function onChange(event){
    sliderUpdate(event.target.value);
    if(props.onChange){
      props.onChange(event.target.value);
    }
  }

  function onMouseOver(){
    if(!props.over){
      textColorUpdate(hoverColor);
      oppositeColorUpdate(textColor);
      thumbColorUpdate(textColor);
    }
  }

  function onMouseOut(){
    if(!props.out){
      textColorUpdate(textColor);
      oppositeColorUpdate(backgroundColor);
      thumbColorUpdate(hoverColor);
    }
  }

  return(<div style={props.outerStyle}>
    <div onMouseOut={onMouseOut} onMouseOver={onMouseOver} style={{width:"200px", margin:"auto", position:"relative"}}>
      <input
        type="range"
        className="range"
        min={min}
        max={max}
        style={{
          ...cssValueChanger,
          width:"100%",
          background: props.textColor?props.textColor:textColorValue,
          color: props.backgroundColor?props.backgroundColor:oppositeColorValue,
        }}
        value={props.value?props.value:sliderValue}
        onChange={onChange}
      />
      <output
        value={props.value?props.value:sliderValue}
        className={bubbleClassName}
        style={{
          background: props.textColor?props.textColor:textColorValue,
          color: props.backgroundColor?props.backgroundColor:oppositeColorValue,
          position: "absolute",
          borderRadius: "100%",
          left: "50%",
          transform: "translateX(-50%)",
          top:"-30px",
          lineHeight:bubbleSize,
          width:bubbleSize,
          height:bubbleSize,
        }}
      />
    </div>
  </div>);
}

SliderBar.css::

input[type="range"] {
  -webkit-appearance: none;
  -moz-appearance: none;
  width: 300px;
  height: 5px;
  padding: 0;
  border-radius: 2px;
  outline: none;
  cursor: pointer;
}

/*Chrome thumb*/

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  -moz-appearance: none;
  -webkit-border-radius: 5px;
  /*16x16px adjusted to be same as 14x14px on moz*/
  height: 16px;
  width: 16px;
  border-radius: 5px;
  background: var(--color);
  border: 1px solid var(--color);
}


/*Mozilla thumb*/

input[type="range"]::-moz-range-thumb {
  -webkit-appearance: none;
  -moz-appearance: none;
  -moz-border-radius: 5px;
  height: 14px;
  width: 14px;
  border-radius: 5px;
  background: var(--color);
  border: 1px solid var(--color);
}


/*IE & Edge input*/

input[type=range]::-ms-track {
  width: 300px;
  height: 6px;
  /*remove bg colour from the track, we'll use ms-fill-lower and ms-fill-upper instead */
  background: transparent;
  /*leave room for the larger thumb to overflow with a transparent border */
  border-color: transparent;
  border-width: 2px 0;
  /*remove default tick marks*/
  color: transparent;
}


/*IE & Edge thumb*/

input[type=range]::-ms-thumb {
  height: 14px;
  width: 14px;
  border-radius: 5px;
  background: #e7e7e7;
  border: 1px solid #c5c5c5;
}


/*IE & Edge left side*/

input[type=range]::-ms-fill-lower {
  background: #919e4b;
  border-radius: 2px;
}


/*IE & Edge right side*/

input[type=range]::-ms-fill-upper {
  background: #c5c5c5;
  border-radius: 2px;
}


/*IE disable tooltip*/

input[type=range]::-ms-tooltip {
  display: none;
}

input[type="text"] {
  border: none;
}

SliderBox.jsx::

import React, {useState} from "react";
import SliderBar from "./slider/SliderBar";
import "./SliderBox.css";

/***
  <SliderBox
    title={"TextValue"}
    value={"TextValue"}
    onChange={function onChange()}
    textColor={"#ffffffff"}
    backgroundColor={"#00000000"}
    hoverColor={"#ff808080"}
    min={0}
    max={20}
  />
*/
export default function SliderBox(props){
  const initialState = props.value?props.value:0;
  const backgroundColor = props.backgroundColor?props.backgroundColor:"#000";
  const textColor = props.textColor?props.textColor:"#fff";
  const hoverColor = props.hoverColor?props.hoverColor:"#888";
  const min = props.min?props.min:0;
  const max = props.max?props.max:20;

  const [sliderValue, sliderUpdate] = useState(initialState);
  const [textColorValue, textColorUpdate] = useState(textColor);
  const [oppositeColorValue, oppositeColorUpdate] = useState(backgroundColor);

  function sliderChange(event){
    sliderUpdate(event);
    if(props.onChange!==undefined){
      props.onChange(event);
    }
  }

  function inputChange(event){
    let value = event.target.value;

    value = value.replace(/^0+/, '')

    if(value===""){
      value="0";
    }
    else if(!/^\d+$/.test(value)){
      return;
    }

    if(value > max){
      value = max;
    }else if(value < min){
      value = min;
    }

    sliderUpdate(value);
    if(props.onChange!==undefined){
      props.onChange(value);
    }
  }

  //selected Or Blur
  function onFocusOrMouseOut(){
    textColorUpdate(textColor);
    oppositeColorUpdate(backgroundColor);
  }

  function onBlur(){
    if(sliderValue.length<1){
      sliderUpdate(0);
    }
  }

  //hover
  function onMouseOver(){
    textColorUpdate(hoverColor);
    oppositeColorUpdate(textColor);
  }

  return(<div
    onMouseOver={onMouseOver}
    onMouseOut={onFocusOrMouseOut}
    onFocus={onFocusOrMouseOut}
    onBlur={onBlur}
    style={{
      width:"200px",
      margin:"auto",
      display:"table",
      height:"50px",
      padding:"35px 20px 15px",
      border:"1px solid "+textColorValue,
      borderRadius:"5px",
      position:"relative"
    }}
  >
    <p style={{
      position: "absolute",
      top: "-20px",
      margin: "0px",
      backgroundColor: backgroundColor,
      padding: "5px",
      borderRadius: "5px"
    }}>{props.title}</p>
    <SliderBar
      outerStyle={{padding:"20px", display:"table-cell"}}
      value={sliderValue}
      min={min}
      max={max}
      onChange={sliderChange}
      textColor={textColorValue}
      hoverColor={hoverColor}
      backgroundColor={oppositeColorValue}
    />
    <div
      style={{
        display:"table-cell",
        verticalAlign:"middle",
        width:"50px"
      }}
    >
      <input
        value={sliderValue}
        onChange={inputChange}
        style={{
          outline:"none",
          color:textColor,
          textAlign:"center",
          backgroundColor: backgroundColor,
          border: "1px solid "+textColorValue,
          borderRadius:"5px",
          width:"30px",
          height:"30px",
          "&:hover :selected":{
            outline:"none",
            color:textColorValue,
            backgroundColor: backgroundColor,
            border: "1px solid "+textColorValue,
          }
        }}
      />
    </div>
  </div>);
}

SliderBox.css

.PrivateValueLabel-label-900{
  color: "orange";
}
.MuiSlider-root .MuiSlider-valueLabel *{
  color: green;
  background-color: red;
}
[class^="PrivateValueLabel-label-"]{
  color: red;
}