寻求实现鼠标拖拽文字跟随效果的代码解决方案
实现鼠标拖拽文字的动态跟随效果
需要实现的效果:鼠标移动时,文字字符依次跟随鼠标,呈现连贯的拖拽牵引感,字符间带有自然延迟,形成类似拖尾的动态效果。我尝试用paper.js实现但未达到预期,请求编写能实现该效果的代码片段,不限使用任何库。
以下是我尝试的代码:
我的尝试代码
HTML
<!DOCTYPE html> <html> <head> <script src="https://unpkg.com/paper"></script> </head> <body> <div class="custom-cursor"></div> <canvas id="myCanvas"></canvas> </body> </html>
CSS
html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; } #myCanvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } .custom-cursor { position: absolute; top: -3px; left: -3px; width: 7px; height: 7px; border: 2px solid black; border-radius: 50%; background-color: transparent; pointer-events: none; z-index: 9999; }
JavaScript
// Setup Paper.js paper.setup('myCanvas'); var word = 'Hello, World!'; var characters = []; var offsetX = 0; var offsetY = 0; var characterSpacing = 20; var chasingSpeed = 0.9; var delayIncrement = 100; for (var i = 0; i < word.length; i++) { var character = new paper.PointText({ content: word[i], fillColor: 'black', fontFamily: 'Arial, sans-serif', fontWeight: 'bold', fontSize: 24, justification: 'center' }); character.targetPosition = new paper.Point(0, 0); character.position = new paper.Point(0, 0); character.delay = i * delayIncrement; characters.push(character); } function onMouseMove(event) { var mousePosition = event.point; var cursor = document.querySelector('.custom-cursor'); cursor.style.top = mousePosition.y - cursor.offsetHeight / 2 + 'px'; cursor.style.left = mousePosition.x - cursor.offsetWidth / 2 + 'px'; // 注释的线性跟随逻辑 // for (var i = 0; i < characters.length; i++) { // var character = characters[i]; // var targetPosition = mousePosition.add(new paper.Point(i * characterSpacing + 20, 0)); // setTimeout(function(char, targetPos) { // char.targetPosition = targetPos; // }, character.delay, character, targetPosition); // } var wordLength = word.length; var totalWidth = wordLength * characterSpacing; var angleIncrement = Math.PI * 2 / totalWidth; var initialAngle = Math.atan2(mousePosition.y, mousePosition.x) - Math.PI / 2; for (var i = 0; i < characters.length; i++) { var character = characters[i]; var angle = initialAngle + angleIncrement * i; var radius = totalWidth / (2 * Math.PI); var targetX = mousePosition.x + Math.cos(angle) * radius; var targetY = mousePosition.y + Math.sin(angle) * radius; setTimeout(function(char, posX, posY) { char.targetPosition = new paper.Point(posX, posY); }, character.delay, character, targetX, targetY); } } function onFrame(event) { for (var i = 0; i < characters.length; i++) { var character = characters[i]; var distance = character.targetPosition.subtract(character.position); character.position = character.position.add(distance.multiply(chasingSpeed)); } } paper.view.onMouseMove = onMouseMove; paper.view.onFrame = onFrame; paper.view.onResize = function(event) { paper.view.viewSize = new paper.Size(window.innerWidth, window.innerHeight); } paper.view.draw();
修正后的实现代码
以下是能实现目标拖拽效果的代码,核心调整了字符跟随逻辑,优化了缓动参数与延迟机制:
HTML
<!DOCTYPE html> <html> <head> <script src="https://unpkg.com/paper"></script> </head> <body> <div class="custom-cursor"></div> <canvas id="myCanvas"></canvas> </body> </html>
CSS
html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; cursor: none; } #myCanvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } .custom-cursor { position: absolute; width: 8px; height: 8px; border: 2px solid #000; border-radius: 50%; background-color: transparent; pointer-events: none; z-index: 9999; transition: transform 0.05s ease; }
JavaScript
paper.setup('myCanvas'); const text = 'Hello, World!'; const chars = []; const charSpacing = 24; const followSpeed = 0.15; const delayStep = 60; // 初始化字符 text.split('').forEach((char, index) => { const pointText = new paper.PointText({ content: char, fillColor: '#000', fontFamily: 'Helvetica Neue, Arial, sans-serif', fontWeight: '600', fontSize: 28, justification: 'center' }); pointText.target = new paper.Point(window.innerWidth/2, window.innerHeight/2); pointText.position = pointText.target.clone(); pointText.delay = index * delayStep; chars.push(pointText); }); // 处理鼠标移动 let mousePos = new paper.Point(window.innerWidth/2, window.innerHeight/2); const cursor = document.querySelector('.custom-cursor'); paper.view.onMouseMove = (event) => { mousePos = event.point; // 更新自定义光标位置 cursor.style.top = `${mousePos.y - cursor.offsetHeight/2}px`; cursor.style.left = `${mousePos.x - cursor.offsetWidth/2}px`; // 为每个字符设置目标位置,带延迟 chars.forEach((char, index) => { const targetX = mousePos.x + (index - chars.length/2) * charSpacing; const targetY = mousePos.y; setTimeout(() => { char.target = new paper.Point(targetX, targetY); }, char.delay); }); }; // 每一帧更新字符位置 paper.view.onFrame = () => { chars.forEach(char => { const diff = char.target.subtract(char.position); char.position = char.position.add(diff.multiply(followSpeed)); }); }; // 窗口大小调整 paper.view.onResize = (event) => { paper.view.viewSize = new paper.Size(event.size.width, event.size.height); }; paper.view.draw();
关键改动说明
- 跟随逻辑优化:字符在鼠标水平方向居中排列,跟随鼠标移动时保持整体行状结构
- 缓动参数调整:降低
followSpeed让字符移动更顺滑,避免生硬跳动 - 延迟机制简化:按字符顺序设置递增延迟,形成自然的拖尾效果
- 光标体验提升:隐藏默认光标,让自定义光标更突出
- 初始位置优化:将字符初始位置设置在屏幕中心,提升首次加载体验
内容的提问来源于stack exchange,提问作者Amir Nejatbakhsh
相关产品推荐
相关产品推荐

