You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用Alpine.js结合异步Fetch更新表格行数据的问题

Alpine.js结合异步Fetch更新表格行数据的问题

问题背景

每个表格行都有一个单元格,里面的“重量级”数据是按需加载的;加载前显示"?"。点击该行的按钮后,单元格会被填充数据。

用户最初尝试的代码如下:

<table>
  <tbody>

    <!-- rows 1..10  -->

    <tr x-data="{ foo: '?' }">
      <td><span x-text="foo"></span></td>
      <!-- ... -->
      <td><button onclick="foo = await fetchFoo('row-11')">Load</button></td>
    </tr>

    <!-- rows 12... -->

  </tbody>
</table>

<script>
  async function fetchFoo(rowId) {
    let url      = `https://www.example.com/foo/${rowId}`;
    let response = await fetch(url);
    let result   = await response.text();
    return result;
  }
</script>

但用户遇到了问题:无法将获取到的数据从按钮传递到单元格中,尝试多种语法都不生效,对应的演示代码如下:

<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.8/dist/cdn.min.js" defer></script>

<table>
  <tbody>
    <tr x-data="{ foo: '?' }">
      <td>Hello</td>
      <td><span x-text="foo"></span></td>
      <td><button onclick="foo = await fetchFoo('row-1')">Load</button></td>
    </tr>
    <tr x-data="{ foo: '?' }">
      <td>World</td>
      <td><span x-text="foo"></span></td>
      <td><button onclick="async () => { foo = await fetchFoo('row-2') }">Load</button></td>
    </tr>
    <tr x-data="{ foo: '?' }">
      <td>Hi</td>
      <td><span x-text="foo"></span></td>
      <td><button onclick="fetchFoo('row-3')">Load</button></td>
    </tr>
    <!-- rows 4+... -->
  </tbody>
</table>

<script>
  async function fetchFoo(rowIndex) {
    return new Promise(resolve => setTimeout(() => resolve(rowIndex), 1000));
  }
</script>

问题分析

咱们逐个看看你尝试的写法哪里出了问题:

  • 第一个按钮:onclick="foo = await fetchFoo('row-1')" —— 原生onclick的回调不是异步函数,直接用await会抛出语法错误,因为await只能在async函数内部使用。
  • 第二个按钮:onclick="async () => { foo = await fetchFoo('row-2') }" —— 这里你定义了一个异步箭头函数,但没有执行它,所以点击按钮后完全不会触发任何逻辑。
  • 第三个按钮:onclick="fetchFoo('row-3')" —— 虽然调用了异步函数,但没有处理它的返回值,也没有把结果赋值给foo,所以单元格不会更新。

另外还有个关键问题:原生onclick的作用域和Alpine.js的组件作用域(这里是<tr>x-data)不一定能正确关联,直接访问foo可能会出现foo is not defined的错误,最好用Alpine提供的指令来处理事件。

解决方案

推荐使用Alpine.js的@click指令(替代原生onclick),它能完美适配Alpine的组件作用域,并且支持异步逻辑。下面是两种可行的写法:

写法一:直接在@click里处理异步逻辑

把异步逻辑直接写在@click指令中,Alpine会自动处理async/await

<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.8/dist/cdn.min.js" defer></script>

<table>
  <tbody>
    <tr x-data="{ foo: '?' }">
      <td>Hello</td>
      <td><span x-text="foo"></span></td>
      <td><button @click="foo = await fetchFoo('row-1')">Load</button></td>
    </tr>
    <tr x-data="{ foo: '?' }">
      <td>World</td>
      <td><span x-text="foo"></span></td>
      <td><button @click="(async () => { foo = await fetchFoo('row-2') })()">Load</button></td>
    </tr>
    <tr x-data="{ foo: '?' }">
      <td>Hi</td>
      <td><span x-text="foo"></span></td>
      <td><button @click="fetchFoo('row-3').then(res => foo = res)">Load</button></td>
    </tr>
  </tbody>
</table>

<script>
  async function fetchFoo(rowIndex) {
    return new Promise(resolve => setTimeout(() => resolve(rowIndex), 1000));
  }
</script>

写法二:把逻辑封装到x-data的方法里(更推荐)

把加载逻辑作为x-data的一部分,代码更模块化、易维护:

<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.8/dist/cdn.min.js" defer></script>

<table>
  <tbody>
    <tr x-data="{ 
      foo: '?',
      async loadFoo(rowId) {
        this.foo = await fetchFoo(rowId);
      }
    }">
      <td>Hello</td>
      <td><span x-text="foo"></span></td>
      <td><button @click="loadFoo('row-1')">Load</button></td>
    </tr>
    <tr x-data="{ 
      foo: '?',
      async loadFoo(rowId) {
        this.foo = await fetchFoo(rowId);
      }
    }">
      <td>World</td>
      <td><span x-text="foo"></span></td>
      <td><button @click="loadFoo('row-2')">Load</button></td>
    </tr>
  </tbody>
</table>

<script>
  async function fetchFoo(rowIndex) {
    return new Promise(resolve => setTimeout(() => resolve(rowIndex), 1000));
  }
</script>

关键要点总结

  • 优先使用Alpine的@click指令而不是原生onclick,确保能正确访问组件作用域内的变量。
  • 处理异步逻辑时,要么在@click里直接用await(Alpine原生支持),要么用.then()处理Promise返回值。
  • 逻辑复杂时,推荐把方法封装到x-data中,让代码结构更清晰。

备注:内容来源于stack exchange,提问作者lonix

火山引擎 最新活动