javascript - onDrag-händelse clientX returnerar 0 i Firefox när man konverterar komponent till Typescript
Jag konverterar en React JS-anpassad slider-komponent till en React Typescript-komponent (jsx) och stöter på problemet att den slutar glida i Firefox. e.clientX är alltid 0, men den vanliga React JS-komponenten fungerar som förväntat i Firefox. De fungerar båda bra i Chrome.
Jag är inte säker på om detta fortfarande är den kända Firefox-buggen gällande "drag"-händelsen. Jag har läst dessa källor: 1, 2, 3, 4, 5.
Frågor:
- Är detta fortfarande samma bugg som nämns i några av de nämnda källorna?
- Varför händer detta specifikt i Typescript, och inte i Javascript?
- Vilken lösning skulle du föreslå för full webbläsarstöd (Firefox, Chrome, Safari)?
Javascript-version
import {useRef, useState} from "react";
export default function Slider({initialValue, onChange}) {
const sliderEl = useRef(null)
const [dragging, setDragging] = useState(false)
const [value, setValue] = useState(initialValue)
const calculateValue = (x) => {
const {x: sliderX, width: sliderWidth} = sliderEl.current.getBoundingClientRect()
const value = (x - sliderX) / sliderWidth
return Math.max(0, Math.min(value, 1))
}
const handleDrag = (e) => {
if (e.clientX === 0) {
return
}
setValue(calculateValue(e.clientX))
}
const handleClick = (e) => {
const value = calculateValue(e.clientX)
setValue(value)
onChange(value)
}
const offsetLeft = `calc(${value * 100}% - 0.5rem)`
return <div className="relative h-4" onMouseDown={handleClick} ref={sliderEl}>
<div className="bg-primary-5 rounded-full h-1 w-full top-1.5 absolute"/>
<div className="bg-primary-500 rounded-l-full h-1 top-1.5 absolute" style={{width: `${value * 100}%`}}/>
<div className="rounded-full bg-primary-700 w-4 h-4 absolute top-0" style={{left: offsetLeft}}/>
<div className="rounded-full bg-primary-500 w-4 h-4 absolute top-0 cursor-pointer"
draggable={true}
style={{left: offsetLeft, opacity: dragging ? 0 : 1}}
onDragStart={(e) => { setDragging(true) }}
onDrag={handleDrag}
onDragEnd={(e) => {
setDragging(false)
onChange && onChange(value)
}}
/>
</div>
}
Typescript-konvertering
import React, { useRef, useState } from 'react'
type SliderProps = {
initialValue: number,
onChange: (value: number) => void
}
export default function Slider({ initialValue = 0, onChange }: SliderProps) {
const sliderEl = useRef<HTMLDivElement>(null)
const [dragging, setDragging] = useState(false)
const [value, setValue] = useState<number>(initialValue)
const calculateValue = (x: number): number => {
if(!sliderEl.current) return 0
const { x: sliderX, width: sliderWidth }: DOMRect = sliderEl.current.getBoundingClientRect()
const value = (x - sliderX) / sliderWidth
return Math.max(0, Math.min(value, 1))
}
const handleDrag = (e: React.MouseEvent<HTMLDivElement>) => {
if (e.clientX === 0) {
return
}
setValue(calculateValue(e.clientX))
}
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
const value = calculateValue(e.clientX)
if(value) {
setValue(value)
onChange(value)
}
}
const offsetLeft = `calc(${value * 100}% - 0.5rem)`
return <div className="relative h-4" onMouseDown={handleClick} ref={sliderEl}>
<div className="bg-primary-5 rounded-full h-1 w-full top-1.5 absolute"/>
<div className="bg-primary-500 rounded-l-full h-1 top-1.5 absolute" style={{width: `${value * 100}%`}}/>
<div className="rounded-full bg-primary-700 w-4 h-4 absolute top-0" style={{left: offsetLeft}}/>
<div className="rounded-full bg-primary-500 w-4 h-4 absolute top-0 cursor-pointer"
draggable={true}
style={{left: offsetLeft, opacity: dragging ? 0 : 1}}
onDragStart={(e) => { setDragging(true) }}
onDrag={handleDrag}
onDragEnd={(e) => {
setDragging(false)
onChange && onChange(value)
}}
/>
</div>
}
import React, { useRef, useState } from 'react'
type SliderProps = {
initialValue: number,
onChange: (value: number) => void
}
export default function Slider({ initialValue = 0, onChange }: SliderProps) {
const sliderEl = useRef<HTMLDivElement>(null)
const [dragging, setDragging] = useState(false)
const [value, setValue] = useState<number>(initialValue)
const calculateValue = (x: number): number => {
if(!sliderEl.current) return 0
const { x: sliderX, width: sliderWidth }: DOMRect = sliderEl.current.getBoundingClientRect()
const value = (x - sliderX) / sliderWidth
return Math.max(0, Math.min(value, 1))
}
const handleDrag = (e: React.MouseEvent<HTMLDivElement>) => {
e.preventDefault()
console.log(e.clientX)
if (e.clientX === 0) {
return
}
setValue(calculateValue(e.clientX))
}
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
const value = calculateValue(e.clientX)
if(value) {
setValue(value)
onChange(value)
}
}
const offsetLeft = `calc(${value * 100}% - 0.5rem)`
return <div className="relative h-4" onMouseDown={handleClick} ref={sliderEl}>
<div className="bg-primary-5 rounded-full h-1 w-full top-1.5 absolute"/>
<div className="bg-primary-500 rounded-l-full h-1 top-1.5 absolute" style={{width: `${value * 100}%`}}/>
<div className="rounded-full bg-primary-700 w-4 h-4 absolute top-0" style={{left: offsetLeft}}/>
<div className="rounded-full bg-primary-500 w-4 h-4 absolute top-0 cursor-pointer"
draggable={true}
style={{left: offsetLeft, opacity: dragging ? 0 : 1}}
onDragStart={(e) => { setDragging(true) }}
onDrag={handleDrag}
onDragEnd={(e) => {
setDragging(false)
onChange && onChange(value)
}}
/>
</div>
}
Tack!