惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Apple Machine Learning Research
Apple Machine Learning Research
J
Java Code Geeks
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Last Week in AI
Last Week in AI
雷峰网
雷峰网
博客园_首页
小众软件
小众软件
美团技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
腾讯CDC
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog
Google DeepMind News
Google DeepMind News
MyScale Blog
MyScale Blog
U
Unit 42
The Cloudflare Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Security Blog
Microsoft Security Blog
大猫的无限游戏
大猫的无限游戏
Engineering at Meta
Engineering at Meta
N
Netflix TechBlog - Medium
Microsoft Azure Blog
Microsoft Azure Blog
博客园 - 叶小钗

博客园 - Zion0707

Codex接入DeepSeek token实现对话与操作,so easy! Openclaw只能聊天不能操作解决方案 Ubuntu从零搭建Openclaw Openclaw安装问题记录 React数字滚动,增加或减少效果 前端实现图片文字识别并提取 ECharts实现两条曲线数据比较,数据高出区域高亮显示 canvas实现视频播放并支持自动播放 fabricjs实现虚线流动动画效果 React国际化方案及示例 fabricjs如何导入echarts fabricjs元素对齐方式实现 萤石云视频监控和回放方案 React仿photoshop参考线功能 react-router-dom v6 使用 “DatePicker”不能用作 JSX 组件。 Element plus的tree组件实现单选和搜索功能 16进制相关操作方法 js 版 AES-128 算法加解密 js 版 React 下拉多选,全选/全不选功能组件
react hooks实现对元素拖拽及鼠标滚轮缩放
Zion0707 · 2024-07-11 · via 博客园 - Zion0707

hooks.js

import { useCallback, useState } from 'react';

// 拖拽
export function useDrag() {
    const [isDragging, setIsDragging] = useState(false);
    const [initialPosition, setInitialPosition] = useState({ x: 0, y: 0 });
    const [initialMousePosition, setInitialMousePosition] = useState({ x: 0, y: 0 });

    const handleMouseDown = useCallback((e) => {
        setIsDragging(true);
        setInitialMousePosition({ x: e.clientX, y: e.clientY });
        setInitialPosition({ x: e.currentTarget.offsetLeft, y: e.currentTarget.offsetTop });
    }, []);

    const handleMouseMove = useCallback(
        (e) => {
            if (isDragging) {
                const dx = e.clientX - initialMousePosition.x;
                const dy = e.clientY - initialMousePosition.y;
                e.currentTarget.style.left = `${initialPosition.x + dx}px`;
                e.currentTarget.style.top = `${initialPosition.y + dy}px`;
            }
        },
        [isDragging, initialMousePosition, initialPosition]
    );

    const handleMouseUp = useCallback(() => {
        setIsDragging(false);
    }, []);

    return {
        handleMouseDown,
        handleMouseMove,
        handleMouseUp,
    };
}

// 缩放
export function useZoom(initialScale = 1) {
    const [scale, setScale] = useState(initialScale);

    const handleWheel = useCallback(
        (e) => {
            if (e.deltaY !== 0) {
                const newScale = scale + (e.deltaY > 0 ? -0.05 : 0.05);
                setScale(newScale < 0.5 ? 0.5 : newScale); // 防止缩放过小
                e.currentTarget.style.transform = `scale(${newScale})`;
            }
        },
        [scale]
    );

    return {
        handleWheel,
        scale,
    };
}

page.jsx

import './index.less';

import { useDrag, useZoom } from './hooks';

const DragZoom = () => {
    const { handleMouseDown, handleMouseMove, handleMouseUp } = useDrag();
    const { handleWheel, scale } = useZoom();

    return (
        <div className="drag-zoom">
            <div className="area">
                <div
                    onMouseDown={handleMouseDown}
                    onMouseMove={handleMouseMove}
                    onMouseUp={handleMouseUp}
                    onWheel={handleWheel}
                    className="element"
                    style={{
                        transform: `scale(${scale})`,
                    }}
                />
            </div>
        </div>
    );
};

export default DragZoom;

index.less

.drag-zoom {
    width: 100vw;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    .area {
        width: 500px;
        height: 500px;
        border: 1px solid #ddd;
        position: relative;
        overflow: hidden;
        .react-draggable {
            border: 1px solid goldenrod;
        }
        .element {
            position: absolute;
            width: 100px;
            height: 100px;
            cursor: grab;
            transition: transform 0.3s ease;
            background: paleturquoise;
        }
    }
}