为 React-Leaflet CSS SVG 路由动画附加 onAnimationEnd

attaching onAnimationEnd for React-Leaflet CSS SVG route animation

我正在使用以下方法为在 React Leaflet 中绘制的路线制作动画,效果很好。但是我想对 CSS 使用 onAnimationEnd。我不知道在哪里可以找到该元素并附加 eventListener。

export default function Map()
{
...
  const RoutingMachineRef = useRef(null);
  useEffect(() =>
  {
    RoutingMachineRef.current.setWaypoints([start, end]);
  },[RoutingMachineRef, start, end]);
...
  return(
    <MapContainer>
      <RoutingMachine ref={RoutingMachineRef} waypoints={[start, end]} />
    </MapContainer>
  )
};

RoutingMachine.js

const createRoutingMachineLayer = (props) =>
{
    const { waypoints } = props;
    const instance =  L.Routing.control(
    {
        waypoints,
        // router: router,
        lineOptions: {
            styles: [ {className:'animate'} ]
        },
        show: false,
        addWaypoints: false,
        routeWhileDragging: false,
        draggableWaypoints: false,
        fitSelectedRoutes: true,
        showAlternatives: false,
        createMarker: function() { return null; },
    })
    return instance
}

const RoutingMachine = createControlComponent(createRoutingMachineLayer)    
export default RoutingMachine;

CSS:

path.leaflet-interactive.animate {
    stroke-dasharray: 1920;
    stroke-dashoffset: 1920;
    animation: dash 20s linear 3s forwards;
}

@keyframes dash {
    to {
        stroke-dashoffset: 0;
    }
}

你设置得很好。您的 RoutingMachine 组件写得很好,您已经有了对它的引用。伟大的。让我们在控制台中检查 RoutingMachineRef

如您所见,如果您深入挖掘,可以在 RoutingMachineRef.current._line._layers[some_layer_id]._path 找到 svg 路径组件。但是 小心 因为有时 leaflet 路由机器会绘制多个图层(单独的 svg 图层用于圆形线帽等)。您实际上可以通过 RoutingMachineRef.

直接访问这些 dom 元素

我不确定其中哪一个在您的代码中获得了 .animate css class,但您可以将事件侦听器添加到其中的每一个。我想只有其中一个会真正动画化(那里可能是一个有问题的假设),所以事件侦听器只会触发一次,当具有 .animate class 的那个停止动画时:

const RoutingMachineRef = useRef(null);
  useEffect(() => {
    RoutingMachineRef.current.setWaypoints([start, end]);
    const pathComponents = Object.values(RoutingMachineRef.current._line._layers);
    pathComponents.forEach((component) => {
      component._path.addEventListener("animationend", () => {
        // animateend callback code here
      });
    });
  },[RoutingMachineRef, start, end]);

我创建了一个codesandbox来帮助演示。我没有任何实际的动画,所以我只是添加了一个点击监听器。当页面加载出来,路由出现后,点击它,可以看到它正在监听点击事件。

Sample Codesandbox

我编写的 codesandbox 与我们的代码略有不同,因为您似乎有一些状态变量 startend 触发 useEffect 到 运行。对于我的情况,我没有这样的状态变量来帮助触发 useEffect - 我希望它在挂载时为 运行。但是 小心 因为你不能指望你的 useEffect 能够在挂载时正确地使用 ref 变量,因为 refs 不是在第一次渲染之后创建的。但另一方面,试图通过在 dep 数组中插入一个 ref 来触发 useEffects 充满了问题。所以我在 routingMachine 传单实例的事件 routesfound 上添加了一个侦听器,它将状态变量 routerReady 设置为 true,然后我将 that 包含在 dep 数组中。这里的逻辑是,一旦创建了路由机器并完成了第一次搜索,我就会触发一个 useEffect 来添加这些事件侦听器。您可能需要调整此逻辑以满足您的需要 - 如果您的 waypoints 是动态的,您将需要在每次绘制新路线时添加侦听器,因为它是一个全新的 svg 路径。