vue极简代码实现自定义可编辑行及操作按钮的Table表格组件(含源码及演示视频)
父组件通过slot-scope(vue3是scope)获取插槽值到 val, 元素的data-id属性引用该值,以便点击事件时获取该值。点编辑时获取对应的id,获取当前值,开启编辑编辑状态后,将文本框进行赋值,要注意的时,组件在v-if=‘false’时,refs是无法找到。父组件给子组件传值props、动态赋值 refs 对DOM进行操作,slot具名插槽的使用,插槽通过slot-scope给父
·
效果图如下:

涉及到技术点包括:
父组件给子组件传值props、动态赋值 refs 对DOM进行操作,slot具名插槽的使用,插槽通过slot-scope给父组件传值
父组件代码:
<template>
<div class="body">
<div class="table">
<div class="filter font-bold">vue自定义Table表格组件</div>
<div class="padding-left-l padding-right-l">
<my-table :fields="fields" :data="tableData" :opFields="opFields">
<template slot="opField1" slot-scope="val">
<span class="pointer color-blue" @click="share" :data-id="val.recordId">分享</span>
<span class="margin-left-l color-blue pointer">更多</span>
</template>
</my-table>
</div>
</div>
</div>
</template>
<script>
/*
名称:vue自定义Table表格组件
功能:封装Html的table,可直接编辑单元格内容,光标失去焦点时更新表格数据,利用slot插槽绑定操作按钮(编辑,删除、分享等)
涉及到技术点包括:父组件给子组件传值、refs 对DOM进行操作,slot具名插槽的使用,插槽通过slot-scope给父组件传值
作者:唐赢
时间:2023-1-14
*/
import MyTable from '@/components/Table' //引入我们写好的递归组件
export default {
name: 'Main',
components: {
MyTable
},
data () {
return {
tableData: [
{
"id":1,
"name": "关于放假的通知.pdf",
"createUser":"唐赢",
"createTime":"2023-1-15"
},
{
"id":2,
"name": "关于复课的通知.pdf",
"createUser":"唐赢",
"createTime":"2023-2-15",
}
],
fields: [
{title:'名称',fieldName:'name',width:'',canEdit: true},
{title:'创建时间',fieldName:'createTime',width:'15%',canEdit: false},
{title:'创建人',fieldName:'createUser',width:'10%',canEdit: false}
],
opFields : [
{name:'opField1', title:"操作", width:'25%'}
]
}
},
methods: {
share(event) {
let id = event.target.getAttribute("data-id");
alert("您要分享的id是:" + id);
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.body {
display: flex;
justify-content: center;
margin-top: 73px;
width: 100%;
}
.table {
background-color: #fff;
width: 1080px;
min-height: 800px;
box-shadow: 0px 3px 6px rgba(0, 0, 0, .1);
margin-bottom: 10px;
}
.filter {
display: flex;
height: 60px;
align-items:center;
background-color: #fff;
font-size: 18px;
justify-content: center;
border-bottom: 1px solid rgba(0, 0, 0, .2);;
}
</style>
子组件代码
<template>
<table border="0" cellspacing="0" cellpadding="4" bgcolor="#fff" align="left" width="100%" style="line-height:28px">
<tr>
<th v-for="item in fields" align="left" :width="item.width" >{{item.title}}</th>
<th v-for="item in opFields" align="left" :width="item.width" >{{item.title}}</th>
</tr>
<tr v-for="record in data" >
<td v-for="field in fields">
<span v-if="!showInput(record, field)" :ref="'text_' + field.fieldName+'_' + record.id">{{getValue(record, field)}}</span>
<span v-if="!showInput(record, field) && field.canEdit" class="margin-left-l pointer">
<img class="logo-18" src="@/assets/images/edit.png" @click="fileNameEdit" :data-field="field.fieldName" :data-id="record.id"/>
</span>
<input v-if="showInput(record, field)" type="text" v-model="fileName" @blur="fileNameBlur" :ref="'input_' + field.fieldName+'_' + record.id">
</td>
<td v-for="field in opFields">
<slot :name="field.name" :recordId="record.id"></slot>
</td>
</tr>
</table>
</template>
<script>
export default {
name: 'MyTable',
props: {
opFields: {},
fields: {},
data:{}
},
data() {
return {
editMode: false,
editId: 0,
editName:'',
fileName:""
}
},
computed: {
},
methods: {
getValue(record, field) {
return record[field.fieldName];
},
showInput(record, field) {
return record.id == this.editId && field.fieldName == this.editName;
},
fileNameEdit(event) {
let id = event.target.getAttribute("data-id");
let fieldName = event.target.getAttribute("data-field");
this.$nextTick(() => {
console.log('text_' + fieldName + '_' + id)
let value = this.$refs['text_' + fieldName + '_' + id][0].innerHTML;
this.fileName = value;
})
this.editMode = true;
this.editId = id;
this.editName = fieldName;
this.$nextTick(() => {
let value = 'input_' + fieldName + '_' + id;
this.$refs[value][0].focus();
})
},
fileNameBlur(event) {
this.data.forEach((i,index) => {
if (i.id == this.editId) {
i[this.editName] = this.fileName;
}
})
console.log(this.data);
this.editMode = false;
this.editId = 0;
this.editName = "";
console.log(event);
}
}
}
</script>
<style scoped>
td{
border-bottom: 1px solid rgba(0, 0, 0, .1) ;
}
th{
border-bottom: 1px solid rgba(0, 0, 0, .1) ;
}
input {
border-radius: 5px;
padding-left: 10px;
padding-right: 10px;
font-size: 14px;
width: 95%;
height: 25px;
border: 1px solid #0070f9 ;
}
</style>
要点说明:
1.插槽slot
子组件的id值绑定到插槽

父组件通过slot-scope(vue3是scope)获取插槽值到 val, <span>元素的data-id属性引用该值,以便点击事件时获取该值

2.动态赋值refs
对每行不同id,不同字段的dom元素进行ref标识

点编辑时获取对应的id,获取当前值,开启编辑编辑状态后,将文本框进行赋值,要注意的时,组件在v-if=‘false’时,refs是无法找到

更多推荐
所有评论(0)