vue实现自定义表格列
在我们开发PC端的项目使用表单时,尤其是crm系统,应该经常会遇到这样的需求, 用户需要根据设置来自定义显示列。 查了element的官方文档, 并没有此类组件, 所以手动封装了一个简单的组件, 希望能在大家开发此类需求时能够有所帮助。
效果图
具体效果图如下:
自定义显示列 (可实现拖拽进行排序,点击选中,再次点击取消选中)

按照用户已设置好的字段排序/显示/隐藏每一列

setTable组件
首先实现拖拽排序的话我们需要借助一个插件:
npm install vuedraggable -S
具体的组件代码如下, 代码内已写有详细的注释,在这里就不过多赘述了。。
setTable.vue
<template>
<div>
<el-dialog title="自定义显示列" :visible.sync="dialogVisible" width="50%">
<div class="select-menus menus-box">
<p class="menus-title">拖动区块调整显示顺序</p>
<div class="menus-content">
<draggable v-model="selected" @update="datadragEnd" :options="{animation:500}">
<transition-group>
<div v-for="menu in selected" :key="menu.field" class="drag-item item">{{menu.name}}</div>
</transition-group>
</draggable>
</div>
</div>
<div class="menus-container menus-box" v-if="fields.length">
<p class="menus-title">选择显示列</p>
<div class="menus-content">
<div
class="item"
:class="{active:menu.active}"
v-for="menu of fields"
:key="menu.field"
@click="onSelect(menu)"
>{{menu.name}}</div>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="onSave">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import draggable from "vuedraggable";
import { getFields, setFields, getFieldControl } from "@/api/user";
export default {
name: "setTable",
inject: ["reload"],
props: {
types: String,
},
components: {
draggable,
},
data() {
return {
dialogVisible: false,
fields: [],//全部菜单
selected: [],//已选中菜单
};
},
watch: {
selected: {
handler(oldVal, newVal) {
if (this.fields.length === 0) {
return;
}
newVal.map((i) => {
this.fields.map((j) => {
if (i.field === j.field) {
// 如果已选中数组内已有相同字段, 则active为true。active主要用来控制全部菜单选中/未选中的样式
j.active = true;
}
});
});
},
},
},
mounted() {
//为了防止火狐浏览器拖拽的时候以新标签打开
document.body.ondrop = function (event) {
event.preventDefault();
event.stopPropagation();
};
},
methods: {
async getData() {
// 获取全部菜单数据
const { data: fields } = await getFields({
types: this.types,
});
fields.map((item) => {
// 由于服务器并没有返回active字段, 为此需要每一条数据增加active字段, 来控制选中的样式
item.active = false;
});
this.fields = fields;
},
async getFields() {
// 获取用户已选中的菜单, 为了再次打开设置时能够把上次选中菜单回显到页面,方便用户再次修改
let fields = await getFieldControl({
account_id: this.$store.state.user.token.account_id,
userid: this.$store.state.user.token.userid,
types: this.types,
});
this.$nextTick(() => {
this.selected.push(...fields.data);
});
},
async onSave() {
// 保存已选中菜单
await setFields({
account_id: this.$store.state.user.token.account_id,
userid: this.$store.state.user.token.userid,
types: this.types,
content: this.selected,
});
this.reload(); //刷新页面
},
async open() {
// 打开设置窗口时清空数据,并再次请求获取最新数据
this.fields = [];
this.selected = [];
this.dialogVisible = true;
await this.getData();
await this.getFields();
},
onSelect(item) {
// 判断已选中菜单内是否已有点击选择的菜单
let findex = this.selected.findIndex((i) => {
return item.field === i.field;
});
if (findex === -1) {
// 如果已选中菜单内没有, 则添加到最后一条
this.selected.push(item);
} else {
// 如果已选中已有,则点击时应该对其移除,并把active设置为false, 改变其选中的样式
item.active = false;
this.selected.splice(findex, 1);
}
},
datadragEnd(evt) {
// 拖动排序
evt.preventDefault();
},
},
};
</script>
<style lang="scss" scoped>
/* 全部菜单 */
.menus-container {
margin-top: 20px;
.menus-content {
.item {
color: #575757;
background: rgba(238, 238, 238, 1);
border: 1px solid rgba(220, 220, 220, 1);
border-radius: 2px 0px 0px 2px;
}
}
}
/* 菜单通用样式 */
.menus-box {
.menus-title {
margin-top: 10px;
line-height: 32px;
}
.menus-content {
display: flex;
flex-wrap: wrap;
.item {
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 8px;
margin: 10px;
border-radius: 3px;
}
.active {
color: #fff;
background: rgba(72, 153, 229, 1);
border-radius: 2px 0px 0px 2px;
}
}
}
/* 已选菜单 */
.select-menus {
.menus-content {
.item {
margin: 0px;
border-radius: 0;
background: rgba(255, 255, 255, 1);
border: 1px solid rgba(220, 220, 220, 1);
}
}
}
</style>
使用
具体使用如下, 在这里已经隐去不必要的业务代码, 只把最核心实现的代码贴了出来, 以免对大家产生误导..
<template>
<div>
<el-table
ref="multipleTable"
:data="tableData"
height="60vh"
:row-class-name="tableRowClassName"
@selection-change="handleSelectionChange"
@row-click="handleRead"
>
<el-table-column type="selection" min-width="55px;"></el-table-column>
<template v-for="(item,index) of fields">
<el-table-column
v-if="item.field==='name'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='gender'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="8%;"
show-overflow-tooltip
>
<template slot-scope="scope">{{scope.row.gender===1?'男':'女'}}</template>
</el-table-column>
<el-table-column
v-if="item.field==='corp_full_name'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="14%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='corp_name'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="12%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='up_date'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="14%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='position'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='remark_mobiles'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="14%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='source_name'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='address'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='detail_address'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='description'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='remark'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='recordContent'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="14%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='owner_name'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
<el-table-column
v-if="item.field==='follow_time'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="8%;"
show-overflow-tooltip
>
<template slot-scope="scope">
<div v-if="scope.row.follow_time===scope.row.createtime">暂无</div>
<div v-else>{{scope.row.follow_time | formatDate}}</div>
</template>
</el-table-column>
<el-table-column
v-if="item.field==='next_follow_time'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="8%;"
show-overflow-tooltip
>
<template slot-scope="scope">
<div v-if="scope.row.next_follow_time===0">暂无</div>
<div v-else>{{scope.row.next_follow_time | formatDate}}</div>
</template>
</el-table-column>
<el-table-column
v-if="item.field==='createtime'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="8%;"
show-overflow-tooltip
>
<template slot-scope="scope">
<div>{{scope.row.createtime | formatDate}}</div>
</template>
</el-table-column>
<el-table-column
v-if="item.field==='updatetime'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="8%;"
show-overflow-tooltip
>
<template slot-scope="scope">
<div>{{scope.row.updatetime | formatDate}}</div>
</template>
</el-table-column>
<el-table-column
v-if="item.field==='is_record'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
>
<template slot-scope="scope">
<div>{{scope.row.is_record === 0 ? '未跟进' : '已跟进' }}</div>
</template>
</el-table-column>
<el-table-column
v-if="item.field==='if_record'"
:key="index"
:prop="item.field"
:label="item.name"
min-width="10%;"
show-overflow-tooltip
></el-table-column>
</template>
<el-table-column label="操作" min-width="8%;">
<template slot-scope="scope">
<el-button @click="handleRead(scope.row)" type="text">详情</el-button>
</template>
</el-table-column>
<el-table-column align="right" min-width="4%;">
<template slot="header">
<i class="iconfont icongengduo" @click="onMore"></i>
</template>
</el-table-column>
</el-table>
<set-table ref="setting" types="leads"></set-table>
</div>
</template>
<script>
import setTable from "@/components/setTable";
import { getFieldControl } from "@/api/user";
export default {
name: "clues",
components: {
setTable,
},
data() {
return {
fields: [],
};
},
async mounted() {
await this.getFields();
this.clues();
},
methods: {
async getFields() {
let fields = await getFieldControl({
account_id: this.$store.state.user.token.account_id,
userid: this.$store.state.user.token.userid,
types: "leads",
});
this.fields = fields.data;
},
onMore() {
this.$refs.setting.open();
},
},
};
</script>
在这里其实也可以设置成固定的列宽或者通过服务器返回具体的尺寸, 这样的话就不用写这么多的if语句了, 会更加方便简洁..
结束语
其实刚接到这个需求时,感觉挺复杂的, 尤其是需要进行拖动, 还要根据服务器返回不同的字段来进行表单列的排序。 但整体做下来并没有我想象的那么麻烦。 大家在遇到需求时, 也一定不要一直想的太多, 一定要先去尝试, 说不定它并没有你想的那么难..
vue实现自定义表格列的更多相关文章
- vue+element ui 的表格列使用组件
前言:工作中用到 vue+element ui 的前端框架,有这个场景:很多表格的列有许多一样的,所以考虑将列封装为组件.转载请注明出处:https://www.cnblogs.com/yuxiaol ...
- Vue 利用后端的数据字典和Map对象实现表格列字段动态转义的处理方案
1.前言 Vue中,使用el-table组件,经常遇到列字段转义的问题.常规处理方法有以下两种: 方法1:在模板中使用v-if,直接转义.如: <el-table-column label= ...
- vue drag 对表格的列进行拖动排序
用drag实现拖动表格列进行列排序 以下是用到的主要方法 1.dragstart 拖动开始返回目标对象 2.dragenter 拖动过程中经过的对象 3.dragend 拖动结束返回目标对象 ...
- DevExpres表格控件运行时动态设置表格列
本文是系列文章,陆续发表于电脑编程技巧与维护杂志. DevExpres产品是全球享有极高声誉的一流控件套包产品!国内典型用户包括:用友.金蝶.神州数码.工信部.中国石化.汉王科技等众多大中型科技型企业 ...
- Android中使用ListView绘制自定义表格(2)
上回再写了<Android中使用ListView绘制自定义表格>后,很多人留言代码不全和没有数据样例.但因为项目原因,没法把源码全部贴上来.近两天,抽空简化了一下,做了一个例子. 效果图如 ...
- FineUIMvc随笔 - 动态创建表格列
声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. 用户需求 用户希望实现动态创建表格列,在 WebForms 中,我们通过在 Page_Init 中创建列来实现: 但是在 MVC ...
- FineUIMvc随笔(1)动态创建表格列
声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. <FineUIMvc随笔>目录 FineUIMvc随笔(1)动态创建表格列 FineUIMvc随笔(2)怎样在控件中 ...
- Dev_GridView自定义表格
#region 自定义表格 //初始化测斜分析数据表 BandedGridView view = advBandedGridView1 as BandedGridView; view.BeginUpd ...
- element-ui表格列金额显示两位小数
对于金额的显示,大多情况下需要保留两位小数,比如下面的(表格采用 element-ui): 在vue.js中,对文本的处理通常是通过设置一系列的过滤器,过滤器可以用在两个地方:双花括号插值 和 v-b ...
随机推荐
- 集训 T1-找试场
大致题意: 按照给定的指令移动,输出最后到达的点. 若没有走动过则输出(0,0). 基本思路 这题就是模拟,主要是判断指令的时候不太好判断, 先用字符串把指令读取进来,看看第一位是否是数字(如果是数字 ...
- C++ 深搜调错
因为前两天某网站的比赛一个深搜错了,我只得了3等奖,我找不到错误,给别的大佬看他们又嫌恶心.emm……,比赛结束后我自己反思了一下,深搜写错了该怎么办,或者说怎样避免写错. 首先,变量名不要太ex,比 ...
- [转载]Python ImportError: No module named 'requests'解决方法
windows解决办法1.找到easy_install.exe.一般在python的安装路径下的Scripts文件夹中,如C:\Python34\Scripts\easy_install.exe2.从 ...
- NPOI Excel设置样式
在表格导出时,会碰到样式修改的问题,作如下简单归纳: //创建行样式ICellStyle style = workbook.CreateCellStyle();//前景色 ...
- node学习第一天
创建服务器 利用require引入http模块:var http=require("http") 利用http模块创建server服务器; 创建服务器:var server=htt ...
- element-ui的el-progress组件增加修改status状态
需求:实现进度条增长中呈现百分比,达到100%后将el-progress的status设置为“success” 想法:element对于status只给出了'success', 'exception' ...
- Zabbix3.2安装
一.环境 OS: CentOS7.0.1406 Zabbix版本: Zabbix-3.2 下载地址: http://repo.zabbix.com/zabbix/3.2/rhel/7/x86_64/z ...
- dp入门题解
学dp学到自闭(真的判断不出是个dp问题哇) 来看一下最近学的dp简单的题库. 1.01背包问题(P1048) 这个的特点是每种东西只能拿一次. https://www.luogu.com.cn/pr ...
- spring 循环依赖的一次 理解
前言: 在看spring 循环依赖的问题中,知道原理,网上一堆的资料有讲原理. 但今天在看代码过程中,又产生了疑问. 疑问点如下: // 疑问点: 先进行 dependon 判断String[] de ...
- PHP connection_status() 函数
实例 返回连接状态: <?phpswitch (connection_status()){高佣联盟 www.cgewang.comcase CONNECTION_NORMAL:$txt = 'C ...