<template>
<div>
</div>
</template>
<script>
import { getTableData } from '@/api/data'
export default {
data () {
return {
tableData: [],
columns: [
{ key: 'name', title: '姓名' },
{ key: 'age', title: '年龄', editable: true },
{ key: 'email', title: '邮箱', editable: true }
]
}
},
mounted () {
getTableData().then(res => {
this.tableData = res.data
})
}
}
</script>
import axios from './index'
export const getTableData = () => {
return axios.request({
url: '/getTableData',
method: 'get'
})
}
import { doCustomTimes } from '@/lib/tools'
import Mock from 'mockjs'
export const getTableData = () => {
const template = {
name: '@name',
'age|18-25': 0,
email: '@email'
}
let arr = []
doCustomTimes(5, () => {
arr.push(Mock.mock(template))
})
return arr
}
import Mock from 'mockjs'
import { getTableData } from './response/data'
Mock.mock(/\/getTableData/, 'get', getTableData)
export default Mock
export const doCustomTimes = (times, callbakc) => {
let i = -1
while (++i < times) {
callbakc()
}
}
自此我们可以获取到mock生成的随机数据
index.js
<template>
<!-- 有两个重要值,一个定义列的数组(在table.vue中的colums),一个定义数据的数组 -->
<Table :columns="columns" :data="value"></Table>
</template>
<script>
export default {
name: 'EditTable',
props: {
columns: {
type: Array,
default: () => []
},
value: {
type: Array,
default: () => []
}
}
}
</script>
import EditTable from '_c/edit-table'
components: {
EditTable
}
<template>
<div>
<edit-table :colums='colums' :data="tableData"></edit-table>
</div>
</template>
1.由于我们不能直接修改父组件传过来的数据,需要在子组件中抛出一个事件,父组件接受这个事件,在事件的回调函数里进行相关操作。我们在edit-table子组件中定义一个insideColumns
mounted () {
// console.log(this.columns)
// 使用map方法做映射,item代表每列对象
const insideColumns = this.columns.map(item => {
// // 如果传进来的item对象有render对象,直接return
// if (item.render) return item
// // 如果没有则判断editable是否为true,
// else if (!item.editable) return item
if (!item.render && item.editable) {
item.render = (h, { row, index, column }) => {
console.log(row, index, column)
// 使用JSX写法,直接在括号在写标签 ,注意括号在包括的所有内容必须有有一个大标签包裹
// 逻辑和变量都要用花括号包裹
// 最外层需要设置一个根元素
return (
<div>
{row[column.key]}
</div>
)
}
return item
} else return item
})
this.insideColumns = insideColumns
}
<Table :columns="insideColumns" :data="value"></Table>
在data中定义
data () {
return {
insideColumns: [],
// 使用表格的行号和key值即可以确定一个单元格
edittingId: ''
}
}
2.如何拿到当前点击按钮的元素,并为其设置id
定义method中的方法,验证当前单元格
methods: {
handleClick ({ row, index, column }) {
console.log({ row, index, column })
}
}
定义一个按钮
<div>
{row[column.key]}
<i-button on-click={this.handleClick.bind(this, { row, index, column })}>编辑</i-button>
</div>
至此我们得到了当前点击的元素,接下来给它修改edittingId
3.有了edittingId ,我们就可以判断当前单元格的具体位置
methods: {
handleClick ({ row, index, column }) {
console.log({ row, index, column })
this.edittingId = `${column.key}_${index}`
}
},
4.继续配置内容
配置input控件
<div>
{row[column.key]}
<i-button on-click={this.handleClick.bind(this, { row, index, column })}>编辑</i-button>
<i-input value={row[column.key]} style="width: 50px;"></i-input>
</div>
return (
<div>
{this.edittingId === `${column.key}_${index}` ?
<i-input value={row[column.key]} style="width: 50px;"></i-input>
: <i-button on-click={this.handleClick.bind(this, { row, index, column })}>编辑</i-button>}
{row[column.key]}
</div>
)
6.如何将修改内容替换?
6.1首先给input绑定一个on-input事件
<i-input value={row[column.key]} style="width: 50px;" on-input={this.handleInput}></i-input>
6.2在data中定义编辑的内容
data () {
return {
insideColumns: [],
// 使用表格的行号和key值即可以确定一个单元格
edittingId: '',
// 每次输入内容时就放在edittingContent中
edittingContent: ''
}
}
6.3在methods中定义
methods: {
handleClick ({ row, index, column }) {
console.log({ row, index, column })
this.edittingId = `${column.key}_${index}`
},
handleInput (newValue) {
this.edittingContent = newValue
}
},
6.4设置按钮的状态值编辑和保存的切换
将判断条件保存为常量,便于重复使用
item.render = (h, { row, index, column }) => {
const isEditting = this.edittingId === `${column.key}_${index}`
<div>
{ isEditting ? <i-input value={row[column.key]} style="width: 50px;" on-input={this.handleInput}></i-input> : <span>{row[column.key]}</span>}
<i-button on-click={this.handleClick.bind(this, { row, index, column })}>{isEditting ? '保存' : '编辑'}</i-button>
</div>
6.5在handleClick中判断当前点击为保存状态还是编辑状态
6.5.1由于要修改tableData,我们用v-model绑定tableData
在父组件table.vue中
<edit-table :columns='columns' v-model="tableData"></edit-table>
在子组件edit-table中
<Table :columns="insideColumns" :data="value"></Table>
并将props中的值设置为value
props: {
columns: {
type: Array,
default: () => []
},
value: {
type: Array,
default: () => []
}
},
6.5.2修改this.value,不能直接修改,智能修改value深拷贝后的数组,这里我们下载clonedeep插件
安装好clonedeep插件后引入
import clonedeep from 'clonedeep'
在edit-table.vue页面中
handleClick ({ row, index, column }) {
console.log({ row, index, column })
if (this.edittingId === `${column.key}_${index}`) {
// 如果为true说明当前点击的按钮为编辑状态,需要定义点击按钮保存逻辑
let tableData = clonedeep(this.value)
tableData[index][column.key] = this.edittingContent
// 触发一个$emit事件,把修改好的tableData数组传给父组件
this.$emit('input', tableData)
// 保存当前编辑元素的数据,导出,newValue用来告诉父组件更新后的值是什么
this.$emit('on-edit', { row, index, column, newValue: this.edittingContent })
// 点击保存后应该将edittingId设为空字符串,按钮值变为编辑状态
this.edittingId = ''
this.edittingContent = ''
} else {
this.edittingId = `${column.key}_${index}`
}
}
6.5.3在父组件中接受on-edit事件
<edit-table :columns='columns' v-model="tableData" @on-edit="handleEdit"></edit-table>
methods: {
handleEdit ({ row, index, column, newValue }) {
console.log({ row, index, column, newValue })
}
}
6.5.4如果我们从后端获取了新的数据是的表头发生了变化,columns的值会发生更新,我们在edit-table.vue中使用watch监听数据
把mounted中的逻辑封装起来
handleColumns () {
// console.log(this.columns)
// 使用map方法做映射,item代表每列对象
const insideColumns = this.columns.map(item => {
// // 如果传进来的item对象有render对象
// if (item.render) return item
// // 如果没有则判断editable是否为true,
// else if (!item.editable) return item
if (!item.render && item.editable) {
item.render = (h, { row, index, column }) => {
const isEditting = this.edittingId === `${column.key}_${index}`
console.log(row, index, column)
// 使用JSX写法,直接在括号在写标签 ,注意括号在包括的所有内容必须有有一个大标签包裹
// 逻辑和变量都要用花括号包裹
// 最外层需要设置一个根元素
return (
<div>
{ isEditting ? <i-input value={row[column.key]} style="width: 50px;" on-input={this.handleInput}></i-input> : <span>{row[column.key]}</span>}
<i-button on-click={this.handleClick.bind(this, { row, index, column })}>{isEditting ? '保存' : '编辑'}</i-button>
</div>
)
}
return item
} else return item
})
this.insideColumns = insideColumns
}
在mounted中执行一次
在这里插入代码片
如果mounted更新,我们再执行一次
watch: {
columns () {
this.handleColumns()
}
}