效果:
image.png
不用svg几乎都是需要有额外的元素遮挡实现,但没有办法做到半透明圆环效果。纯svg画,加宽path的stroke宽度视觉上呈现圆环。(是不是高中学过的三角函数快忘光了?)

以半径32的圆环为例,注意画笔定位基准落在中心位置,需要调整viewbox尺寸避免出现圆环显示不完整。(拷贝自用)

import { createElement, useState, useEffect, useRef, useCallback } from 'rax';

interface IProps {
  time: number; // milliseconds
  style?: Rax.CSSProperties;
  onEnd?: () => void;
}
export const CircleTimer = (props: IProps) => {
  const curT = useRef(0);
  const timer = useRef<number>();
  const [point, setPoint] = useState('32 0');

  useEffect(() => {
    return () => {
      if (timer.current) {
        clearTimeout(timer.current);
      }
    };
  }, []);

  const calPoint = useCallback(() => {
    if (curT.current >= props.time) {
      props.onEnd && props.onEnd();
      return;
    }

    timer.current = setTimeout(() => {
      curT.current += 50;
      const deg = (curT.current / props.time) * Math.PI * 2;
      const x = 32 + 32 * Math.sin(deg);
      const y = 32 - 32 * Math.cos(deg);
      if (curT.current < (1 / 2) * props.time) {
        setPoint(`${x} ${y}`);
      } else if (curT.current > (1 / 2) * props.time) {
        setPoint(`32 64 A 32 32 0 0 1 ${x} ${y}`);
      }
      calPoint();
    }, 50);
  }, [props.time, props.onEnd]);

  useEffect(() => {
    calPoint();
  }, [calPoint]);

  return (
    <svg
      width="60rpx"
      height="60rpx"
      style={props.style || {}}
      viewBox="-2 -2 68 68"
      version="1.1"
      xmlns="http://www.w3.org/2000/svg"
      xmlnsXlink="http://www.w3.org/1999/xlink"
    >
      <path
        d={`M32 0 A 32 32 0 0 1 ${point}`}
        stroke="white"
        fill="transparent"
        stroke-width="4"
      />
    </svg>
  );
};

备注:

  1. 出现stroke width不生效:rax中疑似不能把stroke-width写成strokeWidth。
  2. 圆环半径不影响实际尺寸,但注意根据自己的圆环半径调整viewbox尺寸避免显示不完整,本例圆环半径32.。
  3. 圆环起终点坐标相同,故使用path方式绘制时,必须要设定一个路径的中间点,本例设定了180度位置为中间点。

Marckon
1k 声望169 粉丝

正在成长的小前端...