返回
如何旋转父元素时同步旋转子元素?
javascript
2024-04-01 04:36:04
旋转父元素时如何旋转子元素
问题
有时我们需要让父元素及其所有子元素一起旋转,即使子元素没有附加到父元素中,并且它们相对于父元素的位置是固定的。旋转时,它们与父元素左侧和顶部位置 (x, y) 的距离和角度应该保持不变。
解决方法
要实现这一效果,需要使用 JavaScript 和 CSS 中的变换属性。具体步骤如下:
- 获取鼠标角度: 当用户按下鼠标按钮并开始拖动时,计算鼠标相对于父元素中心点的角度。
- 获取父元素的初始旋转: 使用 CSS 的 getComputedStyle() 方法,获取父元素初始旋转角度。
- 计算旋转增量: 监听鼠标移动事件,不断计算当前鼠标角度和初始鼠标角度之间的增量。
- 应用旋转: 使用 CSS 的 transform 属性,将旋转增量应用于父元素。
- 计算子元素的新位置: 对于每个子元素,根据初始距离和旋转增量计算其相对于父元素中心的新位置。
- 应用子元素旋转: 使用 CSS 的 transform 属性,将父元素的旋转角度应用于每个子元素。
- 更新子元素位置: 将计算的新位置应用于子元素,使其在旋转的同时保持相对于父元素的位置。
代码示例
// 获取元素
const parentElement = document.getElementById("parentElement");
const childElements = document.querySelectorAll(".childElement");
// 鼠标拖动相关变量
let isDragging = false;
let initialMouseAngle = 0;
let initialRotation = 0;
let initialDistance = {};
// 获取鼠标相对于父元素中心点的角度
const getMouseAngle = (e) => {
const rect = parentElement.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const mouseX = e.clientX - centerX;
const mouseY = e.clientY - centerY;
return Math.atan2(mouseY, mouseX) * (180 / Math.PI);
};
// 获取父元素的初始旋转角度
const getRotationDegrees = () => {
const transformValue = window.getComputedStyle(parentElement).getPropertyValue("transform");
const matrix = new DOMMatrixReadOnly(transformValue);
return Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
};
// 鼠标按下开始拖动
const startDrag = (e) => {
isDragging = true;
initialMouseAngle = getMouseAngle(e);
initialRotation = getRotationDegrees();
childElements.forEach(child => {
const parentRect = parentElement.getBoundingClientRect();
const childRect = child.getBoundingClientRect();
initialDistance[child.id] = Math.hypot(childRect.left - parentRect.left, childRect.top - parentRect.top);
});
};
// 鼠标移动处理
const handleDrag = (e) => {
if (isDragging) {
const currentMouseAngle = getMouseAngle(e);
const rotationChange = currentMouseAngle - initialMouseAngle;
const newRotation = initialRotation + rotationChange;
const parentRect = parentElement.getBoundingClientRect();
const angleInRadians = newRotation * (Math.PI / 180);
// 应用旋转给父元素
parentElement.style.transform = `rotate(${newRotation}deg)`;
// 计算子元素新位置并应用旋转
childElements.forEach(child => {
const distance = initialDistance[child.id];
const newX = parentRect.left + distance * Math.cos(angleInRadians);
const newY = parentRect.top + distance * Math.sin(angleInRadians);
child.style.left = `${newX}px`;
child.style.top = `${newY}px`;
child.style.transform = `rotate(${newRotation}deg)`;
});
}
};
// 鼠标释放结束拖动
const stopDrag = () => {
isDragging = false;
};
// 事件监听
document.addEventListener("mousedown", startDrag);
document.addEventListener("mouseup", stopDrag);
document.addEventListener("mousemove", handleDrag);
常见问题解答
1. 如何让子元素保持相对于父元素的相对位置?
通过计算每个子元素相对于父元素中心点的初始距离,并使用此距离来计算子元素在旋转后的新位置。
2. 如何将旋转应用于子元素?
通过将父元素的旋转角度应用于每个子元素的 transform 属性。
3. 如何处理多个子元素?
上面的代码中使用了一个循环来遍历所有的子元素,并根据其 ID 计算每个子元素的初始距离。
4. 如何将子元素拖出父元素范围?
由于子元素相对于父元素的距离保持不变,因此它们无法拖出父元素范围。
5. 如何应用额外的变换效果?
可以根据需要添加额外的变换效果,例如平移或缩放,通过修改 childElement.style.transform 属性。