React:将双色滑块拇指设置为具有透明背景的图像

4
我制作了一个滑动条,左边应该是蓝色的,右边是灰色的。而且蓝色部分应该比灰色部分更宽。

enter image description here

我有两个问题需要解决:
  1. 如果拇指块有一个透明的切口,那么滑块的蓝色部分不会完全延伸到图像可见区域的左侧。
  2. 我希望滑块的边缘是圆形的,特别是蓝色边缘(可能不需要灰色)。

通过圆角,我的意思是像这样 在此输入图片描述


这里是该代码的CodeSandbox链接

以下是代码本身

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} />;


对我来说最好的非法解决方案是编辑图像以具有蓝线,但我仍然无法弄圆它。 - Sam
如果您有一个只能解决我的一个问题的解决方案,并且没有解决两个问题的答案,我会给您赏金。 - Sam
1个回答

2

我注意到重复使用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作为props传递,如下所示

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
     />
   )
}

这里是一个实时示例

编辑 Slider (styled-components) (forked)


谢谢,我注意到图像的背景现在是浅色的。看起来是这样的 - Sam
乍一看,我以为这是因为Firefox中的Shdow DOM,但实际上,你只需要在const thumb = css中添加background-color: transparent;就可以解决了,哈哈。快来看看我的沙盒吧。 - Liam
所以我查看了Firefox,发现有另一个奇怪的问题。在这些图像中,Chrome在上面,Firefox在下面。 - Sam
所以我遇到了一个问题。在我的程序中,有一个位置有两个滑块,其值是相互反转的。在这种情况下,对面的滑块拇指不会移动,以下是此情况的代码沙盒 - Sam
@Sam https://codesandbox.io/s/slider-styled-components-forked-k10tb - Liam
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接