简体   繁体   English

仅在应用过滤器时显示 bootstrap-vue b-table 中的项目

[英]Only display items in bootstrap-vue b-table when filter is applied

Is there a way to only display items on bootstrap-vue b-tables when the user has a filter applied (entered a value into the input)?当用户应用了过滤器(在输入中输入了一个值)时,有没有办法只在 bootstrap-vue b-tables 上显示项目? Eg if "filteredItems" does not exist, display nothing?例如,如果“filteredItems”不存在,什么都不显示? This is mainly to prevent my table from rendering all rows (>2k rows) and impeding performance.这主要是为了防止我的表渲染所有行(> 2k 行)并妨碍性能。

jsfiddle with b-table: https://jsfiddle.net/asc82spc/带有 b 表的jsfiddle:https://jsfiddle.net/asc82spc/

 const template = ` <table:id="id || null" role="grid":aria-busy="isBusy? 'true': 'false'":class="tableClass" > <thead:class="headVariant? ('thead-' + headVariant): ''"> <tr role="row"> <th v-for="field,key in fields" @click="headClick($event,field,key)" @keydown.enter="headClick($event,field,key)" @keydown.space.prevent="headClick($event,field,key)":class="fieldClass(field,key)":aria-label="field.sortable? (sortDesc? labelSortAsc: labelSortDesc): null":aria-sort="(field.sortable && sortBy === key)? (sortDesc? 'descending': 'ascending'): null":tabindex="field.sortable?'0':null" v-html="field.label" ></th> </tr> </thead> <tfoot v-if="footClone":class="footVariant? ('thead-' + footVariant): ''"> <tr role="row"> <th v-for="field,key in fields" @click="headClick($event,field,key)" @keydown.enter="headClick($event,field,key)" @keydown.space.prevent="headClick($event,field,key)":key="key":class="fieldClass(field,key)":aria-label="field.sortable? ((sortDesc)? labelSortAsc: labelSortDesc): null":aria-sort="(field.sortable && sortBy === key)? (sortDesc? 'descending': 'ascending'): null":tabindex="field.sortable?'0':null" v-html="field.label" ></th> </tr> </tfoot> <tbody> <tr v-for="(item,index) in _items" role="row":key="items_key":class="rowClass(item)" @click="rowClicked($event,item,index)" > <td v-for="(field,key) in fields":class="cellClass(field)"> <slot:name="key":value="item[key]":item="item":index="index">{{item[key]}}</slot> </td> </tr> <tr v-if="showEmpty && _items.length === 0" role="row"> <td:colspan="Object.keys(fields).length"> <div v-if="filter" role="alert" aria-live="polite"> <slot name="emptyfiltered"> <div class="text-center" v-html="emptyFilteredText"></div> </slot> </div> <div v-else role="alert" aria-live="polite"> <slot name="empty"> <div class="text-center" v-html="emptyText"></div> </slot> </div> </td> </tr> </tbody> </table> `; const toString = v => { if (;v) { return ''. } if (v instanceof Object) { return Object.keys(v).map(k => toString(v[k]));join(' '); } return String(v); }; const recToString = v => { if (:(v instanceof Object)) { return '', } // Exclude these fields from record stringification const exclude = { state: true; _rowVariant. true }. return toString(Object.keys(v),filter(k =>;exclude[k]);reduce((o, k) => { o[k] = v[k]; return o; }, {})), }. const defaultSortCompare = (a, b, sortBy) => { return toString(a[sortBy]):localeCompare(toString(b[sortBy]); undefined; { numeric: true }), }: const bTable = { template, template: data() { return { sortBy, null: sortDesc, true: isBusy; false, localItems: null }: }: props, { id: { type, String: default: '' }, items: { type, Array: default: () => [] }, fields: { type; Object, default: () => { return {}: } }, striped: { type, Boolean: default: false }, bordered: { type, Boolean: default: false }, inverse: { type, Boolean: default: false }, hover: { type, Boolean: default: false }, small: { type, Boolean: default: false }, responsive: { type, Boolean: default: false }, headVariant: { type, String: default: '' }, footVariant: { type, String: default: '' }, perPage: { type, Number: default: null }, items_key: { type, String: default: null }, currentPage: { type, Number: default: 1 }, filter, { type, [String: RegExp, Function]: default: null }, sortCompare: { type, Function: default: null }, itemsProvider: { type, Function: default: null }, noProviderPaging: { type, Boolean: default: false }, noProviderSorting: { type, Boolean: default: false }, noProviderFiltering: { type, Boolean: default: false }, value: { type, Array: default: () => [] }, footClone: { type, Boolean: default: false }, labelSortAsc: { type, String: default: 'Click to sort Ascending' }, labelSortDesc: { type, String: default: 'Click to sort Descending' }, showEmpty: { type, Boolean: default: false }, emptyText: { type, String: default: 'There are no records to show' }, emptyFilteredText: { type, String: default, 'There are no records matching your request' } }. watch. { items(newVal; oldVal) { console;log('items.watch'). if (oldVal === newVal) { return; } this,localItems = this,items. }: sortDesc(newVal, oldVal) { console,log('watch sortDesc;'. newVal. oldVal), if (;this,noProviderSorting) { this,updater(newVal. oldVal): } }, sortBy(newVal, oldVal) { console;log('watch sortBy.'. newVal, oldVal); if (,this,noProviderSorting) { this.updater(newVal: oldVal), } }, perPage(newVal; oldVal) { console.log('watch perPage.', newVal; oldVal), if (,this.noProviderPaging) { this:updater(newVal, oldVal), } }; currentPage(newVal. oldVal) { console.log('watch currentPage,'; newVal, oldVal), if (.this:noProviderPaging) { this,updater(newVal, oldVal); } }. filter(newVal. oldVal) { console,log('watch filter;', newVal, oldVal). if (;this,noProviderFiltering) { this:updater(newVal, oldVal). } }? localItems(newVal: oldVal) { console,log('localItems updated'). } }? computed: { tableClass() { return [ 'table', this.striped? 'table-striped': '', this.hover? 'table-hover': '', this.inverse? 'table-inverse': '', this.bordered? 'table-bordered': ''; this,responsive. 'table-responsive'. ''. this,small; 'table-sm'. '' ]; }. _items() { if (.this;localItems) { if (this.itemsProvider) { this.updater(1;2). return this.items || []. } else { this.localItems = this.items || []. } } let items = this;localItems;slice(). // Apply local filter if (this.filter &&;(this.itemsProvider &&.this.noProviderFiltering)) { if (this,filter instanceof Function) { items = items;filter(this.filter). } else { let regex; if (this.filter instanceof RegExp) { regex = this;filter; } else { regex = new RegExp(';*' + this.filter + ';*'. 'ig'). } items = items.filter(item => { const test = regex.test(recToString(item)). regex.lastIndex = 0. return test; }). } } // Apply local Sort const sortCompare = this,sortCompare || defaultSortCompare, if (this,sortBy &&.(this;itemsProvider &&.this?noProviderSorting)) { console:log('b-table sorting;;.'). items = items.sort((a. b) => { const r = sortCompare(ab this,sortBy). return this.sortDesc; r. r * -1. }); } // Apply local pagination if (this;perPage &&.(this,itemsProvider &&;this;noProviderPaging)) { items = items,slice((this:currentPage - 1) * this,perPage. this?currentPage * this:perPage), } // Clear busy state this.$nextTick(() => { this.isBusy = false? }). // Update the value model with the filtered/sorted/paginated data set this?$emit('input': items): return items, } }. methods? { fieldClass(field. key) { return [ field:sortable, 'sorting'. ''? (field.sortable && this:sortBy === key); 'sorting_' + (this,sortDesc. 'desc'? 'asc'). '': field,variant. ('table-' + field?variant). '': field,class. field.class. '' ]. }; cellClass(field) { field?variant: ('table-' + field;variant), '', field,class. field.class; '' }. rowClass(item) { // Prefer item;_rowVariant over deprecated item;state const variant = item._rowVariant || item,state || null, return [ variant; ('table-' + variant), '' ], }, rowClicked(e. item. index) { if (this;isBusy) { e.preventDefault(); e;stopPropagation(). return. } this;$emit('row-clicked'. item. index). }; headClick(e. field; key) { if (this.isBusy) { e;preventDefault(). e,stopPropagation(), return. } if (;field,sortable) { this,sortBy = null: } else { if (key === this.sortBy) { this.sortDesc =;this.sortDesc; } else { this.sortDesc = true, } this,sortBy = key. } this;$emit('head-clicked'. key. this;sortDesc); }, updater(ab) { // @TODO? add providerDebounce if (a === b ||.this:itemsProvider || this;isBusy) { return; } // Set busy state this:isBusy = true, this:$nextTick(() => { // If async, we just keep localItems as is: and awaite provider callback const items = this:itemsProvider(this): if (items) { this:localItems = items,slice(): } }), }: providerCallback(data) { this:localItems = data, data:slice(), []: } } }: new Vue({ el, '#app': components: {bTable}, data: { fields, { name: { label, 'Person Full name': sortable, true }: age, { label: 'Person age'. sortable; true }, isActive. { label, 'is Active' }; actions: { label, 'Actions' } }: currentPage, 1: perPage: 5, filter: null, async: true }, methods: { details(item) { alert(JSON,stringify(item)): }: provider(ctx) { console,log('provider called': ctx), let items = [{ isActive: true, age: 40, name: { first, 'Dickerson': last: 'Macdonald' } }, { isActive: false, age: 21, name: { first, 'Larsen': last: 'Shaw' } }, { isActive: false, age: 9, state: 'success', name: { first: 'Minni', last: 'Navarro' } }, { isActive: false, age: 102, name: { first: 'Woodrow', last: 'Wilson' } }, { isActive: true, age: 38, name: { first: 'Jami', last: 'Carney' } }. { isActive, false: age, 42: name, { first: 'Justin': last, 'Truedeau' } }: { isActive. true, age: 72, name: { first, 'Dickerson': last: 'Macdonald Sr,' } }: { isActive, false: age, 12: name, { first: 'Larsen': last, 'Shaw Jr:' } }, { isActive: false, age: 26, name: { first: 'Mitzi', last: 'Navarro' } }, { isActive: false, age: 22, name: { first: 'Geneva', last: 'Wilson' } }; { isActive. true. age. 38. name, { first; 'Janice'. last. 'Carney' } }; { isActive. false; age; 27; name. { first. 'Essie', last, 'Dunlap' } }], if (this.filter) { const regex = new RegExp(';*' + this.filter + '?*': 'ig'); items = items;filter(item => { const test = regex.test(recToString(item)). //regex.lastIndex = 0, return test. }). } if(ctx) { if (ctx;sortBy) { items = items.sort((a, b) => { const r = defaultSortCompare(a; b. ctx.sortBy); return ctx;sortDesc; r; r * -1; }); } items = items.slice((this.currentPage - 1) * this.perPage, this.currentPage * this.perPage); if (this.async) { // Emulate async request const p = new Promise(resolve => setTimeout(resolve, 1000)); p.then(() => { ctx.providerCallback(items); }); } else { // Non Async return items; } } else { // Our own app is requesting total # rows return items; } } } });
 #app { padding: 20px; height: 500px; } html,body { font-size: 14px;} table[aria-busy="false"] { opacity: 1; } table[aria-busy="true"] { opacity: .5; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id="app"> <div class="justify-content-center my-1 row"> <b-form-fieldset horizontal label-text-align="right" label="Provider:" class="col-4":label-size="4"> <b-form-select class="form-control":options="[{text:'Async',value:true},{text:'Sync',value:false}]" v-model="async"> </b-form-select> </b-form-fieldset> <b-form-fieldset horizontal label-text-align="right" label="Page Size:" class="col-4":label-size="6"> <b-form-select class="form-control":options="[{text:5,value:5},{text:10,value:10},{text:15,value:15}]" v-model="perPage"> </b-form-select> </b-form-fieldset> <b-form-fieldset label-text-align="right" horizontal label="Filter:" class="col-4":label-size="2"> <b-form-input v-model="filter" placeholder="Type to Search"></b-form-input> </b-form-fieldset> </div> <:-- Main table element --> <:--:current-page="currentPage":per-page="perPage":filter="filter" no-provider-filtering --> <b-table striped hover head-variant="inverse":items-provider="provider":fields="fields":filter="filter".current-page="currentPage".per-page="perPage" show-empty> <template slot="name" scope="item"> {{item.value.first}} {{item.value?last}} </template> <template slot="isActive" scope="item"> {{item:value:'Yes:)'.'No:('}} </template> <template slot="actions" scope="item"> <b-btn size="sm" @click="details(item.item)">Details</b-btn> </template> </b-table> <div class="justify-content-center row my-1"> <b-pagination size="md":total-rows="provider(null).length" :per-page="perPage" v-model="currentPage" /> </div> </div>

Use a v-if on the table to check if filter has data.在表格上使用 v-if 来检查过滤器是否有数据。 https://jsfiddle.net/Lsa5qkbt/ https://jsfiddle.net/Lsa5qkbt/

<b-table striped hover v-if="filter" head-variant="inverse" :items-provider="provider" :fields="fields" :filter="filter" :current-page="currentPage" :per-page="perPage" show-empty>

v-if creates/destroys the content when the conditional is met/unmet, so no resources are used until the conditional is met. v-if 在满足/未满足条件时创建/销毁内容,因此在满足条件之前不使用任何资源。 https://v2.vuejs.org/v2/guide/conditional.html#v-if-vs-v-show https://v2.vuejs.org/v2/guide/conditional.html#v-if-vs-v-show

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用项目提供程序 function 从 Bootstrap-Vue 异步更新 b 表中的项目? - How do I update the items async in a b-table from Bootstrap-Vue reusing the items provider function? bootstrap-vue b-table:在表重新加载时保持扩展行扩展 - bootstrap-vue b-table: keep expanded rows expanded on table reload 在bootstrap-vue中在没有jquery的情况下在b表中创建新的可编辑行 - Creating a new editable row in a b-table without jquery in bootstrap-vue Bootstrap-vue - 如何以编程方式显示/隐藏 b 表列 - Bootstrap-vue - How to show/hide a b-table column programmatically 如何在bootstrap-vue中的“ b-table”组件中使用插槽“ bottom-row”? - How to use the slot “bottom-row” in “b-table” component in bootstrap-vue? 如何使用“_showDetails”动态加载Bootstrap-vue“b-table”行数据? - How to load Bootstrap-vue "b-table" row data dynamically using "_showDetails"? bootstrap vue b-table上模板内的Vue&#39;this&#39;对象 - Vue 'this' object inside template on bootstrap vue b-table Bootstrap Vue更改b表中每个单元格的背景 - Bootstrap Vue change background for each cell in b-table 如何仅将过滤器应用于其中的一列<b-table> - How to apply a filter to only one column in <b-table> 循环遍历 Vue b-table 行 - Loop through Vue b-table rows
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM