【问题标题】:vue.js with Laravel pagination and filtering for listvue.js 与 Laravel 分页和过滤列表
【发布时间】:2016-05-29 23:23:43
【问题描述】:

我仍在讨论这种方法,但这是我目前所拥有的。过滤器效果很好,但数据列表超过 2k 项,因此需要应用某种限制。问题是,对视图的任何限制都必须需要一个新的 API 拉取,并通过我尝试过的任何方法设置任何过滤器。

我的问题是我应该以某种方式从 API 调用中分页还是提取所有数据并使用 vue 分页?我应该在后端过滤并应用不同的 API 调用,还是应该使用下面的内容?过滤效果很好,但我不清楚如何限制显示的内容,然后过滤整个列表然后返回。

我的 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>

【问题讨论】:

    标签: javascript vue.js vue-resource


    【解决方案1】:

    如果查询花费的时间超过几秒钟,我会实施服务器端过滤,但这确实是您的偏好。如果您使用客户端过滤器,则可以使用内置的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>
    

    【讨论】:

    • oMg 这比我想象的要容易得多。我知道当我变得如此有创造力时,我一定错过了一些东西。明天早上我会试试这个,我可能会有更多问题
    • 工作就像一个魅力,我什至启用了搜索 Vue 太棒了
    • @KevinCompton 哈哈我知道这种感觉!很高兴你启动并运行了
    猜你喜欢
    • 2013-03-02
    • 2013-02-19
    • 2017-06-07
    • 2021-04-13
    • 1970-01-01
    • 2017-03-27
    • 1970-01-01
    • 2021-07-22
    • 2017-09-13
    相关资源
    最近更新 更多