本期我们要做的是一个四方位云台操控器(也是遥控器),我们需要方向的 icon(自己找或者自己画~)和 ahooks 的 useInterval(ahooks 真好用啊 )

# 1. 实现目标

  • 长按可以设定每 x 秒触发一次接口
  • 点击也可以移动
  • ... 没了(就是这么简单)

# 2. 实现方法

export const DIRECTION_MAP: any = {
  top: 1,
  bottom: 6,
  left: 4,
  right: 5,
};
function Ptz(props: IPtzProps) {
  const [interval, setInterval] = useState<any>(null);
  const directionRef = React.useRef('');
  useEffect(() => {
    enterPTZ();
    return () => {
      exitPTZ();
    };
  }, []);
  useInterval(
    async () => {
      if (directionRef.current) {
        await controlPTZ({
          direction: DIRECTION_MAP[directionRef.current],
        }).then(() => {
          //console.log (`向 ${direction} 移一点`);
        });
      }
    },
    interval,
    { immediate: true }
  );
  const handlePress = (e: any) => {
    directionRef.current = e.target.dataset.direction;
    setInterval(interval + 1000); // 调用频率
  };
  return (
    <div className="control-wrapper">
      <div className="control-circle" />
      <div className="control-round" />
      <div
        className="control-btn control-top"
        data-direction="top"
        onMouseDown={handlePress}
        onMouseUp={() => {
          setInterval(null);
        }}
      >
        <Icon className="top-btn" type="arrowsolidlev1up" />
      </div>
      <div
        className="control-btn control-left"
        data-direction="left"
        onMouseDown={handlePress}
        onMouseUp={() => {
          setInterval(null);
        }}
      >
        <Icon className="left-btn" type="arrowsolidlev1down" />
      </div>
      <div
        className="control-btn control-bottom"
        data-direction="bottom"
        onMouseDown={handlePress}
        onMouseUp={() => {
          setInterval(null);
        }}
      >
        <Icon className="bottom-btn" type="arrowsolidlev1down" />
      </div>
      <div
        className="control-btn control-right"
        data-direction="right"
        onMouseDown={handlePress}
        onMouseUp={() => {
          setInterval(null);
        }}
      >
        <Icon className="right-btn" type="arrowsolidlev1up" />
      </div>
    </div>
  );
}
export default Ptz;

然后是最主要的 css

.control-wrapper {
  position: absolute;
  bottom: 60px;
  right: 40px;
  width: 150px;
  height: 150px;
  border-radius: 50%;
  // background-color:  rgba(0, 0, 0, 0.65);
  .top-btn{
    position: absolute;
    top: 0;
    left: 50%;
    transform: translate(-50%, 24px) rotate(45deg);
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    color: rgba(255,255,255, .75);
    z-index: 2;
    pointer-events: none;
  }
  .left-btn{
    position: absolute;
    top: 50%;
    left: 0;
    transform: translate(24px, -50%) rotate(45deg);
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(255,255,255, .75);
    z-index: 2;
    box-sizing: border-box;
    pointer-events: none;
  }
  .bottom-btn {
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translate(-50%, -24px) rotate(-45deg);
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(255,255,255, .75);
    z-index: 2;
    box-sizing: border-box;
    pointer-events: none;
  }
  .right-btn {
    position: absolute;
    top: 50%;
    right: 0;
    transform: translate(-24px, -50%) rotate(45deg);
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(255,255,255, .75);
    z-index: 2;
    box-sizing: border-box;
    pointer-events: none;
  }
  .control-btn {
    position: absolute;
    width: 62px;
    height: 62px;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1;
    box-sizing: border-box;
    // transition: all .3s linear;
    // background-color: red;
    background-color: rgba(0, 0, 0, 0.65);
    &::after{
      content: '';
      position: absolute;
      width: 62px;
      height: 62px;
      z-index: 1;
    }
  }
  .control-top {
      top: 0;
      left: 50%;
      transform: translateX(-50%) rotate(-45deg);
      border-radius: 0 100% 0 0;
      &:hover {
        .top-btn{
          color: rgba(255,255,255, 1);
         }
      }
      &:hover:after{
        background: rgba(255, 255, 255, 0.1);
      }
  }
  .control-top:before {
      transform: translate(30%, -25%);
  }
  .control-top:after {
      left: 0;
      bottom: 0;
      border-radius: 0 100% 0 0;
  }
  .control-bottom {
      left: 50%;
      bottom: 0;
      transform: translateX(-50%) rotate(45deg);
      border-radius: 0 0 100% 0;
      &:hover {
        .bottom-btn{
          color: rgba(255,255,255, 1);
        }
      }
      &:hover::after{
        background: rgba(255, 255, 255, 0.1);
      }
  }
  .control-bottom:before {
      transform: translate(25%, 25%) rotate(90deg);
  }
  .control-bottom:after {
      top: 0;
      left: 0;
      border-radius: 0 0 100% 0;
  }
  .control-left {
      top: 50%;
      left: 0;
      transform: translateY(-50%) rotate(45deg);
      border-radius: 0 0 0 100%;
      &:hover {
        .left-btn{
         color: rgba(255,255,255, 1);
        }
      }
      &:hover::after{
        background: rgba(255, 255, 255, 0.1);
      }
  }
  .control-left:before {
      transform: translate(-25%, 30%) rotate(180deg);
  }
  .control-left:after{
      right: 0;
      top: 0;
      border-radius: 0 0 0 100%;
  }
  .control-right {
      top: 50%;
      right: 0;
      transform: translateY(-50%) rotate(45deg);
      border-radius: 0 100% 0 0;
      &:hover {
        .right-btn{
          color: rgba(255,255,255, 1);
         }
      }
      &:hover::after{
        background: rgba(255, 255, 255, 0.1);
      }
  }
  .control-right:before {
      transform: translate(30%, -25%);
  }
  .control-right:after {
      left: 0;
      bottom: 0;
      border-radius: 0 100% 0 0;
  }
  .control-round {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 56.9px;
      height: 56.9px;
      background: #7C7C7C; 
      border-radius: 50%;
      z-index: 3;
  }
}

着重讲一下 pointer-events 这个属性

需要加上 pointer-events: nonenone 元素永远不会成为鼠标事件的 target (en-US)。但是,当其后代元素的 pointer-events 属性指定其他值时,鼠标事件可以指向后代元素,在这种情况下,鼠标事件将在捕获或冒泡阶段触发父元素的事件侦听器。

否则点击到 icon 的时候是没有方向的,也就无法调用接口。