正确实现 Vue.js + DataTables

Posted

技术标签:

【中文标题】正确实现 Vue.js + DataTables【英文标题】:Implementing Vue.js + DataTables properly 【发布时间】:2015-12-21 17:34:18 【问题描述】:

我正在尝试实现 Vue.js + jQuery 的 DataTables,但发生了一件奇怪的事情。

在 Firefox 上检查这个小提琴 (不适用于 chrome): http://jsfiddle.net/chrislandeza/xgv8c01y/

当我更改 DataTable 的状态时(例如排序、搜索等):

列表中新添加的数据消失 DOM 没有读取指令或 vue 属性

我很确定任何尝试混合使用 vue.js+datatables 的人都遇到过这个问题。你是怎么解决这个问题的?

或者是否有一个纯 Vue.js 脚本/插件具有与 jquery 的 DataTable 相同(或接近)的功能? (分页、搜索、排序、要显示的条目数等)。

这是上面小提琴中的代码:

html

<div class='container-fluid' id="app">
        <div class='row'>
            <div class='col-md-9'>
                <table class="table table-bordered" id="app-datatable">
                    <thead>
                        <tr>
                            <th>Name</th>
                            <th>Age</th>
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr v-repeat="user: users">
                            <td> user.name </td>
                            <td> user.age </td>
                            <td>
                                <button type="button" v-on="click: foo(user)">Action</button>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
            <div class='col-md-3'>
                <div class="form-group">
                    <label>Name</label>
                    <input type="text"
                           class="form-control"
                           v-model="newUser.name"
                           >
                </div>

                <div class="form-group">
                    <label>Age</label>
                    <input type="name"
                           class="form-control"
                           v-model="newUser.age"
                           >
                </div>
                <button type="submit" class="btn btn-primary" v-on="click: addUser()">Add</button>
            </div>
        </div>
    </div>

javascript

$(document).ready(function () 
    var dT = $('#app-datatable').DataTable();
);

var vm = new Vue(
    el: '#app',
    data: 
        newUser: ,
        users: [
            name: 'Chris', age: 1,
            name: 'John', age: 2
        ]
    ,
    methods:
        addUser: function()
           this.users.push(this.newUser);
           this.newUser = ;
        ,
        foo: function(user)
            console.log(user.name);
        
    
);

非常感谢任何建议。

【问题讨论】:

小提琴不起作用,因为您直接引用 githubusercontent - 您应该使用 rawgithub.com -> jsfiddle.net/cLd46juf 请参阅 Reference GitHub file in jsFiddle 这个问题与在 Angular 中使用 jQuery 样式的 dataTables 时相同。两者都试图操纵 DOM,vue 正在赢得这场战斗。遗憾的是,我认为没有简单的开箱即用解决方案。 【参考方案1】:

要使 DataTables 插件与 Vue 正确集成,请记住以下几点:

    根据您的示例,如果您已经准备好数据并呈现到 DOM,则可以使用 var dT = $('#app-datatable').DataTable(); 来初始化 DataTables。如果您没有完全呈现 DOM &lt;table&gt;&lt;/table&gt;(可能是由于通过延迟的 ajax 调用填充的数据),则在数据准备好之前无法初始化 DataTables。例如,如果您的组件中有 fetchData 方法,则可以在完成承诺后初始化 DataTable。

    一旦初始化更新表,可能是由于底层表数据的变化,最好(也许是唯一的方法)是首先销毁表,然后在 Vue 接收新数据并将其写入 DOM 之前:

    var dT = $('#app-datatable').DataTable();
    dT.destroy();
    

    然后,一旦数据(在您的情况下是 users 数组)被更新, 像这样重新初始化 DataTable:

    this.$nextTick(function() 
       $('#app-datatable').DataTable(
          // DataTable options here...
       );
    )
    

    $nextTick 是必要的,以确保 Vue 在重新初始化之前已将新数据刷新到 DOM。如果在 DataTable 插件初始化后更新 DOM,你会看到表格数据,但通常的排序、分页等将不起作用。

    还有一点很重要,就是在你的数据集中有一个row id,并在&lt;tr&gt;&lt;/tr&gt;中设置key:

    &lt;tr v-repeat="user: users" track-by="id"&gt;

    如果没有track-by,Vue 在 DataTables 初始化后将新数据刷新到 DOM 时会报错,这可能是由于找不到被 DataTables 劫持的 DOM 元素。

【讨论】:

【参考方案2】:

也许你可以使用生命周期钩子,事实上这些奇怪的事情是由操作 DOM 的竞争引起的。在你的 vue 实例中,添加一个 created() 钩子,然后初始化 DataTable,如下所示:

var vm = new Vue(
el: '#app',
data: 
    newUser: ,
    users: [
        name: 'Chris', age: 1,
        name: 'John', age: 2
    ]
,
methods:
    addUser: function()
       this.users.push(this.newUser);
       this.newUser = ;
    ,
    foo: function(user)
        console.log(user.name);
    
,
created()
      this.$nextTick(function() 
        $('#app-datatable').DataTable();
      )
    

);

【讨论】:

【参考方案3】:

我已经从外部提供了表格数据(不是来自 DataTable 的 Ajax 调用)并且仅使用这些生命周期挂钩来销毁/重新创建表格对我有用:

beforeUpdate: function() 
    if (this.dataTable) 
        this.dataTable.destroy()
    
,
updated: function() 
    this.dataTable = $(this.$el).DataTable()

来自https://alligator.io/vuejs/component-lifecycle/

“beforeUpdate 钩子在组件上的数据更改之后运行并且更新周期开始,就在 DOM 被修补和重新渲染之前。它允许您在组件上的任何反应性数据实际获取之前获取它的新状态渲染。”

“更新后的钩子在您的组件上的数据更改并且 DOM 重新渲染后运行。如果您需要在属性更改后访问 DOM,这里可能是最安全的地方。”

【讨论】:

以上是关于正确实现 Vue.js + DataTables的主要内容,如果未能解决你的问题,请参考以下文章

如何正确使用 vue js Web 组件内部的插槽并应用样式

如何正确地将数据从 vue 组件发布到 laravel 控制器

Vue.js“扩展”使用的正确方法是啥?

Vue.js / Laravel - 正确处理注销

Vue.js:从其方法内部更改组件道具的正确方法

带有 Vue 2.0 的 Sortable.js 排序不正确