0
点赞
收藏
分享

微信扫一扫

json-server 和 mockjs 配合 iview 制作学生表格

千行 2021-09-24 阅读 37

前言:使用到的技术

  • josn-server 创建数据库的富查询
  • mockjs 生成数据
  • iview 框架,涉及到两个重要的 API 是PageTablehttps://www.iviewui.com/components/table
  • vuex 作为统一状态管理容器
  • vue 技术

项目本来是很简单的,结果业务越加越多就积重难返了,就不那么容易懂了,刚开始写的代码最能体现出思路,但是不好看,后来进行代码优化合并,就造成理解困难。所以除了注释还把所有的源码放上去以帮助自己和有兴趣的人理解。

一开始我们首先的通过:json-server --watch db.json 命令打开我们生成的假数据,并通过http://localhost:3000/students能看到如下数据:

假数据的制作请参考上篇文章。

最后的实现效果大约是这样的:



上面的那个效果,完全是修改好的版本。还好我在写的时候把前期的代码留下来了,当做个思路入门,现讲这个简易版的。

一、入口文件配置

main.js 作为入口文件在这里配置 iview 和 vuex。

import Vue from "vue";
import App from "./App.vue";
import Vuex from "vuex";
import iview from 'iview';
import store from "./store/index";
// Vuex作为插件使用
Vue.use(Vuex);
// iview作为插件使用
// 子组件可直接使用iview里面的组件
Vue.use(iview);

new Vue({
    el:"#app",
    render(h){
        return h(App);
    },
    store:new Vuex.Store(store)
});

相应的 index.html 就是这样:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue 学习</title>
<link rel="stylesheet" href="./styles/iview.css">
</head>
<body>
    <div id="app"></div>
    <script src = "./virtual/bundle.js"></script>
</body>
</html>
二、页面框架搭建

App.vue 搭建页面和事件处理

<template>
    <div>
        <div class="box">
            <h1>学生表格</h1>
            <!-- 表格 stripe隔行变色 border单个单元格有边框-->
            <!-- draggable开启拖拽 并使用拖拽的配套事件@on-drag-drop="drag"-->
            <!--  :columns定义表头 :data表格数据-->
            <Table stripe border draggable @on-drag-drop="drag" :columns="columns" :data="data"></Table>
            <!-- 分页 :total总页数current当前页面,更改页面的点击事件@on-change-->
            <Page :total="total" :current="page" @on-change="changePage"/>
        </div>
    </div>
</template>

<script>
    export default {
        // 组件创建前进行数据初始化,发送Ajax
        beforeCreate(){
            this.$store.dispatch("stu/loadData",{page:1});
        },
        methods:{
            // 更改page触发事件
            changePage(page){
                this.$store.dispatch("stu/loadData",{page});
            },
            // 拖拽事件
            drag(index1, index2){
                this.$store.commit("stu/drag",{index1,index2});
            }
        },
        computed:{
            columns(){
               return this.$store.state.stu.arr;
            },
            data(){
                return this.$store.state.stu.data;
            },
            total(){
                return this.$store.state.stu.total;
            },
            page(){
                return this.$store.state.stu.page;
            }
        }
    }
</script>

<style scoped>
.box{
    width: 1000px;
    margin:50px auto;
    text-align:center;
}
</style>
三、vuex处理数据

stu.js 标准的 vuex 数据结构。

// 引入axios用来发送Ajax
import axios from "axios";
// 以下标准的Vuex
export default {
    // 命名空间
    namespaced :true,
    // 统一的状态容器
    state :{
        // 表格的表头
        arr : [
            {title:"id",key:"id",render: (h, params) => {
                // 附赠的render可以替换前面的内容
                // 列内容全部在params的row里面
                return h('div', [
                    h('i', params.row.id)
                ]);
            }},
            {title:"name",key:"name",align:"center"},
            // sortable: true开启字段排序
            {title:"age",key:"age",sortable: true},
            {title:"province",key:"province"},
            {title:"sex",key:"sex"},
            {title:"education",key:"education"}
        ],
        // 表格的数据
        data  : [],
        // 表格的总页数
        total : 0,
        // 表格的当前页面
        page  : 1
    },
    // 同步请求commit
    mutations:{
        // 数据的初始化
        initdata(state,{data,total,page}){
            state.data = data;
            state.total = Number(total);
            state.page = page;
        },
        // 拖拽排序
        drag(state,{index1,index2}){
            console.log(typeof index1,typeof index2);
            state.data = state.data.map((item,index)=>{
                if(index == index1){
                    return state.data[index2]
                }else if(index == index2){
                    return state.data[index1]
                }
                return item;
            });
        }
    },
    // 异步请求dispatch
    actions:{
        // 初始化发送Ajax请求数据
        loadData({commit},{page}){
            axios.get(`http://localhost:3000/students?_page=${page}&_limit=10`).then(data=>{
                commit("initdata",{data:data.data,total:data.headers["x-total-count"],page});
                console.log(data.headers["x-total-count"]);
            })
        }
    }
}

把 stu.js 进行暴露到全局,以和 App.vue 进行通信:

import stu from "./stu.js";
export default {
    modules:{
        stu
    }
}
四、改进版

上面的代码,明显功能还不够完善,基本没啥技术活。下面进行改进。
stu.js 是改进最多了,改动痕迹可以和上面的初始版本对比,初始版本里面没有的,我也在新版本对改进的地方进行了注释,并没有完全擦除掉改动痕迹。

// 引入axios用来发送Ajax
import axios from "axios";
// 以下标准的Vuex
export default {
    // 命名空间
    namespaced :true,
    // 统一的状态容器
    state :{
        // 表格的表头
        arr : [
            {title:"序号",key:"id",render: (h, params) => {
                // 附赠的render可以替换前面的内容
                // 列内容全部在params的row里面
                return h('div', [
                    h('i', params.row.id)
                ]);
            },align:"center"},
            {title:"头像",key:"avatar",align:"center",render(h,params){
                return h('div', {style:{width:'50px',height:'50px',backgroundSize:"contain",backgroundImage:`url(${params.row.avatar})`,margin:"5px auto"}},"")
            }},
            // 表格内容默认左对齐,align:"center"居中
            {title:"姓名",key:"name",align:"center"},
            // sortable: true开启字段排序
            {title:"年龄",key:"age",sortable: true,align:"center"},
            // 表格筛选是否是共青团员
            {
                title:"共青团员",
                key:"member",
                align:"center",
                // 筛选共青团
                filters: [
                            {
                                // label显示筛选条件
                                // value是其对应的值,不一定是Boolean值
                                label: "是共青团员",
                                value: true
                            },
                            {
                                label: "不是共青团员",
                                value: false
                            }
                        ],
                // 是否开启多条件筛选默认打开
                filterMultiple: false,
                // 筛选函数必须
                filterMethod (value, row) {
                    if (value) {
                        return row.member === "是";
                    } else{
                        return row.member === "否";
                    }
                }
            },
            {title:"省份",key:"province",align:"center"},
            {title:"性别",key:"sex",align:"center"},
            {title:"教育情况",key:"education",align:"center"},
            {title:"民族",key:"national",align:"center"},
        ],
        // 表格的数据
        data  : [],
        // 表格的总页数
        total : 0,
        // 表格的当前页面
        page  : 1,
        // 每页显示条数
        pagesize : 5,
        // Ajax发送的民族查询接口
        national : "",
        // 模糊查询的输入值
        inputValue :""
    },
    // 同步请求commit
    mutations:{
        // 数据的初始化
        initdata(state,{data,total,page}){
            state.data = data;
            state.total = Number(total);
            state.page = page;
        },
        // 拖拽排序
        drag(state,{index1,index2}){
            console.log(typeof index1,typeof index2);
            state.data = state.data.map((item,index)=>{
                if(index == index1){
                    return state.data[index2]
                }else if(index == index2){
                    return state.data[index1]
                }
                return item;
            });
        }
    },
    // 异步请求dispatch
    actions:{
        // 初始化发送Ajax请求数据
        loadData({commit,dispatch,state},{page,pagesize}){
            state.page = page;
            // 因为loadData检测两个事件,所以防止 pagesize 不存在
            pagesize ? state.pagesize = pagesize : 5;
            dispatch("dispatchAjax");
            // let national = state.national ? "&"+state.national : "";
            // console.log(national)
            // axios.get(`http://localhost:3000/students?_page=${page}&_limit=${state.pagesize}${national}`).then(data=>{
            //  commit("initdata",{data:data.data,total:data.headers["x-total-count"],page});
            //  console.log(data.headers["x-total-count"]);
            // });
        },
        checkedArr({commit,dispatch,state},{checkedArr}){
            // 筛选民族的时候把数组给转化成URL
            state.national = checkedArr.length ? "&"+checkedArr.map(item=>`national=${item}`).join("&") : "";
            state.page = 1;
            dispatch("dispatchAjax");
            // axios.get(`http://localhost:3000/students?_page=${state.page}&_limit=${state.pagesize}${state.national}`).then(data=>{
            //  commit("initdata",{data:data.data,total:data.headers["x-total-count"],page:state.page});
            // });
        },
        // 模糊查询的接口
        inputChange({commit,dispatch,state},{inputValue}){
            state.page = 1;
            state.inputValue = inputValue ? `&q=${inputValue}` : "";
            dispatch("dispatchAjax");
            // axios.get(`http://localhost:3000/students?_page=_page=${state.page}&_limit=${state.pagesize}&q=${state.inputValue}`).then(data=>{
            //  commit("initdata",{data:data.data,total:data.headers["x-total-count"],page:state.page});
            // });
        },
        // 把全部的Ajax请求提取出来
        dispatchAjax({commit,state}){
            axios.get(`http://localhost:3000/students?_page=${state.page}&_limit=${state.pagesize}${state.national}${state.inputValue}`).then(data=>{
                commit("initdata",{data:data.data,total:data.headers["x-total-count"],page:state.page});
            })
        }
    }
}

主文件 App.vue 只是稍稍增加了一点功能:

<template>
    <div>
        <div class="box">
            <div>
                查询数组:{{checkGroup}}
                <!-- 筛选 -->
                <Row>
                    <Col :span="2">筛选民族:</Col>
                    <Col :span="22">
                        <CheckboxGroup
                        v-model="checkGroup"
                        @on-change="checkedgroup"> 
                            <Checkbox v-for="i in national" :key="i" :label="i"></Checkbox>
                        </CheckboxGroup>
                    </Col>
                </Row>
            </div>
            <div>
                <Row>
                    <Col span="4">
                        <Input placeholder="模糊查询" ref="inputTxt"/>
                    </Col>
                    <Col span="2">
                        <Button @click="inputChange">查询</Button>
                    </Col>
                    <Col span="2">
                        <Button @click="clear">清空</Button>
                    </Col>
                </Row>
            </div>
            <h1>学生表格</h1>
            <!-- 表格 stripe隔行变色 border单个单元格有边框-->
            <!-- draggable开启拖拽 并使用拖拽的配套事件@on-drag-drop="drag"-->
            <!--  :columns定义表头 :data表格数据-->
            <Table
            stripe
            border
            draggable
            @on-drag-drop="drag"
            :columns="columns"
            :data="data"
            />
            <!-- 分页 :total总页数current当前页面,更改页面的点击事件@on-change-->
            <Page
            :total="total"
            :current="page"
            :page-size="pageCount"
            :page-size-opts="[3,5,8,10]"
            @on-change="changePage"
            @on-page-size-change="changeSize"
            show-total
            show-elevator
            show-sizer
            />
        </div>
    </div>
</template>

<script>
    import national from "./national.js";
    export default {
        data(){
            return {
                national,
                checkGroup:[]
            }
        },
        // 组件创建前进行数据初始化,发送Ajax
        beforeCreate(){
            this.$store.dispatch("stu/loadData",{page:1});
        },
        methods:{
            // 更改page触发事件
            changePage(page){
                this.$store.dispatch("stu/loadData",{page});
            },
            // 拖拽事件
            drag(index1, index2){
                this.$store.commit("stu/drag",{index1,index2});
            },
            // 每页显示条数
            changeSize(pagesize){
                this.$store.dispatch("stu/loadData",{page:1,pagesize});
            },
            // 民族筛选时,选中的数据作为数据发送出去
            checkedgroup(checkedArr){
                this.$store.dispatch("stu/checkedArr",{checkedArr});
            },
            // 根据输入框的内容发送Ajax进行查找
            inputChange(){
                this.$store.dispatch("stu/inputChange",{inputValue:this.$refs.inputTxt.currentValue});
            },
            // 清除输入框的内容和重新发送Ajax请求
            clear(){
                this.$refs.inputTxt.currentValue = "";
                this.$store.dispatch("stu/inputChange",{inputValue:""});
            }
        },
        computed:{
            columns(){
               return this.$store.state.stu.arr;
            },
            data(){
                return this.$store.state.stu.data;
            },
            total(){
                return this.$store.state.stu.total;
            },
            page(){
                return this.$store.state.stu.page;
            },
            pageCount(pagesize){
                return this.$store.state.stu.pagesize;
            }
        }
    }
</script>

<style scoped>
.box{
    width: 1000px;
    margin:50px auto;
    text-align:center;
}
.ivu-page{
    margin-top:20px;
}
</style>

补充一下上面iview 框架 Table 表格里面 render 的用法。render 是用来自定义渲染列,使用的是 Vue 的 Render 函数。会传入两个参数,第一个是 h,第二个为对象,包含 row、column 和 index,分别指当前行数据,当前列数据,当前行索引。

现在介绍的是 h 函数有三个参数时候的使用方法,中间参数能配置的东西。

h(
    'Button', 
    {
        //配置框架标签自带属性
        props: {
            type: "primary",
            size: "small"
        }
    },
    params.row
);
h(
    //添加标签
    'img', 
    {
        //w3c官方标签的属性类似src,herf,style,id,class等
        attrs: {
            style:"margin:'20px'";
        },
        //sytle标签可以单独写出来
        {
            width;"200px";
        },
        //添加事件
        on: {
            click: (e) => {
                e.stopPropagation();
            }
        },
        'class': {
            'cur': params.row.id === 2
        },
        //domProps添加节点属性
        domProps: {
            innerHTML: '...'
        }
    },
    //写入标签的内容
    params.row.content
);

文章完成于:
2019.09.04

举报

相关推荐

0 条评论