内容包含:校验。下拉框。输入框。日期控件
效果图
1.代码目录
2.index.js
import SjjEditable from './src/editable.vue'
// import Vue from 'vue'
SjjEditable.install = function (Vue) {
Vue.component(SjjEditable.name, SjjEditable)
}
export default SjjEditable
3.utilsjs
export const getRowIndetity = (row, rowKey) => {
if (!row) throw new Error('row is required when get row identity')
if (typeof rowKey === 'string') {
if (rowKey.indexOf('.') < 0) {
return row[rowKey]
}
let key = rowKey.split('.')
let current = row
for (let i = 0; i < key.length; i++) {
current = current[key[i]]
}
return current
} else if (typeof rowKey === 'function') {
return rowKey.bind(null, row)
}
}
4.editable-column.vue
<template>
<el-table-column v-if="isIndexTypeColumn(type)" :prop="prop" :type="type" :label="label" :width="width" :min-width="minWidth"/>
<el-table-column v-else :prop="prop" :type="type" :label="label" :width="width" :min-width="minWidth" >
<template slot-scope="scope">
<el-form v-if="type && editing && editing[scope.$index] && editing[scope.$index][prop]" :model="scope.row" :rules="rules" @validate="handleValidate" :ref="`form_${scope.$index}_${prop}`">
<el-form-item :prop="type === 'select' ? prop.replace(/(\_*)(text|txt)/ig, '') : prop" class="el-editable-form-item">
<el-input autofocus v-if="type === 'text' || type === 'textarea'" :type="type" v-model="scope.row[prop]" class="el-editable-element" @change="handleChange"/>
<el-date-picker v-else-if="type === 'date' || type === 'datetime'" v-model="scope.row[prop]" :type="type" class="el-editable-element" @change="handleChange" :format="format" :value-format="valueFormat"/>
<el-select v-else-if="type === 'select'" v-model="scope.row[prop.replace(/(\_*)(text|txt)/ig, '')]" class="el-editable-element" @change="handleChange">
<el-option v-for="(o,i) in options" :key="i" :value="o.value" :label="o.label || o.text" :disabled="o.disabled ? true:false"/>
</el-select>
<sjj-currency v-else-if="type === 'currency'" v-model="scope.row[prop]" class="el-editable-element" @change="handleChange"/>
</el-form-item>
</el-form>
<div v-else :class="editedCell&&editedCell[scope.$index]&&editedCell[scope.$index][prop] ? 'is-edited' : ''">{{ scope.row[prop] }}</div>
</template>
</el-table-column>
</template>
<script>
import sjjCurrency from '../../currency/index.js'
import merge from 'element-ui/src/utils/merge'
import { getRowIndetity } from './utils.js'
export default {
name: 'SjjEditableColumn',
props: {
type: {
type: String,
default: ''
},
label: String,
className: String,
labelClassName: String,
prop: String,
width: {},
minWidth: {},
index: [Number, Function],
options: Array,
format: { // 显示在输入框中的格式,默认为yyyy-MM-dd
type: String,
default: 'yyyy-MM-dd'
},
valueFormat: { // 绑定值得格式,默认为yyyy-MM-dd
type: String,
default: 'yyyy-MM-dd'
}
},
components: {
sjjCurrency
},
data () {
return {
validates: false,
editedCell: {}, // 编辑成功过的cell们
validatedRow: {}, // 已编辑的行
validated: {} // 已编辑的cell
}
},
mounted () {
this.validated = this.$parent.$parent.edited
this.validatedRow = this.$parent.$parent.editedRow
},
computed: {
editing () {
return this.$parent.$parent.editing || {}
},
tableData () {
return this.$parent.$parent.tableData || []
},
originData () {
return this.$parent.$parent.originData || []
},
rules () {
return this.$parent.$parent.$props.rules || []
}
},
methods: {
isIndexTypeColumn (type) {
return type === 'index' // ['selection', 'index', 'expand']
},
isDataColumn (type) {
return ['text', 'textarea', 'date', 'datetime', 'select', 'currency'].indexOf(type) > -1
},
handleValidate (prop, validateFlag) {
this.$parent.$parent.setValidateFlag(validateFlag)
if (validateFlag) {
this.editedCell = merge(this.editedCell, this.editing)
let property = prop
for (let rowIdx in this.editing) {
if (this.$props.type === 'select') {
property = this.$props.prop // property带text,prop是rules的属性
}
this.setEditedRow(rowIdx, prop, property)
}
}
},
handleChange (value) {
for (let rowIdx in this.editing) {
this.$emit('change', rowIdx, this.$props.prop, value)
}
},
// validateColumn (rowIdx, value) {
// let prop = this.$props.prop
// if (this.$props.type === 'select') {
// prop = prop.replace(/(\_*)(text|txt)/ig, '')
// }
// this.$refs[`form_${rowIdx}_${prop}`].validate((valid, prop) => {})
// },
setEditedRow (rowIdx, prop, property) {
let value = this.tableData[rowIdx][prop]
let textValue = value
if (this.$props.type === 'select') {
let arr = this.$props.options.filter(o => {
return o.value === value
})
if (arr.length) {
textValue = arr[0].label || arr[0].text
}
}
this.tableData[rowIdx][property] = textValue
if (value !== this.originData[rowIdx][prop]) {
let obj = {}
obj[prop] = value
if (this.$props.type === 'select') {
obj[property] = textValue
}
if (this.validated.hasOwnProperty(rowIdx)) {
this.validated[rowIdx] = merge(this.validated[rowIdx], obj)
} else {
let rowId = getRowIndetity(this.tableData[rowIdx], this.$parent.$parent.$props.rowKey)
obj[this.$parent.$parent.$props.rowKey] = rowId
this.validated[rowIdx] = obj
}
this.validatedRow[rowIdx] = merge({}, this.tableData[rowIdx])
} else {
if (this.editedCell[rowIdx]) {
delete this.editedCell[rowIdx][property]
}
if (this.validated.hasOwnProperty(rowIdx)) {
let equalFlag = true
for (let k in this.validated[rowIdx]) {
if (k === prop || k === property) {
continue
}
if (this.validated[rowIdx][k] !== this.originData[rowIdx][k]) {
equalFlag = false
break
}
}
if (equalFlag) {
delete this.validated[rowIdx]
} else {
delete this.validated[rowIdx][prop]
delete this.validated[rowIdx][property]
}
}
if (this.validatedRow.hasOwnProperty(rowIdx)) {
let equalFlag = true
for (let k in this.validatedRow[rowIdx]) {
if (k === prop || k === property) {
continue
}
if (this.validatedRow[rowIdx][k] !== this.originData[rowIdx][k]) {
equalFlag = false
break
}
}
if (equalFlag) {
delete this.validatedRow[rowIdx]
} else {
this.validatedRow[rowIdx] = merge({}, this.tableData[rowIdx])
}
}
}
this.$parent.$parent.setEdited(this.validated)
this.$parent.$parent.setEditedRow(this.validatedRow)
}
}
}
</script>
<style scoped>
.is-edited {
color: red;
}
/* .sjj-editable-form-item {
margin: 0;
}
.sjj-editable-element.el-input {
line-height: normal;
}
.sjj-editable-form-item /deep/ .el-form-item__content {
line-height: normal;
}
.sjj-editable-form-item /deep/ .el-form-item__error {
position: relative;
}
.sjj-editable-form-item /deep/ .el-input__inner {
height: 0;
line-height: 1;
padding: 15px;
} */
/* >>> .el-table__row {
height: 50px;
}
>>> .el-table td, .el-table th {
padding: 4px 0;
} */
</style>
5.editable.vue
<template>
<div class="el-editable">
<el-table border :data="tableData" @cell-dblclick="handleCellDblClick" :row-key="rowKey" :height="height">
<slot></slot>
</el-table>
</div>
</template>
<script>
import Vue from 'vue'
import merge from 'element-ui/src/utils/merge'
import { getRowIdentity } from 'element-ui/packages/table/src/util'
export default {
name: 'SjjEditable',
props: {
data: {
type: Array,
default: Function,
required: true
},
rowKey: {
type: String,
required: true
},
height: [String, Number],
rules: {
type: Object,
required: true
}
},
data () {
return {
originData: [], // 原始表格数据
editing: {}, // 正在编辑对象
validateFlag: null,
editedRow: {}, // 编辑成功的row
deditedRowData: [], // 编辑成功的行数据集
edited: {}, // 编辑成功的cell
editedData: [], // 编辑成功的单元格数据集
slotChildren: []
}
},
created () {
this.setOriginData(this.data)
},
computed: {
tableData () {
if (!this.data) {
return []
}
let arr = this.data.filter((d, idx) => {
return d
})
return arr
}
},
watch: {
data (newVal, oldVal) {
this.setOriginData(this.data)
}
},
methods: {
setOriginData (val) {
if (!val) {
this.originData = []
} else {
this.originData = val.map((d, idx) => {
let obj = merge({}, d)
return obj
})
}
},
setValidateFlag (val) {
this.validateFlag = val
},
setEditedRow (val) {
this.editedRow = val
},
setEdited (val) {
this.edited = val
},
handleCellDblClick (row, column, cell, event) {
// this.slotChildren = []
// for (let i = 0; i < this.$slots.default.length; i++) {
// console.log(this.$slots.default[i].elm.nodeType)
// if (this.$slots.default[i].elm.nodeType !== 3) {
// this.slotChildren.push(this.$slots.default[i]) // 获得那些插入的按钮
// }
// }
// console.log(this.slotChildren[2])
//if (Object.keys(this.editing).length && !this.validateFlag) {
//return
//}
this.editing = {}
let rowIdx = null
for (let i = 0; i < this.tableData.length; i++) {
let d = this.tableData[i]
if (getRowIdentity(d, this.rowKey) === getRowIdentity(row, this.rowKey)) {
rowIdx = i
}
}
if (rowIdx !== null) {
let obj = {}
obj[column.property] = true
Vue.set(this.editing, rowIdx, obj)
}
},
getEditedRowData () {
this.editedRowData = []
for (let rowIdx in this.editedRow) {
this.editedRowData.push(this.editedRow[rowIdx])
}
return this.editedRowData
},
getEditedData () {
this.editedData = []
for (let rowIdx in this.edited) {
this.editedData.push(this.edited[rowIdx])
}
return this.editedData
},
isPass () {
return this.validateFlag === null || this.validateFlag === true
}
}
}
</script>
6.使用
<template>
<div class="phone">
<el-button @click="getEditedRowData">查看已编辑行数据</el-button>
<el-button @click="getEditedData">查看已编辑单元格数据</el-button>
<sjj-editable :data="tableData" row-key="rowId" :rules="rules" ref="tb" style="margin-top: 20px">
<sjj-editable-column type="index" label="序号" width="100"></sjj-editable-column>
<sjj-editable-column prop="date" label="日期" type="date" @change="handleChangeDate"></sjj-editable-column>
<sjj-editable-column prop='name' label="姓名" type="text" @change="handleChangeName"></sjj-editable-column>
<sjj-editable-column prop="provinceText" label="城市" type="select" :options="options"></sjj-editable-column>
<sjj-editable-column prop='address' label="地址" type="textarea"></sjj-editable-column>
<sjj-editable-column prop='zip' label="邮编"></sjj-editable-column>
</sjj-editable>
<div style="margin-bottom: 20px;">
<h3>Editable Attributes</h3>
<el-table
:data="tableData2"
stripe
border
style="width: 100%">
<el-table-column
prop="parameter"
label="参数"
width="180">
</el-table-column>
<el-table-column
prop="instructions"
label="说明">
</el-table-column>
<el-table-column
prop="type"
label="类型"
width="180">
</el-table-column>
<el-table-column
prop="optionalValue"
label="可选值"
width="180">
</el-table-column>
<el-table-column
prop="defaultValue"
label="默认值"
width="180">
</el-table-column>
</el-table>
</div>
<div style="margin-bottom: 20px;">
<h3>Editable-Column Attributes</h3>
<el-table
:data="tableData3"
stripe
border
style="width: 100%">
<el-table-column
prop="parameter"
label="参数"
width="180">
</el-table-column>
<el-table-column
prop="instructions"
label="说明">
</el-table-column>
<el-table-column
prop="type"
label="类型"
width="180">
</el-table-column>
<el-table-column
prop="optionalValue"
label="可选值"
width="180">
</el-table-column>
<el-table-column
prop="defaultValue"
label="默认值"
width="180">
</el-table-column>
</el-table>
</div>
<div style="margin-bottom: 20px;">
<h3>Editable Methods</h3>
<el-table
:data="tableData4"
stripe
border
style="width: 100%">
<el-table-column
prop="name"
label="方法名"
width="180">
</el-table-column>
<el-table-column
prop="instructions"
label="说明">
</el-table-column>
<el-table-column
prop="parameter"
label="参数"
width="180">
</el-table-column>
<el-table-column
prop="valueType"
label="返回值类型"
width="180">
</el-table-column>
<el-table-column
prop="valueFormat"
label="返回值格式"
width="180">
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
import SjjEditable from '../../components/editable/index.js'
import SjjEditableColumn from '../../components/editable/src/editable-column'
export default {
name: 'PhoneS',
components: {
SjjEditable,
SjjEditableColumn
},
data () {
return {
options: [
{
value: '1',
text: '上海'
},
{
value: '2',
text: '北京'
},
{
value: '3',
text: '杭州'
}
],
tableData: [
{
rowId: 'R001',
date: '2021-08-17',
name: '王小虎',
province: '1',
provinceText: '上海',
city: '普陀',
address: '上海市普陀区',
zip: 200320,
tag: '家'
},
{
rowId: 'R002',
date: '2021-08-18',
name: '王小',
province: '2',
provinceText: '北京',
city: '朝阳',
address: '北京朝阳',
zip: 200330,
tag: '公司'
}
],
rules: {
name: [
{ required: true, message: '请输入姓名', trigger: 'blur' },
{ min: 1, max: 3, message: '姓名不超过3个字符', trigger: 'blur' }
],
address: [
{ required: true, message: '请输入地址', trigger: 'blur' }
],
province: [
{ required: true, message: '请选择城市', trigger: 'change' }
],
date: [
{ required: true, message: '请选择日期', trigger: 'change' }
]
},
tableData2: [
{
parameter: 'data',
instructions: '表格数据,必输',
type: 'Array',
optionalValue: '-',
defaultValue: '-'
},
{
parameter: 'row-key',
instructions: '行数据的key,必输',
type: 'String',
optionalValue: '-',
defaultValue: '-'
},
{
parameter: 'rules',
instructions: '验证规则,必输',
type: 'Object',
optionalValue: '-',
defaultValue: '-'
},
{
parameter: 'height',
instructions: '表格高度,默认为自动高度,如果height为number类型,单位px;如果height为String类型,则这个高度会设置为Table的style.height的值,Table的高度则会受控于外部样式',
type: 'String/Number',
optionalValue: '-',
defaultValue: '-'
}
],
tableData3: [
{
parameter: 'type',
instructions: '列属性,其中,不设置/index表示双击不可编辑',
type: 'String',
optionalValue: 'index/text/textarea/select/date/datetime/currency',
defaultValue: '-'
},
{
parameter: 'index',
instructions: '如果设置了type=index,可以通过传递index属性来定义索引',
type: 'String/Function(index)',
optionalValue: '-',
defaultValue: '-'
},
{
parameter: 'options',
instructions: '如果设置了type=select,通过传递options属性定义选项列表',
type: 'Array',
optionalValue: '-',
defaultValue: '-'
},
{
parameter: 'format',
instructions: '如果设置了type=date,type=datetime,通过传递format实现定义显示在输入框中的格式',
type: 'String',
optionalValue: '-',
defaultValue: 'yyyy-MM-dd'
},
{
parameter: 'value-format',
instructions: '如果设置了type=date,type=datetime,通过传递value-format属性定义绑定值得格式',
type: 'String',
optionalValue: '-',
defaultValue: 'yyyy-MM-dd'
},
{
parameter: 'label',
instructions: '显示的标题',
type: 'String',
optionalValue: '-',
defaultValue: '-'
},
{
parameter: 'prop',
instructions: '对应列内容的字段名',
type: 'String',
optionalValue: '-',
defaultValue: '-'
},
{
parameter: 'width',
instructions: '固定列宽',
type: 'String',
optionalValue: '-',
defaultValue: '-'
},
{
parameter: 'min-width',
instructions: '最小列宽,与width的却别是width是固定的,min-width会把剩余宽度按比例分配给设置了min-width的列',
type: 'Array',
optionalValue: '-',
defaultValue: '-'
}
],
tableData4: [
{
name: 'getEditedRowData',
instructions: '获取编辑过的整行数据集',
parameter: '-',
valueType: 'Array',
valueFormat: '[ { data的某行 }, ... ]'
},
{
name: 'getEditedData',
instructions: '获取编辑过的行以及列的数据集',
parameter: '-',
valueType: 'Array',
valueFormat: '[ { rowKey: value, prop1: cellValue1, prop2: cellValue2, ... }, ... ]'
}
]
}
},
methods: {
getEditedRowData () {
alert(JSON.stringify(this.$refs.tb.getEditedRowData()))
},
getEditedData () {
alert(JSON.stringify(this.$refs.tb.getEditedData()))
},
handleChangeDate (rowIdx, prop, value) {
console.log(`handle change date: ${rowIdx}--${prop}--${value}`)
},
handleChangeName (rowIdx, prop, value) {
console.log(`handle change name: ${rowIdx}--${prop}--${value}`)
}
}
}
</script>
<style scoped>
/* .explain {
margin: 20px 0;
}
.explain span {
color: #409eff;
}
.phone /deep/ .el-card__body {
height: 250px;
}
.phone /deep/ .el-row {
margin-bottom: 20px;
} */
</style>
方法
文章来源:https://www.toymoban.com/news/detail-680858.html
文章来源地址https://www.toymoban.com/news/detail-680858.html
到了这里,关于vue可编辑表格的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!