简体   繁体   中英

How to center value of slider range input? React, NextJS, Tailwind

I can not solve the problem with the offset. Is there any way to bind a value to the thumb?

I tried two methods, quite simple, but the first one gives a strong offset, the second one gives less. But this looks like a trick, not a solution, what do you recommend?

I need accurate center positioning.

What I have (1st trick):

图片

Second trick: 图片

import { useEffect, useState } from "react";

function Slider() {
  const [value, setValue] = useState(50);

  useEffect(() => {
    const tooltip = document.getElementById("tooltip");
    const maxValue = document.getElementById("slider").getAttribute("max");
    const val = document.getElementById("slider").getAttribute(value);
    const center = (value / maxValue) * 100 + "%";

    if (tooltip) {
      tooltip.style.left = center;
    }
  });

  // useEffect(() => {
  //   const allRanges = document.querySelectorAll(".range-wrap");
  //   allRanges.forEach((wrap) => {
  //     const range = wrap.querySelector(".range");
  //     const bubble = wrap.querySelector(".bubble");
  //
  //     range.addEventListener("input", () => {
  //       setBubble(range, bubble);
  //     });
  //     setBubble(range, bubble);
  //   });
  //
  //   function setBubble(range, bubble) {
  //     const val = range.value;
  //     const min = range.min ? range.min : 0;
  //     const max = range.max ? range.max : 100;
  //     const newVal = Number(((val - min) * 100) / (max - min));
  //     bubble.innerHTML = val;
  //
  //     bubble.style.left = `calc(${newVal}% + (${8 - newVal * 0.15}px))`;
  //   }
  // });

  return (
    <>
      <div className="range-wrap relative flex h-[24px] w-full items-center">
        <input
          className="range relative flex w-full"
          aria-valuemin={0}
          type="range"
          min="0"
          max="100"
          value={value}
          id="slider"
          onChange={({ target: { value: radius } }) => {
            setValue(radius);
          }}
        />
        <div id="progress"></div>
        <div
          id="tooltip"
          className="bubble absolute top-[-40px] left-1/2 flex h-[38px] w-[32px] -translate-x-1/2 items-center justify-center rounded-full bg-purple-400 align-middle text-body-medium text-white"
        >
          {value}
        </div>
      </div>
    </>
  );
}

export { Slider };

I use your method as well and I am very specific with the top and left values (-right-[1.1rem] for example). Probably not the greatest solution but it works fine for me.

在此处输入图像描述

Try this code out.
replace useEffect wtih this

  useEffect(() => {
    const range = document.querySelector("input[type=range]");
    const tooltip = document.getElementById("tooltip");

    let thumbSize = 8;
    const ratio = (range.value - range.min) / (range.max - range.min)
    let amountToMove = ratio * ((range.offsetWidth - thumbSize) - thumbSize) + thumbSize
    tooltip.style.left = amountToMove+"px"
  }, [value]);

And in return() paste this JSX

      <div className="range-wrap relative flex h-[24px] w-full items-center">
        <input
          className="range relative flex w-full"
          aria-valuemin={0}
          type="range"
          min="0"
          max="100"
          value={value}
          id="slider"
          onChange={({ target: { value: radius } }) => {
            setValue(radius);
          }}
        />
        <div id="progress"></div>
        <div
          id="tooltip"
          className={`bubble absolute top-[-40px] flex h-[38px] w-[32px] -translate-x-1/2 items-center justify-center rounded-full bg-purple-400 align-middle text-body-medium text-white`}
        >
          {value}
        </div>
      </div>

This should works as you expect.

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM