Vue - 在引导表自定义组件上更新数据

Posted

技术标签:

【中文标题】Vue - 在引导表自定义组件上更新数据【英文标题】:Vue - Update Data on Bootstrap Table Custom Component 【发布时间】:2019-04-30 17:02:24 【问题描述】:

我正在尝试在 Vue 2.0 中制作一个自定义组件,以扩展 Bootstrap Vue 库 <b-table> 的现有功能。除了 index.jsp 中定义的 removeRow 和 resetData 函数不能按我希望的方式工作外,它主要按我的意愿工作。

removeRow 确实会在视觉上删除该行,并将其从 data 属性中删除,但该行会在下一次交互(排序、过滤等)后重新出现。所以它实际上并没有更新正确的东西。我正在尝试将 v-model 用作项目的浅表副本,以便在不影响原始数据集的情况下对其进行删除,但我只是遗漏了一些东西。

resetData 确实将表中的数据设置回正确,但不会重新呈现表,因此您无法看到重新添加的行,直到您进行单独的交互(排序、过滤等),在这种情况下,它们会再次出现。

所以我知道我有点接近,但非常感谢任何有关如何使其正常工作以及我可以改进此组件任何部分的方法的见解。

OreillyTable.vue.js

const OreillyTable =  
inheritAttrs: false,
data: function () 
    return 
        filter: null,
        sortDesc: false,
        hideEmpty: false,
        isBusy: false,
        currentPage: 1,
        data: null
    
,
mounted: function () 
    let filtered = this.slots.filter(function(value, index, arr)
        return value.customRender;
    );
    this.slots = filtered;
,
methods: 
    oreillyTableSort (a, b, key) 
        if (a[key] === null || b[key] === null) 
            return a[key] === null && b[key] !== null ? -1 : (a[key] !== null && b[key] === null ? 1 : 0);
         else if (typeof a[key] === 'number' && typeof b[key] === 'number') 
            // If both compared fields are native numbers
            return a[key] < b[key] ? -1 : (a[key] > b[key] ? 1 : 0)
         else 
            // Stringify the field data and use String.localeCompare
            return this.toString(a[key]).localeCompare(this.toString(b[key]), undefined, 
                numeric: true
            );
        
    ,

    toString (val) 
        return typeof val !== "undefined" && val != null ? val.toString() : '';
    ,

    oreillyFilter (filteredItems) 
        this.totalRows = filteredItems.length;
        this.currentPage = 1;
    
,
props: 
    fields: 
        type: Array
    ,
    items: 
        type: Array,
        required: true
    ,
    hideEmpty: 
        type: Boolean
    ,
    filterPlaceholder: 
        type: String,
        default: "Filter"
    ,
    sortFunction: 
        type: Function,
        default: null
    ,
    filterFunction: 
        type: Function,
        default: null
    ,
    slots: 
        type: Array
    ,
    sortBy: 
        type: String,
        default: null
    ,
    perPage: 
        type: Number,
        default: 10
    ,
    value: 

    
,
template: `<div :class=" 'no-events' : isBusy ">
            <b-row>
                <b-col md="12">
                    <b-form-group class="mb-2 col-md-3 float-right pr-0">
                        <b-input-group>
                            <b-form-input v-model="filter" :placeholder="filterPlaceholder" class="form-control" />
                        </b-input-group>
                    </b-form-group>
                </b-col>
            </b-row>
            <div class="position-relative">
                <div v-if="isBusy" class="loader"></div>
                <b-table stacked="md" outlined responsive striped hover
                    v-bind="$attrs"
                    v-model="data"
                    :show-empty="!hideEmpty"
                    :items="items"
                    :fields="fields"
                    :no-provider-sorting="true" 
                    :no-sort-reset="true"
                    :filter="filter"
                    :sort-by.sync="sortBy" 
                    :sort-desc.sync="sortDesc" 
                    :sort-compare="sortFunction === null ? this.oreillyTableSort : sortFunction" 
                    :busy.sync="isBusy"
                    :current-page="currentPage"
                    :per-page="perPage"
                    @filtered="filterFunction === null ? this.oreillyFilter : filterFunction">

                    <template :slot="slot.key" slot-scope="row" v-for="slot in slots">
                        <slot :name="slot.key" :data="row"></slot>
                    </template>
                </b-table>

                <b-row v-if="items.length > perPage">
                    <b-col sm="12">
                        <b-pagination size="md" :total-rows="items.length" v-model="currentPage" :per-page="perPage"></b-pagination>
                    </b-col>
                </b-row>
            </div>
        </div>`
;

index.jsp

<script>
Vue.use(window.vuelidate.default);

Vue.component('oreilly-table', OreillyTable);

const dashboardItems = [
     id: 12, firstName: "John", lastName: "Adams", tmNumber: "588999", team: "Corporate", flapjackCount: 4, enrollDate: "2018-11-05" ,
     id: 13, firstName: "George", lastName: "Washington", tmNumber: "422111", team: "America", flapjackCount: 28, enrollDate: "2018-10-01" ,
     id: 14, firstName: "Abraham", lastName: "Lincoln", tmNumber: "358789", team: "America", flapjackCount: 16, enrollDate: "2017-09-02" ,
     id: 15, firstName: "Jimmy", lastName: "Carter", tmNumber: "225763", team: "Core", flapjackCount: 9, enrollDate: "2018-03-02" ,
     id: 16, firstName: "Thomas", lastName: "Jefferson", tmNumber: "169796", team: "Core", flapjackCount: 14, enrollDate: "2018-05-01" 
];

const Dashboard = 
    template: `<jsp:include page="dashboard.jsp"/>`,
    data: function()
        return             
            notification: 
                text: "The Great Flapjack Contest will be held on December 25, 2018.",
                variant: "primary",
                timer: true
            ,
            fields: [
                 key: "name", label: "Name", sortable: true, customRender: true ,
                 key: "team", label: "Team", sortable: true ,
                 key: "enrollDate", label: "Enrollment Date", sortable: true, formatter: (value) => return new Date(value).toLocaleDateString(); ,
                 key: "flapjackCount", sortable: true ,
                 key: "id", label: "", 'class': 'text-center', customRender: true 
            ]
        
    ,
    methods: 
        removeRow: function(id) 
            this.$refs.table.isBusy = true;
            setTimeout(() =>  console.log("Ajax Request Here"); this.$refs.table.isBusy = false; , 1000);
            const index = this.$refs.table.data.findIndex(item => item.id === id) 
            if (~index) 
                this.$refs.table.data.splice(index, 1)  
        ,
        resetData: function() 
            this.$refs.table.data = dashboardItems;
        
    
;

const router = new VueRouter(
    mode: 'history',
    base: "/ProjectTemplate/flapjack",
    routes: [
         path: '/enroll', component: Enroll ,
         path: '/', component: Dashboard ,
         path: '/404', component: NotFound ,  
         path: '*', redirect: '/404' 
    ]
);

new Vue(router).$mount('#app');

dashboard.jsp

<compress:html>
<div>
    <oreilly-table ref="table" :items="dashboardItems" :slots="fields" :fields="fields">
        <template slot="name" slot-scope="row">
             row.data.item.firstName   row.data.item.lastName  ( row.data.item.tmNumber )
        </template>
        <template slot="id" slot-scope="row">
            <a href="#" @click.prevent="removeRow(row.data.item.id)">Remove</a>
        </template>
    </oreilly-table>
    <footer class="footer position-sticky fixed-bottom bg-light">
        <div class="container text-center">
            <router-link tag="button" class="btn btn-outline-secondary" id="button" to="/enroll">Enroll</router-link>
            &emsp;
            <b-button @click.prevent="resetData" size="md" variant="outline-danger">Reset</b-button>
        </div>
    </footer>
</div>

【问题讨论】:

【参考方案1】:

我尝试通过一个简单的示例重现您的问题(请参阅:https://codesandbox.io/s/m30wqm0xk8?module=%2Fsrc%2Fcomponents%2FGridTest.vue),我遇到了同样的问题。就像其他人已经说过的那样,我同意重置原始数据的最简单方法是制作副本。我写了两种删除和重置数据的方法。

methods: 
    removeRow(id) 
      const index = this.records.findIndex(item => item.index === id);

      this.records.splice(index, 1);
    ,
    resetData() 
      this.records = this.copyOfOrigin.slice(0);
    
  

在挂载时,我执行了一个制作数据副本的函数。这是通过 slice 完成的,因为否则它只引用原始数组(请注意,通常 JS 是按值传递的,但正如 vue 文档中的对象所述,因此在 vue 内部它是通过引用传递的(请参阅:Vue docs滚动到红色标记的文本))。

mounted: function() 
    this.copyOfOrigin = this.records.slice(0);
   

现在您可以简单地删除一条记录,但也可以重置所有数据。

SEE FULL DEMO

我希望这能解决您的问题,如果您有任何问题,请随时提问。

【讨论】:

嗨,Kimberley,你能帮忙看看我的代码吗?我有一个非常相似的问题,我尝试了你的方法无济于事。非常感谢您的帮助。 ***.com/questions/55920207/… @NewProgrammer 我会看看,看看我能不能帮忙:)

以上是关于Vue - 在引导表自定义组件上更新数据的主要内容,如果未能解决你的问题,请参考以下文章

如何将我的数据存储在自定义 Vue 组件而不是根 Vue 实例中?

Vue 组件之间传参!

vue v-model 在自定义组件上的使用教程

vue v-model 在自定义组件上的使用教程

vue3自定义组件使用v-model实现双向数据绑定

Laravel Nova自定义工具创建:vue组件不刷新