Vue如何引入含DOMContentLoaded的JS文件并传递组件变量?
在Vue中加载外部JS并传递变量的解决方案
我需要在Vue组件中加载一个外部JS文件,并且向该文件传递变量。这个JS在纯HTML的head标签里引入就能正常运行,但在Vue里尝试动态创建script标签的方式行不通。
目标外部JS代码
document.addEventListener('DOMContentLoaded', () => { const userGrid = document.querySelector('.grid-user') //done const computerGrid = document.querySelector('.grid-computer') //done const displayGrid = document.querySelector('.grid-display') const ships = document.querySelectorAll('.ship') createBoard(userGrid, userSquares) createBoard(computerGrid, computerSquares) function startSinglePlayer() { generate(shipArray[0]) generate(shipArray[1]) generate(shipArray[2]) generate(shipArray[3]) generate(shipArray[4]) startButton.addEventListener('click', () => { setupButtons.style.display = 'none' playGameSingle() }) } //Create Board function createBoard(grid, squares) { for (let i = 0; i < width*width; i++) { const square = document.createElement('div') square.dataset.id = i grid.appendChild(square) squares.push(square) } } // 其他未展示的代码... })
我尝试过的无效写法
mounted() { const plugin = document.createElement("script"); plugin.setAttribute( "src", "//api.myplugincom/widget/mykey.js" ); plugin.async = true; document.head.appendChild(plugin); }
问题原因
原JS依赖DOMContentLoaded事件触发执行,但Vue组件的mounted钩子执行时,页面的DOMContentLoaded事件大概率已经触发完毕,导致外部JS里的代码不会执行。另外,原JS中使用的userSquares、width、shipArray等变量都是全局依赖,在Vue中需要专门处理变量传递。
解决方案
方案一:修改外部JS为模块化可调用形式(推荐)
把原JS改成可接收参数的函数,脱离对DOMContentLoaded的依赖:
// 改写后的外部JS export function initGame(options) { // 解构传入的参数 const { userGrid, computerGrid, displayGrid, ships, userSquares, computerSquares, width, shipArray, startButton, setupButtons } = options; createBoard(userGrid, userSquares); createBoard(computerGrid, computerSquares); function startSinglePlayer() { generate(shipArray[0]); generate(shipArray[1]); generate(shipArray[2]); generate(shipArray[3]); generate(shipArray[4]); startButton.addEventListener('click', () => { setupButtons.style.display = 'none'; playGameSingle(); }); } function createBoard(grid, squares) { for (let i = 0; i < width*width; i++) { const square = document.createElement('div'); square.dataset.id = i; grid.appendChild(square); squares.push(square); } } // 保留原有的其他函数(比如generate、playGameSingle)... // 启动游戏逻辑 startSinglePlayer(); } // 兼容非模块化环境,挂载到window if (typeof window !== 'undefined') { window.initGame = initGame; }
然后在Vue组件中调用:
<template> <div> <div class="grid-user" ref="userGrid"></div> <div class="grid-computer" ref="computerGrid"></div> <div class="grid-display" ref="displayGrid"></div> <div class="ship" ref="ships"></div> <button ref="startButton">开始游戏</button> <div ref="setupButtons">设置区域</div> </div> </template> <script> // 如果是本地JS文件,直接导入 import { initGame } from './path/to/your/game.js'; export default { data() { return { width: 10, // 游戏棋盘宽度,根据实际需求设置 userSquares: [], computerSquares: [], shipArray: [/* 你的船型数据数组 */] }; }, mounted() { // 调用外部JS的初始化函数,传入所需参数 initGame({ userGrid: this.$refs.userGrid, computerGrid: this.$refs.computerGrid, displayGrid: this.$refs.displayGrid, ships: this.$refs.ships, userSquares: this.userSquares, computerSquares: this.computerSquares, width: this.width, shipArray: this.shipArray, startButton: this.$refs.startButton, setupButtons: this.$refs.setupButtons }); // 如果是CDN加载的外部JS,改用以下方式: // const script = document.createElement('script'); // script.src = '//api.myplugincom/widget/mykey.js'; // script.onload = () => { // window.initGame({ /* 传入上述参数 */ }); // }; // document.head.appendChild(script); } }; </script>
方案二:不修改外部JS,适配Vue生命周期(仅适用于无法修改外部JS的场景)
通过挂载全局变量、确保脚本加载时机来适配:
<script> export default { data() { return { width: 10, userSquares: [], computerSquares: [], shipArray: [/* 你的数据 */] }; }, mounted() { // 先把依赖的变量挂载到window全局,供外部JS读取 window.width = this.width; window.userSquares = this.userSquares; window.computerSquares = this.computerSquares; window.shipArray = this.shipArray; // 创建script标签加载外部JS const script = document.createElement('script'); script.src = '//api.myplugincom/widget/mykey.js'; // 脚本加载完成后,若DOMContentLoaded已触发,手动执行核心逻辑 script.onload = () => { // 这里需要知道外部JS里的核心函数名,比如如果原逻辑是在一个匿名函数里,可能需要手动模拟触发 // 例如,如果原JS的核心逻辑是绑定在DOMContentLoaded上的,可尝试重新执行该逻辑 // 注意:这种方式可靠性较低,容易出问题 }; document.head.appendChild(script); } }; </script>
注意事项
- 优先选择方案一,模块化的方式更符合Vue的开发规范,避免全局变量污染,参数传递更清晰
- 方案二依赖全局变量,容易引发命名冲突,仅作为无法修改外部JS时的妥协方案
- 无论哪种方案,都要确保Vue组件中的DOM元素已经渲染完成(
mounted钩子满足这个条件),避免外部JS找不到DOM节点
内容的提问来源于stack exchange,提问作者Seira
相关产品推荐
相关产品推荐

