vue笔记(十一): table表格组件
table表格
场景:后台管理系统的数据展示基本都是由表格构成,原本想做个element那样的表格,无奈能力有限,所以暂时写了这个满足我自己日常使用的表格
思路:
之前看过几篇相关的博客文章,总结了一点思路,因为经验有限,暂时先以实现为主
自定义table数据和表头header数据,header[子数据]里key键的值对应table[子数据]的某个键名字,渲染的时候利用这个联系显示对应的tables数据
另外也实现了一个左边操作列冻结,是另外单独写了一个元素,放在表格外,用绝对定位在右侧,冻结的列是写死的只冻结操作列,默认不显示,props参数开启冻结列,右侧的冻结列就会显示,覆盖在表格上面
先看看运行后的效果
自定义数据
isZebra: true,是否显示斑马线,默认显示
isRightfrozen: false,是否冻结操作栏,默认false
columns:title,表头名字,key指定列值,width设置列宽度,不写默认自动宽度
js
columns: [
{
title: "姓名",
key: "name",
width: "200"
},
{
title: "年龄",
key: "age",
},
{
title: "性别",
key: "sex",
},
{
title: "地址",
key: "address",
},
],
columns: [
{
title: "姓名",
key: "name",
width: "200"
},
{
title: "年龄",
key: "age",
},
{
title: "性别",
key: "sex",
},
{
title: "地址",
key: "address",
},
],
data: 表格数据
js
data: [
{
id: 0,
name: "小刘",
age: 19,
sex: "男",
address: "广东深圳"
},
],
data: [
{
id: 0,
name: "小刘",
age: 19,
sex: "男",
address: "广东深圳"
},
],
运行
一定要按照约定配置参数
新建table.vue
html
<template>
<div class="table">
<div class="table-main">
<table class="table-box" ref="opentablebox">
<tr>
<!-- 选择框 -->
<th >
<div class="table-check-all" >
<input class="check-box" type="checkbox" :checked="selectAlls" @click="checkAll($event)">
</div>
</th>
<!-- 循环输出表头 -->
<th v-for="item in columns" :class="[item.width>0 ? ' ':'otbi-item-width']">
<div class="otbi-item" :style="{'width':`${item.width}px`}">
{{item.title}}
</div>
</th>
<!-- 操作列表头 -->
<th>
<div class="otbi-tool">操作</div>
</th>
</tr>
<tr v-for= "(item,index) in data" :class="['table-box-item',index % 2 == 0&&isZebra ? 'table-item-zebra' : '']" >
<!-- 选择框 -->
<td>
<div class="table-check-item">
<input class="check-box" type="checkbox" :checked="selectItems" @click="checkItem(item.id,$event)">
</div>
</td>
<!-- 循环输出表头key值对应的table数据 -->
<td v-for="items in columns" :class="[!items.width?'otbi-item-width':'']">
<div class="otbi-item" :style="{'width':`${items.width}px`}">
{{item[items.key]}}
</div>
</td>
<!-- 操作列 -->
<td>
<div class="otbi-tool" >
<span class="otbi-tool-edit" @click="onEdit(item.id)">编辑</span>
<span class="otbi-tool-remove" @click="onRemove(item.id)">删除</span>
</div>
</td>
</tr>
</table>
</div>
<!-- 冻结的操作列 -->
<div class="otbi-tool-frozen" v-if="isRightfrozen">
<div class="otbi-tool-header">操作</div>
<div v-for= "(item,index) in data" :class="['table-line table-box-item',index % 2 == 0&&isZebra ? 'table-item-zebra' : '']" >
<div>
<div :class="['otbi-tool',index % 2 == 0&&isZebra ? 'table-item-zebra' : '']" >
<span class="otbi-tool-edit" @click="onEdit(item.id)">编辑</span>
<span class="otbi-tool-remove" @click="onRemove(item.id)">删除</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Table',
props: {
//斑马线,默认true
isZebra: {
type: Boolean,
default: true
},
//冻结右侧操作列,默认不冻结
isRightfrozen: {
type: Boolean,
default: false
},
columns: {
type: Array,
default: function(data){
return data;
}
},
data: {
type: Array,
default: function(data){
return data;
}
},
},
data () {
return {
selectAlls: false,//全选框绑定的chacked
selectItems: false,//单选框绑定的chacked
selectList: [],//选中的id数组
}
},
methods: {
//点击单选框
checkItem(id,e){
if(e.target.checked){
this.selectList.push(id);
if(this.selectList.length == this.data.length){
this.selectAlls = true;
}
}else{
this.selectAlls = false;
let index = this.selectList.indexOf(id);
this.selectList.splice(index,1)
}
// 提交选中集合到父组件
this.onChange();
},
//点击全选框
checkAll(e){
if(e.target.checked){
this.selectAlls = true;
this.selectItems = true;
this.selectList = [];
this.data.forEach((item)=>{
this.selectList.push(item.id)
})
}else{
this.selectAlls = false;
this.selectList = [];
this.selectItems = false
}
// 提交选中集合到父组件
this.onChange();
},
//编辑按钮事件
onEdit(id){
this.$emit('onEdit',id)
},
//删除按钮事件
onRemove(id){
this.$emit('onRemove',id)
},
//点击选框时把选中的id数组提交给父组件
onChange(){
this.$emit('onChange',this.selectList)
}
}
}
</script>
<style>
.table{
width: 100%;
box-sizing: border-box;
padding: 15px;
position: relative;
}
.table-main{
width: inherit;
position: relative;
overflow: auto;
}
.table-box{
width: inherit;
}
.table-check-all{
padding: 8px 0;
}
.table-check-all,.table-check-item{
display: flex;
align-items: center;
width: 40px;
text-align: left;
}
.check-box[type=checkbox]{
width: 17px;
height: 17px;
border: 1px #dcdfe6 solid!important;
border-radius: 2px;
}
.check-box[type=checkbox]:checked::before {
content: "✓";
color: #fff;
font-size: 8px;
font-weight: bold;
padding: 2px 4px;
border-radius: 3px;
background: #f56c6c;
}
tr{
width: 100%;
border-bottom: 1px #ebeef5 solid;
box-sizing: border-box;
display: flex;
padding: 0 10px;
}
.table-line{
border-bottom: 1px #ebeef5 solid;
}
tr th{
box-sizing: border-box;
text-align: left;
padding: 8px 0;
font-size: var(--font-size-base);
font-weight: bold;
color: #999;
}
tr td{
display: flex;
flex-wrap: nowrap;
overflow-y: auto;
align-items: center;
box-sizing: border-box;
font-weight: 400;
font-size: 14px;
color: #666;
}
.otbi-item-width{
flex: 1;
}
.otbi-tool{
min-width: 110px;
padding: 8px;
display: flex;
justify-content: space-between;
}
.otbi-tool span{
display: inline-block;
font-size: var(--font-size-sm);
padding: 5px 11px;
border-radius: 4px;
cursor: pointer;
}
.otbi-tool-edit{
color: #666;
border: 1px #dcdfe6 solid;
}
.otbi-tool-edit:hover{
background: #ecf5ff;
color: #1890ff;
border: 1px #1890ff solid;
}
.otbi-tool-remove{
color: #ffffff;
background: #f56c6c;
border: 1px #f56c6c solid;
}
.otbi-tool-remove:hover{
background: rgba(245, 108, 108, 0.7);
border: 1px rgba(245, 108, 108, 0.7) solid;
}
.otbi-item{
min-width: 100px;
width: 100%;
padding: 8px;
display: flex;
flex-wrap: ;
box-sizing: border-box;
}
.table-box-item:hover{
background: #f5f7fa;
}
.otbi-tool-header{
box-sizing: border-box;
text-align: left;
padding: 16px 8px 19px 8px;
font-size: var(--font-size-base);
font-weight: bold;
color: #999;
}
.otbi-tool-frozen{
background: #fff;
position:absolute;
top: 16px;
right: 15px;
padding-right: 10px;
z-index: 999;
border-left: 1px #eee solid;
}
.otbi-tool-header-frozen{
background: #fff;
position:;
top: 15px;
right: 15px;
padding-right: 10px;
margin-right: 7px;
z-index: 999;
border-left: 1px #eee solid;
box-shadow: -3px 0px 10px 0px #eee;
}
/*斑马线*/
.table-item-zebra{
background: #fafafa;
}
</style>
<template>
<div class="table">
<div class="table-main">
<table class="table-box" ref="opentablebox">
<tr>
<!-- 选择框 -->
<th >
<div class="table-check-all" >
<input class="check-box" type="checkbox" :checked="selectAlls" @click="checkAll($event)">
</div>
</th>
<!-- 循环输出表头 -->
<th v-for="item in columns" :class="[item.width>0 ? ' ':'otbi-item-width']">
<div class="otbi-item" :style="{'width':`${item.width}px`}">
{{item.title}}
</div>
</th>
<!-- 操作列表头 -->
<th>
<div class="otbi-tool">操作</div>
</th>
</tr>
<tr v-for= "(item,index) in data" :class="['table-box-item',index % 2 == 0&&isZebra ? 'table-item-zebra' : '']" >
<!-- 选择框 -->
<td>
<div class="table-check-item">
<input class="check-box" type="checkbox" :checked="selectItems" @click="checkItem(item.id,$event)">
</div>
</td>
<!-- 循环输出表头key值对应的table数据 -->
<td v-for="items in columns" :class="[!items.width?'otbi-item-width':'']">
<div class="otbi-item" :style="{'width':`${items.width}px`}">
{{item[items.key]}}
</div>
</td>
<!-- 操作列 -->
<td>
<div class="otbi-tool" >
<span class="otbi-tool-edit" @click="onEdit(item.id)">编辑</span>
<span class="otbi-tool-remove" @click="onRemove(item.id)">删除</span>
</div>
</td>
</tr>
</table>
</div>
<!-- 冻结的操作列 -->
<div class="otbi-tool-frozen" v-if="isRightfrozen">
<div class="otbi-tool-header">操作</div>
<div v-for= "(item,index) in data" :class="['table-line table-box-item',index % 2 == 0&&isZebra ? 'table-item-zebra' : '']" >
<div>
<div :class="['otbi-tool',index % 2 == 0&&isZebra ? 'table-item-zebra' : '']" >
<span class="otbi-tool-edit" @click="onEdit(item.id)">编辑</span>
<span class="otbi-tool-remove" @click="onRemove(item.id)">删除</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'Table',
props: {
//斑马线,默认true
isZebra: {
type: Boolean,
default: true
},
//冻结右侧操作列,默认不冻结
isRightfrozen: {
type: Boolean,
default: false
},
columns: {
type: Array,
default: function(data){
return data;
}
},
data: {
type: Array,
default: function(data){
return data;
}
},
},
data () {
return {
selectAlls: false,//全选框绑定的chacked
selectItems: false,//单选框绑定的chacked
selectList: [],//选中的id数组
}
},
methods: {
//点击单选框
checkItem(id,e){
if(e.target.checked){
this.selectList.push(id);
if(this.selectList.length == this.data.length){
this.selectAlls = true;
}
}else{
this.selectAlls = false;
let index = this.selectList.indexOf(id);
this.selectList.splice(index,1)
}
// 提交选中集合到父组件
this.onChange();
},
//点击全选框
checkAll(e){
if(e.target.checked){
this.selectAlls = true;
this.selectItems = true;
this.selectList = [];
this.data.forEach((item)=>{
this.selectList.push(item.id)
})
}else{
this.selectAlls = false;
this.selectList = [];
this.selectItems = false
}
// 提交选中集合到父组件
this.onChange();
},
//编辑按钮事件
onEdit(id){
this.$emit('onEdit',id)
},
//删除按钮事件
onRemove(id){
this.$emit('onRemove',id)
},
//点击选框时把选中的id数组提交给父组件
onChange(){
this.$emit('onChange',this.selectList)
}
}
}
</script>
<style>
.table{
width: 100%;
box-sizing: border-box;
padding: 15px;
position: relative;
}
.table-main{
width: inherit;
position: relative;
overflow: auto;
}
.table-box{
width: inherit;
}
.table-check-all{
padding: 8px 0;
}
.table-check-all,.table-check-item{
display: flex;
align-items: center;
width: 40px;
text-align: left;
}
.check-box[type=checkbox]{
width: 17px;
height: 17px;
border: 1px #dcdfe6 solid!important;
border-radius: 2px;
}
.check-box[type=checkbox]:checked::before {
content: "✓";
color: #fff;
font-size: 8px;
font-weight: bold;
padding: 2px 4px;
border-radius: 3px;
background: #f56c6c;
}
tr{
width: 100%;
border-bottom: 1px #ebeef5 solid;
box-sizing: border-box;
display: flex;
padding: 0 10px;
}
.table-line{
border-bottom: 1px #ebeef5 solid;
}
tr th{
box-sizing: border-box;
text-align: left;
padding: 8px 0;
font-size: var(--font-size-base);
font-weight: bold;
color: #999;
}
tr td{
display: flex;
flex-wrap: nowrap;
overflow-y: auto;
align-items: center;
box-sizing: border-box;
font-weight: 400;
font-size: 14px;
color: #666;
}
.otbi-item-width{
flex: 1;
}
.otbi-tool{
min-width: 110px;
padding: 8px;
display: flex;
justify-content: space-between;
}
.otbi-tool span{
display: inline-block;
font-size: var(--font-size-sm);
padding: 5px 11px;
border-radius: 4px;
cursor: pointer;
}
.otbi-tool-edit{
color: #666;
border: 1px #dcdfe6 solid;
}
.otbi-tool-edit:hover{
background: #ecf5ff;
color: #1890ff;
border: 1px #1890ff solid;
}
.otbi-tool-remove{
color: #ffffff;
background: #f56c6c;
border: 1px #f56c6c solid;
}
.otbi-tool-remove:hover{
background: rgba(245, 108, 108, 0.7);
border: 1px rgba(245, 108, 108, 0.7) solid;
}
.otbi-item{
min-width: 100px;
width: 100%;
padding: 8px;
display: flex;
flex-wrap: ;
box-sizing: border-box;
}
.table-box-item:hover{
background: #f5f7fa;
}
.otbi-tool-header{
box-sizing: border-box;
text-align: left;
padding: 16px 8px 19px 8px;
font-size: var(--font-size-base);
font-weight: bold;
color: #999;
}
.otbi-tool-frozen{
background: #fff;
position:absolute;
top: 16px;
right: 15px;
padding-right: 10px;
z-index: 999;
border-left: 1px #eee solid;
}
.otbi-tool-header-frozen{
background: #fff;
position:;
top: 15px;
right: 15px;
padding-right: 10px;
margin-right: 7px;
z-index: 999;
border-left: 1px #eee solid;
box-shadow: -3px 0px 10px 0px #eee;
}
/*斑马线*/
.table-item-zebra{
background: #fafafa;
}
</style>
调用
js
// data数据和columns数据用的上面讲解自定义参数的数据
<table @onEdit="onEdit" @onRemove="onRemove" @onChange="onChange" :columns="columns" :data="data"> </table>
//编辑按钮触发事件
onEdit(id){
console.log(id)//正常输入
},
//删除按钮触发事件
onRemove(id){
console.error(id)//error输出红色错误样式信息
},
//点击选框事件
onChange(data){
console.warn(data)//warn输出黄色警告样式信息
},
// data数据和columns数据用的上面讲解自定义参数的数据
<table @onEdit="onEdit" @onRemove="onRemove" @onChange="onChange" :columns="columns" :data="data"> </table>
//编辑按钮触发事件
onEdit(id){
console.log(id)//正常输入
},
//删除按钮触发事件
onRemove(id){
console.error(id)//error输出红色错误样式信息
},
//点击选框事件
onChange(data){
console.warn(data)//warn输出黄色警告样式信息
},
运行
都正常输出了
下面看看冻结操作列
设置:isRightfrozen="true"
js
<table :isRightfrozen="true" @onEdit="onEdit" @onRemove="onRemove" @onChange="onChange" :columns="columns" :data="data"> </table>
<table :isRightfrozen="true" @onEdit="onEdit" @onRemove="onRemove" @onChange="onChange" :columns="columns" :data="data"> </table>
运行
此组件代码写完还未优化,适合学习交流用
本文到此结束。
反馈信息
INFO