Skip to main content

测量 DOM 节点

如果您想要测量一个 DOM 节点,您可以为其分配一个 React Ref,然后使用 getBoundingClientRect() 浏览器 API 来获取节点的位置和大小。

在 Remotion 中,这并不那么容易,因为视频渲染到的 <div> 元素上应用了一个 scale() 变换,这会影响您从 getBoundingClientRect() 获取的值。

使用 useCurrentScale() 钩子进行测量

从 v4.0.111 开始,您可以使用 useCurrentScale() 钩子来校正元素的尺寸。

MyComponent.tsx
tsx
import { useCallback, useEffect, useState, useRef } from "react";
import { useCurrentScale } from "remotion";
 
export const MyComponent = () => {
const ref = useRef<HTMLDivElement>(null);
 
const [dimensions, setDimensions] = useState<{
correctedHeight: number;
correctedWidth: number;
} | null>(null);
 
const scale = useCurrentScale();
 
useEffect(() => {
if (!ref.current) {
return;
}
 
const rect = ref.current.getBoundingClientRect();
 
setDimensions({
correctedHeight: rect.height / scale,
correctedWidth: rect.width / scale,
});
}, [scale]);
 
return (
<div>
<div ref={ref}>Hello World!</div>
</div>
);
};
MyComponent.tsx
tsx
import { useCallback, useEffect, useState, useRef } from "react";
import { useCurrentScale } from "remotion";
 
export const MyComponent = () => {
const ref = useRef<HTMLDivElement>(null);
 
const [dimensions, setDimensions] = useState<{
correctedHeight: number;
correctedWidth: number;
} | null>(null);
 
const scale = useCurrentScale();
 
useEffect(() => {
if (!ref.current) {
return;
}
 
const rect = ref.current.getBoundingClientRect();
 
setDimensions({
correctedHeight: rect.height / scale,
correctedWidth: rect.width / scale,
});
}, [scale]);
 
return (
<div>
<div ref={ref}>Hello World!</div>
</div>
);
};

v4.0.110 之前的版本

为了获得准确的测量,您可以渲染一个具有固定宽度(比如 10px)的额外元素,并对其进行测量。然后,您可以将元素的宽度除以 10 来获得比例因子。

MyComponent.tsx
tsx
import { useCallback, useEffect, useState, useRef } from "react";
 
const MEASURER_SIZE = 10;
 
export const MyComponent = () => {
const ref = useRef<HTMLDivElement>(null);
const measurer = useRef<HTMLDivElement>(null);
 
const [dimensions, setDimensions] = useState<{
correctedHeight: number;
correctedWidth: number;
} | null>(null);
 
useEffect(() => {
if (!ref.current || !measurer.current) {
return;
}
 
const rect = ref.current.getBoundingClientRect();
const measurerRect = measurer.current.getBoundingClientRect();
const scale = measurerRect.width / MEASURER_SIZE;
 
setDimensions({
correctedHeight: rect.height * scale,
correctedWidth: rect.width * scale,
});
}, []);
 
return (
<div>
<div ref={ref}>Hello World!</div>
<div
ref={measurer}
style={{
width: MEASURER_SIZE,
position: "fixed",
top: -99999,
}}
/>
</div>
);
};
MyComponent.tsx
tsx
import { useCallback, useEffect, useState, useRef } from "react";
 
const MEASURER_SIZE = 10;
 
export const MyComponent = () => {
const ref = useRef<HTMLDivElement>(null);
const measurer = useRef<HTMLDivElement>(null);
 
const [dimensions, setDimensions] = useState<{
correctedHeight: number;
correctedWidth: number;
} | null>(null);
 
useEffect(() => {
if (!ref.current || !measurer.current) {
return;
}
 
const rect = ref.current.getBoundingClientRect();
const measurerRect = measurer.current.getBoundingClientRect();
const scale = measurerRect.width / MEASURER_SIZE;
 
setDimensions({
correctedHeight: rect.height * scale,
correctedWidth: rect.width * scale,
});
}, []);
 
return (
<div>
<div ref={ref}>Hello World!</div>
<div
ref={measurer}
style={{
width: MEASURER_SIZE,
position: "fixed",
top: -99999,
}}
/>
</div>
);
};

示例项目

v4.0.103 之前的版本

在 Remotion 的早期版本中,由于组件挂载但尚未显示,getBoundingClientRect() 可能会在第一个 useEffect() 中返回所有值为 0 的尺寸。

从现在开始,您可以依赖于尺寸不为零。

另请参阅