如何在AlpineJS模块中使用JS类解决Todo实例复用问题
AlpineJS 结合 Todo 模块的实例复用问题解决
问题背景
使用函数式 Todo 模块结合 AlpineJS 时,添加多个待办项会出现所有条目同步更新的问题;改用类模块时,又无法正常运行,具体问题如下:
类导出的问题
- 直接使用
Alpine.data('todo', Todo)时,报错:Uncaught TypeError: Class constructor default cannot be invoked without 'new' - 尝试
x-data="new todo()"时,报错:todo is not a constructor - 尝试
Alpine.data('todo', new Todo());时,报错:Uncaught TypeError: callback.bind is not a function
函数导出的问题
- 仅推入
item.name能生成独立条目,但业务需要完整的待办对象 - 使用
structuredClone(item)推入时,报错:Uncaught DOMException: Failed to execute 'structuredClone' on 'Window': # could not be cloned.
解决方案
方案一:修复函数式模块的实例复用问题
核心问题是每次推入的都是同一个 item 对象引用,需在提交时创建新对象副本,避免引用复用。
- 修改
todo.js的函数导出:
export default () => ({ item: { name: '', completed: false }, // 新增创建新待办项的方法 createNewTodo() { // 复制当前item属性到新对象,切断引用 const newTodo = { ...this.item }; // 重置输入框内容 this.item.name = ''; return newTodo; } });
- 修改 HTML 中的提交逻辑:
<article x-data="{ todos: [] }"> <form x-data="todo" @submit.prevent="todos.push(createNewTodo())"> <input x-model="item.name"><button>Add</button> </form> <ul> <template x-for="todo in todos" :key="todo"> <li x-text="todo.name"></li> </template> </ul> </article>
方案二:修复类模块的使用方式
AlpineJS 的 Alpine.data 要求接收一个返回对象的函数,而非直接传入类或类实例,需调整类的注册方式。
- 修改
todo.js的类导出:
export default class Todo { constructor() { // 初始化空的待办项模板 this.item = { name: '', completed: false }; } createNewTodo() { const newTodo = { ...this.item }; this.item.name = ''; return newTodo; } }
- 修改 Alpine 的注册逻辑:
<script type="module"> import Alpine from './modules/alpine.js'; import Todo from './modules/todo.js'; // 用函数包裹类,确保每次x-data调用都生成新的类实例 Alpine.data('todo', () => new Todo()); Alpine.start(); </script>
- HTML 部分与方案一的提交逻辑一致:
<article x-data="{ todos: [] }"> <form x-data="todo" @submit.prevent="todos.push(createNewTodo())"> <input x-model="item.name"><button>Add</button> </form> <ul> <template x-for="todo in todos" :key="todo"> <li x-text="todo.name"></li> </template> </ul> </article>
关键说明
- 函数式方案中,使用对象扩展运算符
{ ...this.item }创建副本,彻底切断原对象的引用关系; - 类方案中,
Alpine.data必须传入返回类实例的函数,保证每个x-data="todo"都生成独立的类实例; - 两种方案都需在提交后重置输入框的
item.name,避免下一次输入影响已添加的条目。
内容的提问来源于 stack exchange,提问作者 Simon Ferndriger
相关产品推荐
相关产品推荐

