如何在Vue项目中导入自定义鼠标轨迹模块并解决报错问题
在Vue项目中引入自定义鼠标轨迹脚本
mouseTrail.js的解决方法 问题描述
我编写了一个实现自定义鼠标轨迹的mouseTrail.js文件,在普通HTML项目中,会通过以下代码在标签末尾引入:
<script src="./mouseTrail.js" type="module"></script>
但在Vue项目中采用同样方式引入时会报错,求解决办法。
报错信息
目标环境不支持动态import()语法,因此无法在script标签中使用外部'module'类型
mouseTrail.js关键代码
import { Polyline, Renderer, Transform, Geometry, Program, Mesh, Vec3, Vec2, Color } from 'https://cdn.jsdelivr.net/npm/ogl@0.0.25/dist/ogl.mjs'; const vertex = ` attribute vec3 position; attribute vec3 next; attribute vec3 prev; attribute vec2 uv; attribute float side; uniform vec2 uResolution; uniform float uDPR; uniform float uThickness; vec4 getPosition() { vec2 aspect = vec2(uResolution.x / uResolution.y, 1); vec2 nextScreen = next.xy * aspect; vec2 prevScreen = prev.xy * aspect; vec2 tangent = normalize(nextScreen - prevScreen); vec2 normal = vec2(-tangent.y, tangent.x); normal /= aspect; normal *= 1.0 - pow(abs(uv.y - 0.5) * 1.9, 2.0); float pixelWidth = 1.0 / (uResolution.y / uDPR); normal *= pixelWidth * uThickness; float dist = length(nextScreen - prevScreen); normal *= smoothstep(0.0, 0.02, dist); vec4 current = vec4(position, 1); current.xy -= normal * side; return current; } void main() { gl_Position = getPosition(); } `
解决方案
1. 放弃直接用type="module"引入脚本
Vue的构建环境(Vite/Webpack)本身会处理模块导入,不需要在script标签里指定type="module"。如果要保留原脚本文件,可将其放入项目public目录,然后在index.html中这样引入:
<script src="./mouseTrail.js"></script>
但这种方式仍可能因脚本内的CDNimport语句报错,更推荐下面两种封装方式。
2. 封装为Vue组件(推荐)
创建MouseTrail.vue组件,将轨迹逻辑整合到Vue生命周期中:
<template> <div ref="trailContainer"></div> </template> <script setup> import { onMounted, onUnmounted, ref } from 'vue'; import { Polyline, Renderer, Transform, Geometry, Program, Mesh, Vec3, Vec2, Color } from 'ogl'; const trailContainer = ref(null); let renderer, scene; // 复用原vertex shader代码 const vertex = ` attribute vec3 position; attribute vec3 next; attribute vec3 prev; attribute vec2 uv; attribute float side; uniform vec2 uResolution; uniform float uDPR; uniform float uThickness; vec4 getPosition() { vec2 aspect = vec2(uResolution.x / uResolution.y, 1); vec2 nextScreen = next.xy * aspect; vec2 prevScreen = prev.xy * aspect; vec2 tangent = normalize(nextScreen - prevScreen); vec2 normal = vec2(-tangent.y, tangent.x); normal /= aspect; normal *= 1.0 - pow(abs(uv.y - 0.5) * 1.9, 2.0); float pixelWidth = 1.0 / (uResolution.y / uDPR); normal *= pixelWidth * uThickness; float dist = length(nextScreen - prevScreen); normal *= smoothstep(0.0, 0.02, dist); vec4 current = vec4(position, 1); current.xy -= normal * side; return current; } void main() { gl_Position = getPosition(); } `; // 初始化鼠标轨迹 const initTrail = () => { renderer = new Renderer({ dpr: window.devicePixelRatio }); const gl = renderer.gl; trailContainer.value.appendChild(gl.canvas); scene = new Transform(); // 补充原mouseTrail.js中剩余的轨迹初始化、鼠标事件监听逻辑 // ... }; // 组件挂载后初始化 onMounted(() => { initTrail(); // 监听窗口大小变化 const handleResize = () => { renderer.setSize(trailContainer.value.clientWidth, trailContainer.value.clientHeight); // 补充resize时的轨迹调整逻辑 }; window.addEventListener('resize', handleResize); // 组件销毁时移除监听 onUnmounted(() => { window.removeEventListener('resize', handleResize); renderer.dispose(); }); }); </script> <style scoped> div { width: 100vw; height: 100vh; position: fixed; top: 0; left: 0; pointer-events: none; /* 避免遮挡页面交互 */ } </style>
之后在根组件App.vue中引入使用:
<template> <MouseTrail /> <!-- 其他页面内容 --> </template> <script setup> import MouseTrail from './components/MouseTrail.vue'; </script>
3. 在入口文件main.js中初始化
若不想封装组件,可在项目入口文件中初始化,确保DOM挂载完成后执行:
import { createApp } from 'vue'; import App from './App.vue'; import { Polyline, Renderer, Transform, Geometry, Program, Mesh, Vec3, Vec2, Color } from 'ogl'; const app = createApp(App); app.mount('#app'); // 等待DOM挂载完成后初始化轨迹 setTimeout(() => { const renderer = new Renderer({ dpr: window.devicePixelRatio }); const gl = renderer.gl; document.body.appendChild(gl.canvas); // 补充原mouseTrail.js中的轨迹逻辑 // ... }, 100);
4. 安装ogl本地依赖
原脚本通过CDN导入ogl,在Vue项目中更推荐通过npm安装依赖,便于构建工具处理:
npm install ogl --save
安装后即可直接通过import引入ogl模块,无需依赖CDN链接。
内容的提问来源于stack exchange,提问作者Eduardo Garcia
相关产品推荐
相关产品推荐

