完成可编辑可删除表格

This commit is contained in:
zhigang.li 2018-06-05 17:08:19 +08:00
parent d2e3b84d0e
commit 715d072a34
16 changed files with 420 additions and 21 deletions

6
package-lock.json generated
View File

@ -14881,9 +14881,9 @@
"dev": true
},
"vue-i18n": {
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-7.6.0.tgz",
"integrity": "sha512-IqyGj4nOFrGopCCpRucfMPJSgp5WauuI8HTaAQc7XIpHT7iOH4flndy1g09FiUzidi0lRVKJME+S7sPJny/t/A=="
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-5.0.3.tgz",
"integrity": "sha1-ttlsyDJgQjfmE53kceDUyCCu2+0="
},
"vue-loader": {
"version": "15.0.11",

View File

@ -23,7 +23,7 @@
"sortablejs": "^1.7.0",
"tinymce": "^4.7.11",
"vue": "^2.5.10",
"vue-i18n": "^7.6.0",
"vue-i18n": "^5.0.3",
"vue-router": "^3.0.1",
"vuex": "^3.0.1"
},

8
src/api/data.js Normal file
View File

@ -0,0 +1,8 @@
import axios from '@/libs/api.request'
export const getTableData = () => {
return axios.request({
url: 'get_table_data',
method: 'get'
})
}

View File

@ -0,0 +1,72 @@
<template>
<div class="tables-edit-outer">
<div v-if="!isEditting" class="tables-edit-con">
<span class="value-con">{{ value }}</span>
<Button @click="startEdit" class="tables-edit-btn" style="padding: 2px 4px;" type="text"><Icon type="edit"></Icon></Button>
</div>
<div v-else class="tables-editting-con">
<Input :value="value" @input="handleInput" class="tables-edit-input"/>
<Button @click="saveEdit" style="padding: 6px 4px;" type="text"><Icon type="checkmark-round"></Icon></Button>
<Button @click="canceltEdit" style="padding: 6px 4px;" type="text"><Icon type="close-round"></Icon></Button>
</div>
</div>
</template>
<script>
export default {
name: 'TablesEdit',
props: {
value: [String, Number],
edittingCellId: String,
params: Object
},
computed: {
isEditting () {
return this.edittingCellId === `editting-${this.params.index}-${this.params.column.key}`
}
},
methods: {
handleInput (val) {
this.$emit('input', val)
},
startEdit () {
this.$emit('on-start-edit', this.params)
},
saveEdit () {
this.$emit('on-save-edit', this.params)
},
canceltEdit () {
this.$emit('on-cancel-edit', this.params)
}
}
}
</script>
<style lang="less">
.tables-edit-outer{
height: 100%;
.tables-edit-con{
position: relative;
height: 100%;
.value-con{
vertical-align: middle;
}
.tables-edit-btn{
position: absolute;
right: 10px;
top: 0;
display: none;
}
&:hover{
.tables-edit-btn{
display: inline-block;
}
}
}
.tables-editting-con{
.tables-edit-input{
width: ~"calc(100% - 50px)";
}
}
}
</style>

View File

@ -0,0 +1,50 @@
const btns = [
(h, params, vm) => {
return h('Poptip', {
props: {
confirm: true,
title: '你确定要删除吗?'
},
on: {
'on-ok': () => {
vm.$emit('on-delete', params)
vm.$emit('input', params.tableData.filter((item, index) => index !== params.index))
}
}
}, [
h('Button', {
props: {
type: 'text'
}
}, [
h('Icon', {
props: {
type: 'trash-b',
size: 18
}
})
])
])
},
(h, params, vm) => {
return h('Button', {
props: {
type: 'text'
},
on: {
click: () => {
console.log(params)
}
}
}, [
h('Icon', {
props: {
type: 'search',
size: 18
}
})
])
}
]
export default btns

View File

@ -0,0 +1,2 @@
import tables from './tables.vue'
export default tables

View File

View File

@ -0,0 +1,163 @@
<template>
<Table
:data="value"
:columns="insideColumns"
:stripe="stripe"
:border="border"
:show-header="showHeader"
:width="width"
:height="height"
:loading="loading"
:disabled-hover="disabledHover"
:highlight-row="highlightRow"
:row-class-name="rowClassName"
:size="size"
:no-data-text="noDataText"
:no-filtered-data-text="noFilteredDataText"
></Table>
</template>
<script>
import TablesEdit from './edit.vue'
import handleBtns from './handle-btns'
export default {
name: 'tables',
props: {
value: {
type: Array,
default () {
return []
}
},
columns: {
type: Array,
default () {
return []
}
},
size: String,
width: {
type: [Number, String]
},
height: {
type: [Number, String]
},
stripe: {
type: Boolean,
default: false
},
border: {
type: Boolean,
default: false
},
showHeader: {
type: Boolean,
default: true
},
highlightRow: {
type: Boolean,
default: false
},
rowClassName: {
type: Function,
default () {
return ''
}
},
context: {
type: Object
},
noDataText: {
type: String
},
noFilteredDataText: {
type: String
},
disabledHover: {
type: Boolean
},
loading: {
type: Boolean,
default: false
},
editable: {
type: Boolean,
default: false
}
},
/**
* Events
* @on-start-edit 返回值 {Object} 同iview中render函数中的params对象 { row, index, column }
* @on-cancel-edit 返回值 {Object} 同上
* @on-save-edit 返回值 {Object} 除上面三个参数外还有一个value: 修改后的数据
*/
data () {
return {
insideColumns: [],
edittingCellId: '',
edittingText: ''
}
},
methods: {
suportEdit (item, index) {
item.render = (h, params) => {
return h(TablesEdit, {
props: {
params: params,
value: this.value[params.index][params.column.key],
edittingCellId: this.edittingCellId
},
on: {
'input': val => {
this.edittingText = val
},
'on-start-edit': (params) => {
this.edittingCellId = `editting-${params.index}-${params.column.key}`
this.$emit('on-start-edit', params)
},
'on-cancel-edit': (params) => {
this.edittingCellId = ''
this.$emit('on-cancel-edit', params)
},
'on-save-edit': (params) => {
this.value[params.index][params.column.key] = this.edittingText
this.$emit('input', this.value)
this.$emit('on-save-edit', Object.assign(params, {value: this.edittingText}))
this.edittingCellId = ''
}
}
})
}
return item
},
surportHandle (item) {
let btns = item.button ? [].concat(handleBtns, item.button) : handleBtns
item.render = (h, params) => {
params.tableData = this.value
return h('div', btns.map(item => item(h, params, this)))
}
return item
},
handleColumns (columns) {
this.insideColumns = columns.map((item, index) => {
let res = item
if (res.editable) res = this.suportEdit(res, index)
if (res.key === 'handle') res = this.surportHandle(res)
return res
})
}
},
watch: {
columns (columns) {
this.handleColumns(columns)
}
},
mounted () {
this.handleColumns(this.columns)
}
}
</script>
<style>
</style>

View File

@ -192,3 +192,14 @@ export const getNextName = (list, name) => {
}
return res
}
/**
* @param {Number} times 回调函数需要执行的次数
* @param {Function} callback 回调函数
*/
export const doCustomTimes = (times, callback) => {
let i = -1
while (++i < times) {
callback()
}
}

View File

@ -16,17 +16,20 @@ Vue.use(VueI18n)
let lang = 'zh-CN'
Vue.config.lang = lang
Vue.locale = () => {}
const messages = {
'zh-CN': Object.assign(zhCnLocale, customZhCn),
'zh-TW': Object.assign(zhTwLocale, customZhTw),
'en-US': Object.assign(enUsLocale, customEnUs)
}
// vue-i18n 6.x+写法
// Vue.locale = () => {}
// const messages = {
// 'zh-CN': Object.assign(zhCnLocale, customZhCn),
// 'zh-TW': Object.assign(zhTwLocale, customZhTw),
// 'en-US': Object.assign(enUsLocale, customEnUs)
// }
// const i18n = new VueI18n({
// locale: lang,
// messages
// })
const i18n = new VueI18n({
locale: lang,
messages
})
export default i18n
// vue-i18n 5.x写法
Vue.locale('zh-CN', Object.assign(zhCnLocale, customZhCn))
Vue.locale('en-US', Object.assign(zhTwLocale, customZhTw))
Vue.locale('zh-TW', Object.assign(enUsLocale, customEnUs))

View File

@ -5,7 +5,7 @@ import App from './App'
import router from './router'
import store from './store'
import iView from 'iview'
import i18n from '@/locale'
import '@/locale'
import config from '@/config'
import 'iview/dist/styles/iview.css'
import env from '../config/env'
@ -23,6 +23,5 @@ new Vue({
el: '#app',
router,
store,
i18n,
render: h => h(App)
})

18
src/mock/data.js Normal file
View File

@ -0,0 +1,18 @@
import Mock from 'mockjs'
import { doCustomTimes } from '@/libs/util'
export const getTableData = req => {
let tableData = []
doCustomTimes(5, () => {
tableData.push(Mock.mock({
name: '@name',
email: '@email',
createTime: '@date'
}))
})
return {
code: 200,
data: tableData,
msg: ''
}
}

View File

@ -1,9 +1,11 @@
import Mock from 'mockjs'
import { login, logout, getUserInfo } from './login'
import { getTableData } from './data'
// 登录相关和获取用户信息
Mock.mock(/\/login/, login)
Mock.mock(/\/get_info/, getUserInfo)
Mock.mock(/\/logout/, logout)
Mock.mock(/\/get_table_data/, getTableData)
export default Mock

View File

@ -42,13 +42,22 @@ export default [
component: Main,
children: [
{
path: 'count_to',
name: 'count_to',
path: 'count_to_page',
name: 'count_to_page',
meta: {
icon: 'arrow-graph-up-right',
title: '数字渐变'
},
component: () => import('@/view/components/count-to/count-to.vue')
},
{
path: 'tables_page',
name: 'tables_page',
meta: {
icon: 'ios-grid-view',
title: '多功能表格'
},
component: () => import('@/view/components/tables/tables.vue')
}
]
},

View File

@ -142,7 +142,7 @@
<script>
import countTo from '_c/count-to'
export default {
name: 'count_to',
name: 'count_to_page',
components: {
countTo
},

View File

@ -0,0 +1,62 @@
<template>
<div>
<tables v-model="tableData" :columns="columns" @on-delete="handleDelete"/>
</div>
</template>
<script>
import tables from '_c/tables'
import { getTableData } from '@/api/data'
export default {
name: 'tables_page',
components: {
tables
},
data () {
return {
columns: [
{title: 'Name', key: 'name', sortable: true},
{title: 'Email', key: 'email', editable: true},
{title: 'Create-Time', key: 'createTime'},
{
title: 'Handle',
key: 'handle',
button: [
(h, params, vm) => {
return h('Poptip', {
props: {
confirm: true,
title: '你确定要删除吗?'
},
on: {
'on-ok': () => {
vm.$emit('on-delete', params)
vm.$emit('input', params.tableData.filter((item, index) => index !== params.rowIndex))
}
}
}, [
h('Button', '自定义删除')
])
}
]
}
],
tableData: []
}
},
methods: {
handleDelete (params) {
console.log(params)
}
},
mounted () {
getTableData().then(res => {
this.tableData = res.data
})
}
}
</script>
<style>
</style>