首页网文心情网络杂谈文字随意拖动效果 使用 Matter.js 物理引擎实现的文字拖动效果

文字随意拖动效果 使用 Matter.js 物理引擎实现的文字拖动效果

分类网络杂谈时间2026-08-23 21:52:05发布heikeyh浏览31
导读:使用 Matter.js 物理引擎实现的文字拖动效果,每个文字都可以自由拖动并带有物理碰撞。这是一个有趣的物理文字效果。使用 Matter.js 2D 物理引擎,将每个文字变成可拖动的物理实体,具有重力、碰撞和边界约束。你可以随意拖动文字,松开后会自然下落并与其他文字碰撞。核心特性物理引擎:使用 Matter.js 实现真实物理效果自由拖动:鼠标拖动文字,松...

使用 Matter.js 物理引擎实现的文字拖动效果,每个文字都可以自由拖动并带有物理碰撞。

这是一个有趣的物理文字效果。使用 Matter.js 2D 物理引擎,将每个文字变成可拖动的物理实体,

具有重力、碰撞和边界约束。你可以随意拖动文字,松开后会自然下落并与其他文字碰撞。

核心特性

物理引擎:使用 Matter.js 实现真实物理效果

自由拖动:鼠标拖动文字,松开后自然下落

碰撞效果:文字之间会产生物理碰撞

边界约束:文字不会飞出视窗

完整代码

效果图:

9dfdb892-5e3f-4a52-b5f8-e279bdbf8d6c.png

---由于布局原因页面无法全部显示,自行复制代码测试


以下是完整的单文件代码,你可以直接保存为 .html 文件运行:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>文字拖动效果</title>
  <link href="https://fonts.googleapis.com/css2?family=ZCOOL+XiaoWei&display=swap" rel="stylesheet">
  <style>
    body {
      margin: 0;
      padding: 0;
      background: #1a1a2e;
      color: transparent;
      font-family: 'ZCOOL XiaoWei', serif;
      width: 100vw;
      height: 100vh;
      overflow: hidden;
    }
    * {
      user-select: none;
    }
    .word {
      position: absolute;
      cursor: grab;
      font-size: 30px;
      color: #ffeb3b;
    }
    .word:active {
      cursor: grabbing;
    }
  </style>
</head>
<body>
  <main>
    <div>丙辰中秋,欢饮达旦,大醉,作此篇,兼怀子由。明月几时有,把酒问青天。...</div>
  </main>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>
  <script>
    // 拆分文字
    const splitWords = () => {
      const textNode = document.querySelector(".text");
      const text = textNode.textContent;
      const newDomElements = text.split("").map((char) => {
        return `<span>${char === ' ' ? '&nbsp;' : char}</span>`;
      });
      textNode.innerHTML = newDomElements.join("");
    };

    // 渲染画布
    const renderCanvas = () => {
      const Engine = Matter.Engine;
      const Render = Matter.Render;
      const World = Matter.World;
      const Bodies = Matter.Bodies;
      const Runner = Matter.Runner;

      const canvasSize = {
        width: window.innerWidth,
        height: window.innerHeight
      };

      const engine = Engine.create({});

      const render = Render.create({
        element: document.body,
        engine: engine,
        options: {
          ...canvasSize,
          background: "#1a1a2e",
          wireframes: false
        }
      });

      // 边界
      const wallOptions = {
        isStatic: true,
        render: { fillStyle: "transparent" }
      };
      const floor = Bodies.rectangle(
        canvasSize.width / 2,
        canvasSize.height,
        canvasSize.width,
        50,
        wallOptions
      );
      const wall1 = Bodies.rectangle(0, canvasSize.height / 2, 50, canvasSize.height, wallOptions);
      const wall2 = Bodies.rectangle(canvasSize.width, canvasSize.height / 2, 50, canvasSize.height, wallOptions);
      const top = Bodies.rectangle(canvasSize.width / 2, 0, canvasSize.width, 50, wallOptions);

      // 创建文字物理实体
      const wordElements = document.querySelectorAll(".word");
      const wordBodies = [...wordElements].map((elemRef) => {
        const width = elemRef.offsetWidth || 30;
        const height = elemRef.offsetHeight || 30;

        return {
          body: Matter.Bodies.rectangle(
            Math.random() * (canvasSize.width - 100) + 50,
            Math.random() * 200,
            width,
            height,
            {
              render: { fillStyle: "transparent" }
            }
          ),
          elem: elemRef,
          render() {
            const { x, y } = this.body.position;
            this.elem.style.top = `${y - height / 2}px`;
            this.elem.style.left = `${x - width / 2}px`;
            this.elem.style.transform = `rotate(${this.body.angle}rad)`;
          }
        };
      });

      // 鼠标控制
      const mouse = Matter.Mouse.create(document.body);
      const mouseConstraint = Matter.MouseConstraint.create(engine, {
        mouse,
        constraint: {
          stiffness: 0.2,
          render: { visible: false }
        }
      });

      // 移除鼠标滚轮事件
      mouse.element.removeEventListener("mousewheel", mouse.mousewheel);
      mouse.element.removeEventListener("DOMMouseScroll", mouse.mousewheel);

      World.add(engine.world, [
        floor, wall1, wall2, top,
        ...wordBodies.map((box) => box.body),
        mouseConstraint
      ]);

      render.mouse = mouse;
      Runner.run(engine);
      Render.run(render);

      // 循环更新
      (function rerender() {
        wordBodies.forEach((element) => {
          element.render();
        });
        Matter.Engine.update(engine);
        requestAnimationFrame(rerender);
      })();
    };

    window.addEventListener("DOMContentLoaded", () => {
      splitWords();
      renderCanvas();
    });
  </script>
</body>
</html>


Hackyh'Blog版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

网络杂谈网络技术
最新 Windows10/11可用激活码 附使用方法 网页特效 CSS + JavaScript 实现管状数码时钟

游客 回复需填写必要信息
召唤伊斯特瓦尔