在 DataTables 中使用 Vue Router

问题描述 投票:0回答:3

我正在尝试向我的 DataTable 中的行添加链接/按钮,单击后会将您带到 vue 路由。当然,我可以简单地添加一个带有

<a>
的普通
href="/item/${id}"
链接。但这会绕过路由器并导致整个页面重新加载

我想出了两个解决方案,都依赖于设置

onclick
来执行一些代码:

  1. route1
    中,我在
    vueRoute
    对象上附加了一个名为
    window
    的函数,它只是对vue方法
    route1
    的引用。现在可以从任何地方调用此功能

  2. route2
    中,我有
    onclick
    触发
    CustomEvent
    ,我有一个事件侦听器设置为由
    route2
    vue 方法处理

我对这两种解决方案都不满意。尽管它们有效,但它们看起来非常“hacky”。我应该做什么呢?

// datatables column definitions
columns: [
  // route1
  {
      data: 'id',
      render: function (dt) {
          return `<a href="#" onclick="(function(){vueRoute('${dt}');})()">route1</a>`;
      },
  },
  // route2
  {
    data: 'id',
    render: function (dt) {
        return `<a href="#" onclick="(function(){document.body.dispatchEvent(
          new CustomEvent('clickedEdit', {detail : ${dt} }));})() ">route2</a>`;
    },
  },
],

// vue methods
methods: {
  route1(id) {
    this.router.push('/item/' + id);
  },

  route2(evt) {
    this.router.push('/item/' + evt.detail);
  },
},

// on mount, set up route1 and route2
mounted() {
  window.vueRoute = this.route1;

  document.body.addEventListener('clickedEdit', this.route2);
},

javascript vue.js datatables vuejs3 vue-router
3个回答
1
投票

您可以在 DataTable 对象上设置

@click
处理程序:

<DataTable
  ...
  @click="resolveRouteFromClick($event)"
>

该事件将是一个常规的点击事件,因此我们需要一个可识别的数据集属性 id:

{
  data: 'id',
  render: function (idValue) {
    return `<a href="#" data-item-id="${idValue}">route3</a>`;
  },
},

点击处理程序只需确保可以检索到 id,确保点击来自链接:

resolveRouteFromClick(e){
  const itemId = e.target.dataset.itemId
  if (!itemId) {
    return
  }
  e.preventDefault()
  this.router.push('/item/' + itemId);
}

这是更新后的stackblitz


有趣的是,问题甚至不是 Vue 和 jQuery 之间的连接,而是 DataTables 的工作方式,特别是没有单击单元格或单击行的事件,并且渲染器只能返回 HTML字符串。

不过这并不奇怪,jQuery 的工作方式就是这样,数据、视图和行为之间并没有内在的联系,但是您可以按照您认为合适的方式将它们联系起来。所以没有我们可以搭载的单元格单击事件,因为在 jQuery 中,你自己编写它或者它不存在。

在 jQuery 中设置处理程序的最有效方法是使用目标过滤器在表上设置事件:

$('.datatable').on('click', 'a[data-item-id]', function(){...})

优点是:

  • 所有行只有一个事件
  • 更改页面或重新渲染时无需添加事件(时间很重要)
  • 渲染函数中的代码保持最小

和上面的解决方案完全一样,只是在Vue中设置了事件,我们必须自己编写目标过滤器,这是没有问题的。

所以我认为这是使其在 Vue 中工作的最有效方法,无论是代码量(可维护性)还是性能。


1
投票

我不会说这是最好的解决方案,但在我看来,据我所知,没有真正的“最佳”解决方案,因为数据表使用的是 jQuery 而你在这里使用的是 vue(DOM 控件有点不一致).通过快速搜索,我发现没有办法 在数据表的

render
属性中渲染一个 vue 组件。

所以我的想法是不同的,它简化渲染功能,并使用

drawCallback
添加事件监听器并使用事件委托来附加监听器。

来自文档

DataTables 每次执行绘制时调用的函数。

...您可能想将事件分配给新创建的元素

  data() {
    return {
      ...
      columns: [
        ...
        {
          data: 'id',
          render: function (dt) {
            return `<a href="#" class="route3" data-item-id='${dt}'>route3</a>`;
          },
        },
      ],
    };
  },
  methods: {
    ...
    drawCallback(settings) {
      const tableElm = document.getElementById(settings.sInstance);

      tableElm.addEventListener('click', (e) => {
        const id = e.target.dataset.itemId;

        if (id) {
          this.router.push('/item/' + id);
        }
      });
    },
  },
...
<template>
  ...
    <DataTable
      :data="data"
      :columns="columns"
      :options="{
        drawCallback: drawCallback,
      }"
      class="display"
      width="100%"
    >
  ...
</template>

所以我简单地将

data-item-id
附加到每个链接,然后使用父级的点击事件来进行路由器推送(事件委托)。我知道这不是最好的答案,但也许这可能是您的另一种选择。

如果你有兴趣,这就是分叉的沙箱。


0
投票

你想避免 hacky 解决方案是可以理解的。这是使用 Vue 指令和更以 Vue 为中心的方法来处理这种情况的更好方法。

  1. 首先,您需要使用 v-html 指令来呈现 DataTable 列的原始 HTML。

  2. 接下来,使用 v-on 指令(或简写 @click)将点击事件绑定到链接,并以行数据作为参数调用 Vue 方法。

以下是修改代码的方法:

  1. 更新列定义:
columns: [
  {
    data: 'id',
    render: function (id) {
      return `<a class="route1-link" data-id="${id}">route1</a>`;
    },
  },
  {
    data: 'id',
    render: function (id) {
      return `<a class="route2-link" data-id="${id}">route2</a>`;
    },
  },
],
  1. 使用 Vue 修改挂载函数以附加事件监听器:
mounted() {
  this.$nextTick(() => {
    // Attach event listeners to the route1-link and route2-link elements
    this.$el.querySelectorAll('.route1-link').forEach((link) => {
      link.addEventListener('click', (event) => {
        event.preventDefault();
        this.route1(event.target.dataset.id);
      });
    });

    this.$el.querySelectorAll('.route2-link').forEach((link) => {
      link.addEventListener('click', (event) => {
        event.preventDefault();
        this.route2(event.target.dataset.id);
      });
    });
  });
},
  1. mounted()函数中删除之前的window.vueRoutedocument.body.addEventListener行。

通过这些更改,您现在可以使用 Vue 的内置功能来处理路由和点击事件,从而使代码更易于维护并且更不容易出错。

© www.soinside.com 2019 - 2024. All rights reserved.