vue.js 具有 Laravel 列表的分页和过滤
vue.js with Laravel pagination and filtering for list
我仍在争论这种方法,但这是我目前所拥有的。过滤器效果很好,但数据列表超过 2k 项,因此需要应用某种限制。问题是,对视图的任何限制都必须需要一个新的 API 拉动,并通过我尝试过的任何方法设置任何过滤器。
我的问题是我应该以某种方式从 API 调用分页还是提取所有数据并使用 vue 分页?我应该在后端过滤并应用不同的 API 调用还是应该使用下面的内容?过滤效果很好,但我不清楚如何限制显示的内容,然后过滤整个列表 return。
我的 Vue 应用程序和组件:
Vue.component('filter', {
props: ['list', 'name'],
template: '#filter-template',
watch: {
selected: function(currentValue) {
this.$dispatch('filter-update', [this.name, currentValue]);
}
}
});
Vue.component('products', {
template: '#product-template',
created() {
this.fetchProducts();
},
data:function(){
return {
products:[],
category: 'All',
collection: 'All',
design: 'All'
}
},
events: {
'push-category': function(id) {
this.category = id;
this.filterProducts();
},
'push-collection': function(id) {
this.collection = id;
this.filterProducts();
},
'push-design': function(id) {
this.design = id;
this.filterProducts();
}
},
computed: {
total: function () {
return this.products.length;
}
},
methods: {
fetchProducts: function() {
this.$http.get('api/internal/products', function(products) {
this.$set('products', products);
});
},
filterProducts: function() {
var parent = this;
var catFilter = [];
var collFilter = [];
var designFilter = [];
// Collect all the bad guys
if(this.category == 'All') {
catFilter = [];
} else {
var key = 'Item_Disc_Group';
filter(key, this.category, catFilter);
}
if(this.collection == 'All') {
collFilter = [];
} else {
var key = 'Collection';
filter(key, this.collection, collFilter);
}
if(this.design == 'All') {
designFilter = [];
} else {
var key = 'Fancy_Color_Intensity';
filter(key, this.design, designFilter);
}
// Hide all the bad guys, show any good guys
for (var i = this.products.length - 1; i >= 0; i--) {
var product = this.products[i];
if(catFilter.indexOf(product) > -1) {
product.On_The_Web = "0";
} else if(collFilter.indexOf(product) > -1) {
product.On_The_Web = "0";
} else if(designFilter.indexOf(product) > -1) {
product.On_The_Web = "0";
} else {
product.On_The_Web = "1";
}
};
function filter(key, active, array) {
for (var i = parent.products.length - 1; i >= 0; i--) {
var product = parent.products[i];
if(product[key] != active) {
array.push(product);
}
};
}
}
}
});
new Vue({
el: '#product-filter',
created() {
this.fetchCategories();
this.fetchCollections();
this.fetchDesigns();
},
methods: {
fetchCategories: function() {
this.$http.get('api/categories', function(categories) {
this.$set('categories', categories);
});
},
fetchCollections: function() {
this.$http.get('api/collections', function(collections) {
this.$set('collections', collections);
});
},
fetchDesigns: function() {
this.$http.get('api/designs', function(designs) {
this.$set('designs', designs);
});
}
},
events: {
'filter-update': function(data) {
if(data[0] == "categories") {
this.$broadcast('push-category', data[1]);
} else if (data[0] == "collections") {
this.$broadcast('push-collection', data[1]);
} else {
this.$broadcast('push-design', data[1]);
}
}
}
});
我的标记:
<div id="product-filter">
<filter :list="categories" name="categories"></filter>
<filter :list="collections" name="collections"></filter>
<filter :list="designs" name="designs"></filter>
<div class="clearfix"></div>
<products></products>
<!-- Vue Templates -->
<template id="filter-template">
<div class="form-group col-md-2">
<label>@{{ name }}</label>
<select v-model="selected" class="form-control input-small">
<option selected>All</option>
<option value="@{{ option.navision_id }}" v-for="option in list">@{{ option.name }}</option>
</select>
<span>Selected: @{{ selected }}</span>
</div>
</template>
<template id="product-template">
<div class="row mix-grid thumbnails">
<h1>@{{ total }}</h1>
<div v-for="product in products" v-if="product.On_The_Web == '1'" class="col-md-3 col-sm-6 mix category_1">
<a href="/products/@{{ product.id }}">
<div class="mix-inner">
<img class="img-responsive" src="https://s3-us-west-1.amazonaws.com/sg-retail/images/products/@{{ product.No }}.jpg" alt="">
<div class="prod-details">
<h3>@{{ product.No }}</h3>
<p></p>
<span class="price"></span>
</div>
</div>
</a>
<div class="prod-ui">
</div>
</div>
</div>
</template>
</div>
如果查询花费的时间超过几秒钟,我会实施服务器端过滤,但这确实是您的偏好。如果您使用客户端过滤器,则可以使用内置的 filterBy
过滤器:
<div v-for="product in products | filterBy category in 'Item_Disc_Group' | filterBy collection in 'Collection' | filterBy design in 'Fancy_Color_Intensity'">
只需将默认值设为 ''
而不是 All
,这样如果没有选择过滤器,则列表根本不会被过滤。
<option value="" selected>All</option>
然后你还可以使用分页过滤器进一步分页结果(借用this fiddle):
data:function(){
return {
currentPage: 0,
itemsPerPage: 1,
resultCount: 0
}
},
computed: {
totalPages: function() {
return Math.ceil(this.resultCount / this.itemsPerPage)
}
},
methods: {
setPage: function(pageNumber) {
this.currentPage = pageNumber
}
},
filters: {
paginate: function(list) {
this.resultCount = list.length
if (this.currentPage >= this.totalPages) {
this.currentPage = this.totalPages - 1
}
var index = this.currentPage * this.itemsPerPage
return list.slice(index, index + this.itemsPerPage)
}
}
过滤后最后添加:
<div v-for="product in products | filterBy category in 'Item_Disc_Group' | filterBy collection in 'Collection' | filterBy design in 'Fancy_Color_Intensity' | paginate">
您还想添加按钮以支持分页,即:
<ul>
<li v-repeat="pageNumber: totalPages">
<a href="#" v-on="click: setPage(pageNumber)" v-class="current: currentPage === pageNumber">{{ pageNumber+1 }}</a>
</li>
</ul>
我仍在争论这种方法,但这是我目前所拥有的。过滤器效果很好,但数据列表超过 2k 项,因此需要应用某种限制。问题是,对视图的任何限制都必须需要一个新的 API 拉动,并通过我尝试过的任何方法设置任何过滤器。
我的问题是我应该以某种方式从 API 调用分页还是提取所有数据并使用 vue 分页?我应该在后端过滤并应用不同的 API 调用还是应该使用下面的内容?过滤效果很好,但我不清楚如何限制显示的内容,然后过滤整个列表 return。
我的 Vue 应用程序和组件:
Vue.component('filter', {
props: ['list', 'name'],
template: '#filter-template',
watch: {
selected: function(currentValue) {
this.$dispatch('filter-update', [this.name, currentValue]);
}
}
});
Vue.component('products', {
template: '#product-template',
created() {
this.fetchProducts();
},
data:function(){
return {
products:[],
category: 'All',
collection: 'All',
design: 'All'
}
},
events: {
'push-category': function(id) {
this.category = id;
this.filterProducts();
},
'push-collection': function(id) {
this.collection = id;
this.filterProducts();
},
'push-design': function(id) {
this.design = id;
this.filterProducts();
}
},
computed: {
total: function () {
return this.products.length;
}
},
methods: {
fetchProducts: function() {
this.$http.get('api/internal/products', function(products) {
this.$set('products', products);
});
},
filterProducts: function() {
var parent = this;
var catFilter = [];
var collFilter = [];
var designFilter = [];
// Collect all the bad guys
if(this.category == 'All') {
catFilter = [];
} else {
var key = 'Item_Disc_Group';
filter(key, this.category, catFilter);
}
if(this.collection == 'All') {
collFilter = [];
} else {
var key = 'Collection';
filter(key, this.collection, collFilter);
}
if(this.design == 'All') {
designFilter = [];
} else {
var key = 'Fancy_Color_Intensity';
filter(key, this.design, designFilter);
}
// Hide all the bad guys, show any good guys
for (var i = this.products.length - 1; i >= 0; i--) {
var product = this.products[i];
if(catFilter.indexOf(product) > -1) {
product.On_The_Web = "0";
} else if(collFilter.indexOf(product) > -1) {
product.On_The_Web = "0";
} else if(designFilter.indexOf(product) > -1) {
product.On_The_Web = "0";
} else {
product.On_The_Web = "1";
}
};
function filter(key, active, array) {
for (var i = parent.products.length - 1; i >= 0; i--) {
var product = parent.products[i];
if(product[key] != active) {
array.push(product);
}
};
}
}
}
});
new Vue({
el: '#product-filter',
created() {
this.fetchCategories();
this.fetchCollections();
this.fetchDesigns();
},
methods: {
fetchCategories: function() {
this.$http.get('api/categories', function(categories) {
this.$set('categories', categories);
});
},
fetchCollections: function() {
this.$http.get('api/collections', function(collections) {
this.$set('collections', collections);
});
},
fetchDesigns: function() {
this.$http.get('api/designs', function(designs) {
this.$set('designs', designs);
});
}
},
events: {
'filter-update': function(data) {
if(data[0] == "categories") {
this.$broadcast('push-category', data[1]);
} else if (data[0] == "collections") {
this.$broadcast('push-collection', data[1]);
} else {
this.$broadcast('push-design', data[1]);
}
}
}
});
我的标记:
<div id="product-filter">
<filter :list="categories" name="categories"></filter>
<filter :list="collections" name="collections"></filter>
<filter :list="designs" name="designs"></filter>
<div class="clearfix"></div>
<products></products>
<!-- Vue Templates -->
<template id="filter-template">
<div class="form-group col-md-2">
<label>@{{ name }}</label>
<select v-model="selected" class="form-control input-small">
<option selected>All</option>
<option value="@{{ option.navision_id }}" v-for="option in list">@{{ option.name }}</option>
</select>
<span>Selected: @{{ selected }}</span>
</div>
</template>
<template id="product-template">
<div class="row mix-grid thumbnails">
<h1>@{{ total }}</h1>
<div v-for="product in products" v-if="product.On_The_Web == '1'" class="col-md-3 col-sm-6 mix category_1">
<a href="/products/@{{ product.id }}">
<div class="mix-inner">
<img class="img-responsive" src="https://s3-us-west-1.amazonaws.com/sg-retail/images/products/@{{ product.No }}.jpg" alt="">
<div class="prod-details">
<h3>@{{ product.No }}</h3>
<p></p>
<span class="price"></span>
</div>
</div>
</a>
<div class="prod-ui">
</div>
</div>
</div>
</template>
</div>
如果查询花费的时间超过几秒钟,我会实施服务器端过滤,但这确实是您的偏好。如果您使用客户端过滤器,则可以使用内置的 filterBy
过滤器:
<div v-for="product in products | filterBy category in 'Item_Disc_Group' | filterBy collection in 'Collection' | filterBy design in 'Fancy_Color_Intensity'">
只需将默认值设为 ''
而不是 All
,这样如果没有选择过滤器,则列表根本不会被过滤。
<option value="" selected>All</option>
然后你还可以使用分页过滤器进一步分页结果(借用this fiddle):
data:function(){
return {
currentPage: 0,
itemsPerPage: 1,
resultCount: 0
}
},
computed: {
totalPages: function() {
return Math.ceil(this.resultCount / this.itemsPerPage)
}
},
methods: {
setPage: function(pageNumber) {
this.currentPage = pageNumber
}
},
filters: {
paginate: function(list) {
this.resultCount = list.length
if (this.currentPage >= this.totalPages) {
this.currentPage = this.totalPages - 1
}
var index = this.currentPage * this.itemsPerPage
return list.slice(index, index + this.itemsPerPage)
}
}
过滤后最后添加:
<div v-for="product in products | filterBy category in 'Item_Disc_Group' | filterBy collection in 'Collection' | filterBy design in 'Fancy_Color_Intensity' | paginate">
您还想添加按钮以支持分页,即:
<ul>
<li v-repeat="pageNumber: totalPages">
<a href="#" v-on="click: setPage(pageNumber)" v-class="current: currentPage === pageNumber">{{ pageNumber+1 }}</a>
</li>
</ul>