React:将双色滑块拇指设置为具有透明背景的图像
React: Setting a dual color slider thumb to an image with transparent background
我做了一个滑块,左边应该是蓝色,右边是灰色。蓝色应该也比灰色厚一些。
我有 2 个问题。
- 如果拇指块有透明切口,则滑块的蓝色部分不会一直延伸到图像上可见部分的左侧。
- 我希望滑块的边缘是圆的,尤其是蓝色边缘(我可能不需要灰色)
我说的圆边是这样的
Here is a codesandbox of the code
以及代码本身
import React from "react";
import styled from "styled-components";
const image = "https://i.imgur.com/XMfYtkv.png";
const thumb = {
width: 25,
height: 26
};
const height = 36;
const trackHeight = 4;
// colours
const lowerBackground = `linear-gradient(to bottom, gray, gray) 100% 50% / 100% ${
trackHeight / 2.5
}px no-repeat transparent`;
const upperBackground = `linear-gradient(to bottom, blue, blue) 100% 50% / 100% ${
trackHeight / 2.5
}px no-repeat transparent`;
const makeLongShadow = (color, size) => {
// Colors the slider to the right of the thumbpiece
let i = 1;
let shadow = `-${i}px 0 0 ${size} ${color}`;
for (; i < 1950; i++) {
//If i is a small number, like 720, then when the slider gets set to its minimum, the end of the slider is the color for the left side of the slider, when it should be the color for the right side
shadow = `${shadow}, -${i}px 0 0 ${size} ${color}`;
}
return shadow;
};
const StyledSlider = styled.input`
overflow: hidden;
appearance: none;
height: ${height}px;
cursor: pointer;
marginbottom: 0;
&:focus {
outline: none;
}
&::-webkit-slider-runnable-track {
width: 100%;
height: ${height}px;
background: ${lowerBackground};
}
&::-webkit-slider-thumb {
position: relative;
appearance: none;
height: ${thumb.height}px;
width: ${thumb.width}px;
background: url(${image});
background-size: cover;
border: 0;
top: 50%;
transform: translateY(-50%);
box-shadow: ${makeLongShadow("blue", "-11px")};
transition: background-color 150ms;
}
&::-moz-range-progress {
background: ${lowerBackground};
}
&::-moz-range-track,
&::-moz-range-progress {
width: 100%;
height: ${height};
background: ${upperBackground};
}
&::-moz-range-thumb {
appearance: none;
margin: 0;
height: ${thumb.height}px;
width: ${thumb.height}px;
background: url(${image});
border: 0;
transition: background-color 150ms;
}
&::-ms-track {
width: 100%;
height: ${height}px;
border: 0;
/* color needed to hide track marks */
color: transparent;
background: transparent;
}
&::-ms-fill-lower {
background: ${lowerBackground};
}
&::-ms-fill-upper {
background: ${upperBackground};
}
&::-ms-thumb {
appearance: none;
height: ${thumb.height}px;
width: ${thumb.height}px;
background: url(${image});
border-radius: 100%;
border: 0;
transition: background-color 150ms;
/* IE Edge thinks it can support -webkit prefixes */
top: 0;
margin: 0;
box-shadow: none;
}
`;
//!Black line is too thick when then margin at the bottom is 11 or 10 ? I don't know what would cause this
export default (props) => <StyledSlider type="range" {...props} />;
我注意到 box-shadow
重复导致性能下降,我修复了您的代码问题并改进了代码。
在代码中,我写了注释,可以帮助您理解我所做的事情。
import React from "react";
import ReactDOM from "react-dom";
import styled, { css } from "styled-components";
import "./styles.css";
const image = "https://i.imgur.com/XMfYtkv.png";
const thumbD = "50px"; // image width + height prefered same value
const filllC = "blue"; //first line
const trackC = "gray"; //second line
const trackH = "0.6em"; //dont change it if not neccessry
const firstFillthicker = 10; //in px
const secondFillthicker = 4; //in px
const track = css`
box-sizing: border-box;
border: none;
height: ${secondFillthicker}px;
background: ${trackC};
border-radius: 8px;
`;
const trackFill = css`
${track};
height: ${firstFillthicker}px;
background-color: transparent;
background-image: linear-gradient(${filllC}, ${filllC}),
linear-gradient(${trackC}, ${trackC});
background-size: var(--sx) ${firstFillthicker}px,
calc(100% - var(--sx)) ${secondFillthicker}px;
background-position: left center, right center;
background-repeat: no-repeat;
`;
const inputCSS = css`
width: 100%;
--min: 0;
--max: 100;
--val: 50;
`;
const fill = css`
height: ${trackH};
background: ${filllC};
border-radius: 4px;
`;
const thumb = css`
margin-top: calc(0.5 * (${trackH} - ${thumbD}));
cursor: pointer;
margin-left: -15px;
background-size: cover;
background-color: transparent; // should add this for firefox
background-image: url(${image});
border: none;
width: ${thumbD};
height: ${thumbD};
`;
const StyledSlider = styled.input`
&,
&::-webkit-slider-thumb {
-webkit-appearance: none;
}
&:focus {
outline: none;
}
--range: calc(var(--max) - var(--min));
--ratio: calc((var(--val) - var(--min)) / var(--range));
--sx: calc(0.5 * ${thumbD} + var(--ratio) * (100% - ${thumbD}));
margin: 0;
padding: 0;
height: ${thumbD};
background: transparent;
font: 1em/1 arial, sans-serif;
&::-webkit-slider-runnable-track {
${trackFill};
}
&::-moz-range-track {
${track};
}
&::-ms-track {
${track};
}
&::-moz-range-progress {
${fill};
}
&::-ms-fill-lower {
${fill};
}
&::-webkit-slider-thumb {
${thumb};
}
&::-moz-range-thumb {
${thumb};
}
&::-ms-thumb {
margin-top: 0;
${thumb};
}
&::-ms-tooltip {
display: none;
}
&::-moz-focus-outer {
border: 0;
}
`;
export default (props) => <StyledSlider type="range" {...props} />;
确保像这样 onInput
函数和 style
传递道具
function Exam(){
const [value, setValue] = React.useState(50);
return (
<App onInput={e => setValue(e.target.value)}
style={{width: "80%","--min": 0,"--max": 100, "--val": value}} // pass the value from the props
/>
)
}
这是一个活生生的例子
我做了一个滑块,左边应该是蓝色,右边是灰色。蓝色应该也比灰色厚一些。
我有 2 个问题。
- 如果拇指块有透明切口,则滑块的蓝色部分不会一直延伸到图像上可见部分的左侧。
- 我希望滑块的边缘是圆的,尤其是蓝色边缘(我可能不需要灰色)
我说的圆边是这样的
Here is a codesandbox of the code
以及代码本身
import React from "react";
import styled from "styled-components";
const image = "https://i.imgur.com/XMfYtkv.png";
const thumb = {
width: 25,
height: 26
};
const height = 36;
const trackHeight = 4;
// colours
const lowerBackground = `linear-gradient(to bottom, gray, gray) 100% 50% / 100% ${
trackHeight / 2.5
}px no-repeat transparent`;
const upperBackground = `linear-gradient(to bottom, blue, blue) 100% 50% / 100% ${
trackHeight / 2.5
}px no-repeat transparent`;
const makeLongShadow = (color, size) => {
// Colors the slider to the right of the thumbpiece
let i = 1;
let shadow = `-${i}px 0 0 ${size} ${color}`;
for (; i < 1950; i++) {
//If i is a small number, like 720, then when the slider gets set to its minimum, the end of the slider is the color for the left side of the slider, when it should be the color for the right side
shadow = `${shadow}, -${i}px 0 0 ${size} ${color}`;
}
return shadow;
};
const StyledSlider = styled.input`
overflow: hidden;
appearance: none;
height: ${height}px;
cursor: pointer;
marginbottom: 0;
&:focus {
outline: none;
}
&::-webkit-slider-runnable-track {
width: 100%;
height: ${height}px;
background: ${lowerBackground};
}
&::-webkit-slider-thumb {
position: relative;
appearance: none;
height: ${thumb.height}px;
width: ${thumb.width}px;
background: url(${image});
background-size: cover;
border: 0;
top: 50%;
transform: translateY(-50%);
box-shadow: ${makeLongShadow("blue", "-11px")};
transition: background-color 150ms;
}
&::-moz-range-progress {
background: ${lowerBackground};
}
&::-moz-range-track,
&::-moz-range-progress {
width: 100%;
height: ${height};
background: ${upperBackground};
}
&::-moz-range-thumb {
appearance: none;
margin: 0;
height: ${thumb.height}px;
width: ${thumb.height}px;
background: url(${image});
border: 0;
transition: background-color 150ms;
}
&::-ms-track {
width: 100%;
height: ${height}px;
border: 0;
/* color needed to hide track marks */
color: transparent;
background: transparent;
}
&::-ms-fill-lower {
background: ${lowerBackground};
}
&::-ms-fill-upper {
background: ${upperBackground};
}
&::-ms-thumb {
appearance: none;
height: ${thumb.height}px;
width: ${thumb.height}px;
background: url(${image});
border-radius: 100%;
border: 0;
transition: background-color 150ms;
/* IE Edge thinks it can support -webkit prefixes */
top: 0;
margin: 0;
box-shadow: none;
}
`;
//!Black line is too thick when then margin at the bottom is 11 or 10 ? I don't know what would cause this
export default (props) => <StyledSlider type="range" {...props} />;
我注意到 box-shadow
重复导致性能下降,我修复了您的代码问题并改进了代码。
在代码中,我写了注释,可以帮助您理解我所做的事情。
import React from "react";
import ReactDOM from "react-dom";
import styled, { css } from "styled-components";
import "./styles.css";
const image = "https://i.imgur.com/XMfYtkv.png";
const thumbD = "50px"; // image width + height prefered same value
const filllC = "blue"; //first line
const trackC = "gray"; //second line
const trackH = "0.6em"; //dont change it if not neccessry
const firstFillthicker = 10; //in px
const secondFillthicker = 4; //in px
const track = css`
box-sizing: border-box;
border: none;
height: ${secondFillthicker}px;
background: ${trackC};
border-radius: 8px;
`;
const trackFill = css`
${track};
height: ${firstFillthicker}px;
background-color: transparent;
background-image: linear-gradient(${filllC}, ${filllC}),
linear-gradient(${trackC}, ${trackC});
background-size: var(--sx) ${firstFillthicker}px,
calc(100% - var(--sx)) ${secondFillthicker}px;
background-position: left center, right center;
background-repeat: no-repeat;
`;
const inputCSS = css`
width: 100%;
--min: 0;
--max: 100;
--val: 50;
`;
const fill = css`
height: ${trackH};
background: ${filllC};
border-radius: 4px;
`;
const thumb = css`
margin-top: calc(0.5 * (${trackH} - ${thumbD}));
cursor: pointer;
margin-left: -15px;
background-size: cover;
background-color: transparent; // should add this for firefox
background-image: url(${image});
border: none;
width: ${thumbD};
height: ${thumbD};
`;
const StyledSlider = styled.input`
&,
&::-webkit-slider-thumb {
-webkit-appearance: none;
}
&:focus {
outline: none;
}
--range: calc(var(--max) - var(--min));
--ratio: calc((var(--val) - var(--min)) / var(--range));
--sx: calc(0.5 * ${thumbD} + var(--ratio) * (100% - ${thumbD}));
margin: 0;
padding: 0;
height: ${thumbD};
background: transparent;
font: 1em/1 arial, sans-serif;
&::-webkit-slider-runnable-track {
${trackFill};
}
&::-moz-range-track {
${track};
}
&::-ms-track {
${track};
}
&::-moz-range-progress {
${fill};
}
&::-ms-fill-lower {
${fill};
}
&::-webkit-slider-thumb {
${thumb};
}
&::-moz-range-thumb {
${thumb};
}
&::-ms-thumb {
margin-top: 0;
${thumb};
}
&::-ms-tooltip {
display: none;
}
&::-moz-focus-outer {
border: 0;
}
`;
export default (props) => <StyledSlider type="range" {...props} />;
确保像这样 onInput
函数和 style
传递道具
function Exam(){
const [value, setValue] = React.useState(50);
return (
<App onInput={e => setValue(e.target.value)}
style={{width: "80%","--min": 0,"--max": 100, "--val": value}} // pass the value from the props
/>
)
}
这是一个活生生的例子