Vue实战(三) - 实战项目(中) - 深入组件/内置函数/R

2021-05-09  本文已影响0人  ElliotG

1. 自定义分页组件

1-1) 准备分页数据(通过全局状态管理)

修改一下src/store文件夹下的index.js以支持分页。
代码如下:

...

export default new Vuex.Store({
    strict: true,
    state: {
        products: testData, 
        productsTotal: testData.length, 
        currentPage: 1,
        pageSize: 4
    },
    getters: {
        processedProducts: state => {
            let index = (state.currentPage -1) * state.pageSize;
            
            return state.products.slice(index, index + state.pageSize);
        },
        pageCount: state => Math.ceil(state.productsTotal / state.pageSize)
    },
    mutations: {
        setCurrentPage(state, page) {
            state.currentPage = page;
        },
        setPageSize(state, size) {
            state.pageSize = size;
            state.currentPage = 1;
        } 
    }
})

代码解释:

I. state(状态)部分:

我们看到,在state中我们添加了几个状态来支持分页。
除了原来的products代表所有数据以外,
我们添加了下面3项:
productsTotal - 记录总数
currentPage - 当前页
pageSize - 每页记录数
--------------------------------------------------------------
II. getters部分:

processedProducts - 当前页所有的记录
pageCount - 总共有多少页
--------------------------------------------------------------
III. mutations部分:

mutations - 定义了可以改变state中多个状态的方法
之前我们提到过, 改变store中状态的唯一途径就是显式地提交mutation。

setCurrentPage - 改变state中的currentPage属性
setPageSize - 改变state中的pageSize属性,同时重置currentPage属性

a. 通过mutations来改变state状态
b. 通过getters来对外暴露状态的处理值

 

1-2) 新建分页组件

PageControls.vue

<template>
    <div v-if="pageCount > 1" class="text-right">
        <div class="btn-group mx-2">
            <button v-for="i in pageNumbers" v-bind:key="I"
                    class="btn btn-secpmdary"
                    v-bind:class="{ 'btn-primary': i == currentPage }">
                {{ I }}
            </button>
        </div>
    </div>
</template>

<script>
    import { mapState, mapGetters } from "vuex";

    export default {
        computed: {
            ...mapState(["currentPage"]),
            ...mapGetters(["pageCount"]),
            pageNumbers() {
                return [...Array(this.pageCount + 1).keys()].slice(1);
            }
        } 
    }
</script>

代码解释:

关键词 详细描述
mapState 映射之前state中的currentPage(当前页)属性。
mapGetters 映射之前getters中的pageCount(总页数)属性。
pageNumbers 自定义计算属性(computed)方法用于显示第几页。

 

1-3) 列表组件中引用分页组件

修改ProductList.vue如下:

<template>
    <div>
        <div v-for="p in products" ...>
            ...
        </div>
        <page-controls />
    </div>
</template>

<script>
import { mapGetters } from "vuex";
import PageControls from "./PageControls";

export default {
    components: { PageControls },
    computed: {
        ...mapGetters({ products: "processedProducts" })
    }, 
    ...
} 
</script>

效果图如下:


image.png

 

1-4) 分页按钮事件

代码如下

<template>
    <div class="col form-group">
        <select class="form-control" v-on:change="changePageSize">
            <option value="4">4 per page</option>
            <option value="8">8 per page</option>
            <option value="12">12 per page</option>
        </select>
    </div>
    <div>
        ...
        <button v-for="i in pageNumbers" v-bind:key="I"
                       ...
                       v-on:click="setCurrentPage(i)">
        ...
        </button>
    </div>
</template>

<script>
    import { mapState, mapGetters, mapMutations } from "vuex";

    export default {
        ...
        methods: {
            ...mapMutations(["setCurrentPage", "setPageSize"]),
            changePageSize($event) {
                this.setPageSize(Number($event.target.value));
            }
        }
    } 
</script>

效果图如下:

image.png

store中的mutations是不能直接在组件中调用的,要通过mapMutations函数来进行映射。

 
 

2. 调用REST服务

2-1) 修改store, 增加axios库支持和actions

代码如下

...
import Axios from "axios";

Vue.use(Vuex);

const baseUrl = "http://localhost:3500";
const productsUrl = `${baseUrl}/products`;
const categoriesUrl = `${baseUrl}/categories`;

export default new Vuex.Store({
    strict: true,
    state: {
        ...
        categoriesData: []
    }, 
    getters: {
        ...
        categories: state => ["All", ...state.categoriesData]
    },
    mutations: {
        ...
        setData(state, data) {
            state.products = data.pdata;
            state.productsTotal = data.pdata.length;
            state.categoriesData = data.cdata.sort();
        }
    },
    actions: {
        async getData(context) {
            let pdata = (await Axios.get(productsUrl)).data;
            let cdata = (await Axios.get(categoriesUrl)).data;
            context.commit("setData", { pdata, cdata } );
        } 
    }
})

代码解释:

1. Axios库发起get请求获取数据。
2. async 和 await关键字配合使用,async修饰方法表示该方法异步,await等待异步任务结束后获取数据。
3. actions中的getData异步方法在获取到请求数据后,调用mutations中的方法来修改状态中的数据。

a. mutations中必须都是同步函数,不能存在异步调用。
b. action可以包含异步操作,用于放置异步方法(eg: 网络请求)。
c. actions通过context对象来访问data store的一些功能(eg: 提交mutations修改状态)。

 

2-2) 组件调用异步的action方法

代码如下
App.vue

...

<script>
    ...
    import { mapActions } from "vuex";

    export default {
        ...
        methods: {
            ...mapActions(["getData"])
        },
        created() {
            this.getData();
        }
    } 
</script>

代码解释:

1. mapActions映射之前我们在store中定义的异步action - getData, 用于请求数据并且修改数据状态。
2. created方法在组件创建时调用。

组件不能直接调用action方法,需要通过mapActions映射。

上一篇下一篇

猜你喜欢

热点阅读