Vue.js:无法使用 "v-on" 捕获名称中带有点的事件

Vue.js: Unable to catch an event with a point in name using "v-on"

我正在使用 Vue.js (2.6) 和 DataTables.js 并试图捕捉 Page change event.

Datatables 中的页面更改事件被命名为 page.dt(与所有 DataTables 事件一样,它在点后具有命名空间 dt

如果我尝试按照文档来做,它不起作用。
我想,它不起作用,因为 Vue 使用事件名称中的点来定义事件修饰符,例如 click.once

我的问题是:有没有办法使用 Vue 捕获名称中带有点的此类事件?

这里是 HTML 指令:

 <table class="table" id="dataTable" v-on:page.dt="pageChange">

这是我的方法pageChange:

  methods: {
            pageChange(e) {
                var info = datatable.page.info();
                alert('Showing page: ' + info.page + ' of ' + info.pages);
           }
  }
                

以下 jQuery 事件处理程序完美运行:

  $('#dataTable').on('page.dt', function () {
            var info = datatable.page.info();
            alert('Showing page: ' + info.page + ' of ' + info.pages);
  });

<!DOCTYPE html>
<html>

<head>
    <title>Vue.js + Datatables.js</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"
        integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
        <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs4/dt-1.10.22/datatables.min.css"/>
    </head>

<body class="p-4">
    <div class="container fluid">
        <div id="app">
            <div class="table-responsive-xl">
                <table class="table" id="dataTable" v-on:[`page.dt`]="pageChange">
                    <thead>
                        <tr>
                            <th>
                                Id
                            </th>
                            <th>
                                Name
                            </th>
                            <th>
                                Candy
                            </th>
                            <th>
                                Height
                            </th>
                            <th>
                                Weight
                            </th>
                        </tr>
                    </thead>
                    <tbody>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</body>

<script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js"
    integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous">
</script>
<script type="text/javascript" src="https://cdn.datatables.net/v/bs4/dt-1.10.22/datatables.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script type="text/javascript">

var datatable = null;

var app = new Vue({
  el: "#app",
   computed: {
        table: function () {
            return datatable;
        }
    },
   methods: {
        pageChange(e) {
            var info = this.table.page.info();
            alert('Showing page: ' + info.page + ' of ' + info.pages);
        }
  }
       
});

datatable = $("#dataTable").DataTable({
  ajax: {
    url:
      "https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json",
    dataSrc: "pokemon"
  },
  columns: [
    { data: "id" },
    { data: "name" },
    { data: "candy" },
    { data: "height" },
    { data: "weight" }
  ]
});

/* $('#dataTable').on('page.dt', function () {
    var info = datatable.page.info();
    alert('Showing page: ' + info.page + ' of ' + info.pages);
});
 */

</script>

</html>

ref="dataTable" 添加到您的 table,并在您的方法中通过 this.$refs.dataTable 访问

<table class="table" id="dataTable" ref="dataTable" v-on:page.dt="pageChange">
  methods: {
            pageChange(e) {
                var info = this.$refs.dataTable.page.info();
                alert('Showing page: ' + info.page + ' of ' + info.pages);
           }
  }

另一种方法是使用 $event(我不确定它是否有效,因为无权检查)

<table class="table" id="dataTable" v-on:page.dt="pageChange($event)">
  methods: {
            pageChange(event) {
                var info = event.target.page.info();
                alert('Showing page: ' + info.page + ' of ' + info.pages);
           }
  }

您应该能够使用动态参数语法:

v-on:[`page.dt`]="pageChange"

或:

@[`page.dt`]="pageChange"

注意反引号的使用。您不能使用其他形式的引号,因为在属性名称中不允许使用它们。

更新:

我使用 the JSFiddle 提供的进一步调查。

我提供的代码 确实<table> 元素添加了一个 page.dt 事件侦听器。您可以在开发者工具中看到:

因此,如果您想使用 Vue 捕获名称中带有点的事件,那么我建议的代码是正确的。

然而...

这不是这里实际需要的。

page.dt 是命名空间 jQuery 事件。实际事件称为 page,而不是 page.dt。 jQuery 将在事件触发但事件本身被调用时按名称空间进行内部过滤 page。当您使用 jQuery 添加事件 page.dt 时,您会看到它向 DOM:

添加了一个 page 事件

所以您可能认为我们可以通过使用 v-on:page 来解决这个问题。我当然做到了。但可惜没有。

DataTables 调用 jQuery 的 trigger 方法来触发 page.dt 事件。这有两件事:

  1. 它调用所有通过jQuery注册的监听器。这就是使用 jQuery 示例时 alert 的显示方式。
  2. 触发原生事件。或者至少,这就是它声称要做的。它实际做的(通过查看 jQuery 代码)是尝试在与事件同名的元素上调用一个方法。对于本机事件可能会很好地工作但对于自定义 page 事件它不会做任何事情。

所以 Vue 无法检测到事件的原因是因为没有 DOM 事件被触发。这都是内部 jQuery 魔法,而不是真正的 DOM 事件。

但是,这确实为我们提供了 Vue-based 解决方法。

鉴于 jQuery 将尝试在元素上调用名为 page 的方法,我们可以为其提供:

:page.prop="pageChange"

我用你的 Fiddle 试过了,确实有效。