前言:使用到的技术
- josn-server 创建数据库的富查询
- mockjs 生成数据
- iview 框架,涉及到两个重要的 API 是
Page
和Table
:https://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
网友评论