拆分JS文件后出现Alpine Expression Error: board未定义求助
Alpine.js 拆分代码后报错:board is not defined
将Tile类迁移至Tile.js、游戏数据从app.js移至game.js后出现标题中的错误,所有JS代码在同一文件时运行正常,拆分后报错,已排除常见语法等简单问题。
错误信息
Alpine Expression Error: board is not defined
Expression: "board"
HTMLTemplateElement{attributes: {…}, innerHTML: "\n <div class="row">\n <template x-for="tile in row">\n <div class="tile" x-text="tile.letter"><…", nodeType: 1, tagName: "template"}
相关代码
index.html
<html> <head> <base href="/" target="_blank" /> <link rel="stylesheet" href="./styles.scss" /> <script src="//unpkg.com/alpinejs" defer></script> <script type="module" src="./app.js"></script> </head> <body> <div id="game" x-data="game" @keyup.window="onKeyPress($event.key)"> <template x-for="row in board"> <div class="row"> <template x-for="tile in row"> <div class="tile" x-text="tile.letter"></div> </template> </div> </template> </div> </body> </html>
app.js
import game from './game'; document.addEventListener('alpine:init', () => { Alpine.data('game', () => game); });
game.js
import Tile from './Tile'; export default { guessesAllowed: 5, wordLength: 5, currentRowIndex: 0, init() { this.board = Array.from({ length: this.guessesAllowed }, () => { return Array.from({ length: this.wordLength }, () => new Tile()); }); }, onKeyPress(key) { if (/^[A-z]$/.test(key)) { this.fillTile(key); } }, fillTile(key) { for (let tile of this.currentRow()) { if (!tile.letter) { tile.fill(key); break; } } if (this.currentTileIndex === this.wordLength - 1) { this.currentRowIndex++; this.currentTileIndex = 0; } else { this.currentTileIndex++; } }, currentRow() { return this.board[this.currentRowIndex]; }, };
Tile.js
export default class Tile { letter = ''; status = ''; // 'correct', 'incorrect', 'empty' fill(key) { this.letter = key.toUpperCase(); this.status = 'filled'; } empty() { this.letter = ''; this.status = 'empty'; } }
问题原因及修复方案
核心原因
- 模板渲染时机早于
board初始化:Alpine.js组件挂载时会立即渲染模板,而board仅在init()方法中赋值,此时模板访问board时该属性还不存在,导致报错。 - 共享实例导致状态异常:直接将导出的game对象传给
Alpine.data,所有组件实例会共享同一个对象,后续操作可能引发不可预期的问题。 - 缺失
currentTileIndex初始值:代码中使用了currentTileIndex但未初始化,后续fillTile方法会报错。
修复步骤
给
board和currentTileIndex添加初始值
修改game.js,在默认导出对象中补充初始属性:export default { guessesAllowed: 5, wordLength: 5, currentRowIndex: 0, currentTileIndex: 0, // 补上缺失的初始值 board: [], // 给board设置初始空数组 // ... 原init及其他方法不变 };改为返回新对象的函数,避免实例共享
修改game.js为导出函数,确保每次调用都生成新的组件状态对象:import Tile from './Tile'; export default () => ({ guessesAllowed: 5, wordLength: 5, currentRowIndex: 0, currentTileIndex: 0, board: [], init() { this.board = Array.from({ length: this.guessesAllowed }, () => { return Array.from({ length: this.wordLength }, () => new Tile()); }); }, onKeyPress(key) { if (/^[A-z]$/.test(key)) { this.fillTile(key); } }, fillTile(key) { for (let tile of this.currentRow()) { if (!tile.letter) { tile.fill(key); break; } } if (this.currentTileIndex === this.wordLength - 1) { this.currentRowIndex++; this.currentTileIndex = 0; } else { this.currentTileIndex++; } }, currentRow() { return this.board[this.currentRowIndex]; }, });调整
app.js的调用(可选,若上面修改game.js为函数则直接用)
若保持game.js为对象,app.js需改为每次返回新对象:import game from './game'; document.addEventListener('alpine:init', () => { Alpine.data('game', () => ({...game})); // 解构生成新对象 });
完成以上修改后,模板渲染时board有初始空数组不会报错,init()执行后会替换为正确的棋盘数据,同时每个组件实例拥有独立状态,功能可正常运行。
内容的提问来源于stack exchange,提问作者jarrodwhitley
相关产品推荐
相关产品推荐

