英文:
Inversing slider value without affecting drag functionality MUI Slider React
问题
我有一个 MUI 滑块,滑块的值需要根据布尔变量进行反转。我的当前代码能够正确反转它,但它也反转了拖动功能,也就是说,如果我试图将滑块向 0 拖动,它会移向 100。我无法想出一个解决办法来修复这个问题。如果有人有任何建议,我会很感激。
const handleSelectionChange = (e: any) => {
if (typeof e.target.value === 'string') {
onChange(e.target.value)
} else {
onChange(Number(e.target.value))
}
}
<Slider
aria-label='DiceRoll'
defaultValue={50}
valueLabelDisplay='auto'
step={1}
min={0}
max={100}
value={overUnder ? 100 - targetNumber : targetNumber} // overUnder 是布尔值,targetNumber 的范围是从 0 到 100。
marks={marks}
onChange={handleSelectionChange}
/>
以上是您提供的代码的翻译部分。
英文:
I have a MUI slider where the value of the slider needs to be inverted based on a boolean variable. My current code inverts it correctly but it also inverts the drag functionality, meaning if I tried to drag my slider towards 0, it would move towards 100 instead. I can't think of a workaround to correct this. Would appreciate if anyone has any suggestions I could try.
const handleSelectionChange = (e: any) => {
if (typeof e.target.value === 'string') {
onChange(e.target.value)
} else {
onChange(Number(e.target.value))
}
}
<Slider
aria-label='DiceRoll'
defaultValue={50}
valueLabelDisplay='auto'
step={1}
min={0}
max={100}
value={overUnder ? 100 - targetNumber : targetNumber} //overUnder is boolean and targetNumber ranges from 0 to 100.
marks={marks}
onChange={handleSelectionChange}
/>
答案1
得分: 0
使用valueLabelFormat
函数,您可以简单地格式化数字显示而不是数字值本身,从而避免这个问题。
请使用以下代码:
valueLabelFormat={(v) => (overUnder ? 100 - v : v)}
将值恢复为正常:
value={targetNumber}
以下是代码示例:
const { StrictMode, useState } = React;
const { createRoot } = ReactDOM;
const App = () => {
const [overUnder, setOverUnder] = useState(false);
const [targetNumber, setTargetNumber] = useState(42.0);
const handleSelectionChange = (e) => {
if (typeof e.target.value === "string") {
setTargetNumber(e.target.value);
} else {
setTargetNumber(Number(e.target.value));
}
};
const onFlip = () => {
setOverUnder((s) => !s);
};
return (
<div>
<div>
<button onClick={onFlip}>Flip</button>
</div>
<div>Target Number: {targetNumber}</div>
<div>Over Under: {`${overUnder}`}</div>
<MaterialUI.Slider
aria-label="DiceRoll"
defaultValue={50}
valueLabelDisplay="on"
step={1}
min={0}
max={100}
value={targetNumber}
valueLabelFormat={(v) => (overUnder ? 100 - v : v)}
marks={false}
inverted={true}
onChange={handleSelectionChange}
sx={{ pt: "10rem" }}
/>
</div>
);
}
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<StrictMode>
<App />
</StrictMode>
);
希望这对您有所帮助。
英文:
Using the valueLabelFormat
function, you can simply format the number display instead of the number value itself, preventing the problem.
Use this instead:
valueLabelFormat={(v) => (overUnder ? 100 - v : v)}
Set the value back to normal:
value={targetNumber}
<!-- begin snippet: js hide: false console: true babel: true -->
<!-- language: lang-js -->
const { StrictMode, useState } = React;
const { createRoot } = ReactDOM;
const App = () => {
const [overUnder, setOverUnder] = useState(false);
const [targetNumber, setTargetNumber] = useState(42.0);
const handleSelectionChange = (e) => {
if (typeof e.target.value === "string") {
setTargetNumber(e.target.value);
} else {
setTargetNumber(Number(e.target.value));
}
};
const onFlip = () => {
setOverUnder((s) => !s);
};
return (
<div>
<div>
<button onClick={onFlip}>Flip</button>
</div>
<div>Target Number: {targetNumber}</div>
<div>Over Under: {`${overUnder}`}</div>
<MaterialUI.Slider
aria-label="DiceRoll"
defaultValue={50}
valueLabelDisplay="on"
step={1}
min={0}
max={100}
value={targetNumber}
valueLabelFormat={(v) => (overUnder ? 100 - v : v)}
marks={false}
inverted={true}
onChange={handleSelectionChange}
sx={{ pt: "10rem" }}
/>
</div>
);
}
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<StrictMode>
<App />
</StrictMode>
);
<!-- language: lang-html -->
<div id="root"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@mui/material@latest/umd/material-ui.production.min.js"></script>
<!-- end snippet -->
Also a sandbox for reference.
答案2
得分: 0
在几个小时之后,我找到了解决方案,实际上这是一个相当简单的解决方案,只需要额外的3行代码。我们只需引入另一个状态,其唯一目的是显示正确的滑块值。
const handleSelectionChange = (e: any) => {
if (overUnder) { // overUnder的默认值为true
if (typeof e.target.value === 'string') {
onChange(e.target.value);
} else {
onChange(Number(e.target.value));
}
} else {
if (typeof e.target.value === 'string') {
onChange(100 - e.target.value);
setFlippedTargetNumber(e.target.value);
} else {
onChange(100 - Number(e.target.value));
setFlippedTargetNumber(Number(e.target.value));
}
}
}
const [flippedTargetNumber, setFlippedTargetNumber] = useState<number>(50);
<Slider
aria-label='DiceRoll'
defaultValue={50}
valueLabelDisplay='auto'
step={1}
min={0}
max={100}
value={overUnder ? targetNumber : flippedTargetNumber} // overUnder是布尔值,targetNumber范围从0到100。
marks={marks}
onChange={handleSelectionChange}
/>
基本上,这是它的作用:当overUnder
为true
时,滑块将正常工作。当它被翻转并且overUnder
为false
时,onChange
将更新targetNumber
为其相反值(对于其他组件是必需的)。而setFlippedTargetNumber
将用作滑块值,而不是targetNumber
。
希望这对于面临类似问题的任何人有所帮助。
英文:
So after a few hours I've found the solution, it's actually a pretty simple solution, just an additional 3 lines of codes. We just have to introduce another state which only purpose is to display the correct slider Value.
const handleSelectionChange = (e: any) => {
if(overUnder){ //defaultValue of overUnder is true
if (typeof e.target.value === 'string') {
onChange(e.target.value)
} else {
onChange(Number(e.target.value))
}
} else {
if (typeof e.target.value === 'string') {
onChange(100 - e.target.value)
setFlippedTargetNumber(e.target.value)
} else {
onChange(100 - Number(e.target.value))
setFlippedTargetNumber(Number(e.target.value))
}
}
}
const [ flippedTargetNumber, setFlippedTargetNumber] = useState<number>(50)
<Slider
aria-label='DiceRoll'
defaultValue={50}
valueLabelDisplay='auto'
step={1}
min={0}
max={100}
value={overUnder ? targetNumber : flippedTargetNumber} //overUnder is boolean and targetNumber ranges from 0 to 100.
marks={marks}
onChange={handleSelectionChange}
/>
basically what this does is, when overUnder = true, and when it's true, the slider would just work normally. when it is flipped and overUnder = false, onChange will update targetNumber to inverse [which is needed for other components]. and setFlippedTargetNumber will be used as slider Value instead of targetNumber.
Hope this helps anyone who is facing a similar problem.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论