You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue跨组件数据与方法调用:非父子组件表格行删除方案

其实你的form-row组件和根组件(thead所在的组件)是父子关系哦,根组件直接使用了form-row,所以我们可以直接利用Vue的父子组件事件传递来实现删除功能,这是最直接的方案。如果真的遇到完全无关联的非父子组件场景,也可以用事件总线来解决,下面分别给你两种方案的实现:


方案一:利用父子组件事件传递(最适配你的场景)

步骤1:修改form-row组件的删除逻辑

首先注意:delete是JavaScript的关键字,不能作为方法名,我们改成handleDelete;然后给组件新增一个index属性接收当前行的索引,点击删除按钮时触发自定义事件把索引传递给父组件:

Vue.component("form-row", {
  template: "#row-template",
  props: {
    itemname: String,
    quantity: Number,
    sellingprice: Number,
    amount: Number,
    index: Number // 新增:接收当前行的索引
  },
  methods: {
    handleDelete() {
      // 触发自定义事件,把当前行索引传给父组件
      this.$emit("delete-row", this.index);
    }
  },
  // 原有计算属性保持不变
  computed: {
    quantitySynced: {
      get() { return this.quantity; },
      set(v) { this.$emit("update:quantity", +v); }
    },
    sellingpriceSynced: {
      get() { return this.sellingprice; },
      set(v) { this.$emit("update:sellingprice", +v); }
    },
    amountSynced() {
      this.$emit("update:amount", parseFloat(this.quantity) * parseFloat(this.sellingprice));
      return this.amount
    }
  }
});

同时修改组件模板里的删除按钮,绑定点击事件:

<script type="text/x-template" id="row-template">
  <tr>
    <!-- 原有td内容保持不变 -->
    <td>
      <button @click="handleDelete">Delete</button>
    </td>
  </tr>
</script>

步骤2:在根组件中监听事件并实现删除

在根组件的form-row标签上,传递index属性,并监听delete-row事件,绑定删除方法:

<tbody>
  <form-row 
    v-for="(row, key) in tableDatas" 
    :key="key" 
    :index="key"
    v-bind.sync="row"
    @delete-row="deleteRow"
  ></form-row>
</tbody>

然后在根组件的methods里添加删除逻辑:

new Vue({
  el: "#app",
  data() {
    return { tableDatas: [] };
  },
  methods: {
    btnOnClick(v) {
      this.tableDatas.push({ itemname: "item", quantity: 1, sellingprice: 55, amount: 55 });
    },
    deleteRow(index) {
      console.log("Removing row at index:", index);
      this.tableDatas.splice(index, 1);
    }
  },
  computed: {
    calculate() {
      return ( this.tableDatas.reduce((total, { amount }) => total + amount, 0) || 0 );
    }
  }
});

方案二:事件总线(适用于真正的非父子组件)

如果你的两个组件完全没有父子关联(比如在不同路由页面、嵌套层级极深),可以用Vue事件总线实现跨组件通信:

步骤1:创建全局事件总线

在Vue实例创建前,定义一个全局总线实例:

// 创建全局事件总线
const EventBus = new Vue();

步骤2:在form-row组件中触发删除事件

修改handleDelete方法,通过事件总线向外发送删除信号:

methods: {
  handleDelete() {
    // 触发总线事件,传递当前行索引(需要先接收index prop)
    EventBus.$emit("delete-table-row", this.index);
  }
}

步骤3:在根组件中监听事件并处理

在根组件的created钩子中监听总线事件,实现删除逻辑,同时记得在组件销毁时移除监听避免内存泄漏:

new Vue({
  el: "#app",
  data() {
    return { tableDatas: [] };
  },
  created() {
    // 监听总线的删除事件
    EventBus.$on("delete-table-row", (index) => {
      this.tableDatas.splice(index, 1);
    });
  },
  methods: {
    btnOnClick(v) {
      this.tableDatas.push({ itemname: "item", quantity: 1, sellingprice: 55, amount: 55 });
    }
  },
  computed: {
    calculate() {
      return ( this.tableDatas.reduce((total, { amount }) => total + amount, 0) || 0 );
    }
  },
  beforeDestroy() {
    // 组件销毁时移除监听
    EventBus.$off("delete-table-row");
  }
});

小建议

  • 优先用方案一,因为你的场景里两个组件本来就是父子关系,原生事件传递更直观,不需要额外的总线实例。
  • 尽量不要用数组索引作为:key(数据有增删时容易出问题),建议给每一行数据加唯一id(比如时间戳),删除时通过id查找索引会更可靠:
    btnOnClick(v) {
      this.tableDatas.push({ 
        id: Date.now(), // 临时唯一id
        itemname: "item", 
        quantity: 1, 
        sellingprice: 55, 
        amount: 55 
      });
    },
    deleteRow(id) {
      const index = this.tableDatas.findIndex(row => row.id === id);
      if (index !== -1) this.tableDatas.splice(index, 1);
    }
    

内容的提问来源于stack exchange,提问作者user11543110

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:11:30