原创
like 1
Vue之智能动态表单组件
2020.07.07 10:37
1 人喜欢
811 次阅读
0 条评论
父组件
<template>
<div>
<dynamic-form :data.sync="data" />
</div>
</template>
<script>
import DynamicForm from '@/components/public/DynamicForm.vue'
export default {
name: 'test',
components: {
'dynamic-form': DynamicForm
},
data () {
const data = {
str: '123123',
num: 111,
strAry: ['isis', 'wddd', '23sdfsdfs', 'wclgdj'],
isOn: true,
isNb: false,
isC: true,
daa: {
num: 12312,
ary: [
{
nb: 1,
wc: ['nb', 'xdnb', '兄弟牛逼'],
nbb: {
strr: 'nbnbnb'
}
},
{
nb: 2,
wc: ['nb222', 'xdnb2222', '兄弟牛逼2222'],
nbb: {
strr: 'nbnbnb22222',
ary: [
{
nb: 1,
wc: ['nb', 'xdnb', '兄弟牛逼'],
nbb: {
strr: 'nbnbnb'
}
}
]
}
}
]
}
}
return {
data
}
}
}
</script>
动态表单组件DynamicForm
<template>
<div class="recursive_form">
<!--别挡我测试!-->
<el-form ref="form" label-width="100px">
<el-form-item v-for="(item,i) in dataKeyAry" :key="i" :label="item">
<el-card shadow="hover" v-if="verifType(data[item]) === 'String'">
<el-input v-model="data[item]"></el-input>
</el-card>
<el-card shadow="hover" v-if="verifType(data[item]) === 'Number'">
<el-input v-model.number="data[item]"></el-input>
</el-card>
<el-card shadow="hover" v-if="verifType(data[item]) === 'Boolean'">
<el-switch v-model="data[item]" active-color="#13ce66" inactive-color="#ff4949"></el-switch>
</el-card>
<el-card shadow="hover" v-if="verifType(data[item]) === 'Array'">
<div
v-if="verifType(data[item][0]) === 'String' || verifType(data[item][0]) === 'Number' || data[item].length === 0"
>
<el-tag
:key="tag"
style="margin:5px;"
v-for="tag in data[item]"
closable
:disable-transitions="false"
@close="handleClose(data[item],tag)"
>{{tag}}</el-tag>
<el-input
class="input-new-tag"
v-if="tagInputJson['inputVisible' + i]"
v-model="tagInputJson['inputValue' + i]"
:ref="'saveTagInput' + i"
size="small"
@keyup.enter.native="handleInputConfirm(data[item],i)"
@blur="handleInputConfirm(data[item],i)"
></el-input>
<el-button v-else class="button-new-tag" size="small" @click="showInput(i)">新增</el-button>
</div>
<div v-else>
<DynamicForm
:data.sync="item_"
:isAryObj="true"
:ItemAry.sync="data[item]"
:itemIndex.sync="ii"
v-for="(item_,ii) in data[item]"
:key="ii"
/>
</div>
</el-card>
<el-card shadow="hover" v-if="verifType(data[item]) === 'Object'">
<DynamicForm :data.sync="data[item]" />
</el-card>
</el-form-item>
<el-row
type="flex"
justify="center"
style="margin-top: 5px;"
v-if="verifType(data) === 'Object' && isAryObj === true"
>
<el-button type="warning" @click="removeItem()" icon="el-icon-minus" circle></el-button>
<el-button
type="primary"
@click="addItem()"
v-if="itemIndex === ItemAry.length - 1"
icon="el-icon-plus"
circle
></el-button>
</el-row>
</el-form>
</div>
</template>
<script>
export default {
name: 'DynamicForm',
components: {},
props: {
data: Object,
isAryObj: {
type: Boolean,
deafult: false
},
ItemAry: Array,
itemIndex: Number
},
data () {
return {
dataKeyAry: [],
tagInputJson: {
inputVisible1: false, // 这里的会自动增加 inputVisible或inputValue,以此类推往下+,变成inputValue2、inputValue3等等
inputValue1: ''
}
}
},
mounted () {
this.dataKeyAry = Object.keys(this.data)
},
methods: {
addItem () {
let j = this.extend(this.ItemAry[0])
this.kInitData(j)
this.ItemAry.push(j)
},
removeItem () {
if (this.ItemAry.length === 1) return this.$message.warning('不可清空!')
this.ItemAry.splice(this.itemIndex, 1)
},
extend (source) {
// 深拷贝数据
let target
if (typeof source === 'object') {
target = Array.isArray(source) ? [] : {}
for (let key in source) {
if (source.hasOwnProperty(key)) {
if (typeof source[key] !== 'object') target[key] = source[key]
else target[key] = this.extend(source[key])
}
}
} else target = source
return target
},
kInitData (j) {
// 将这个json中的所有值初始化一遍
const keys = Object.keys(j)
keys.forEach(e => {
let v = j[e]
if (this.verifType(v) === 'String') j[e] = ''
if (this.verifType(v) === 'Number') j[e] = 0
if (this.verifType(v) === 'Boolean') j[e] = true
if (this.verifType(v) === 'Array') {
if (this.verifType(v[0]) === 'Object') j[e] = [this.kInitData(v[0])]
else j[e] = []
}
if (this.verifType(v) === 'Object') j[e] = this.kInitData(v)
})
return j
},
verifType (obj) {
if (obj === undefined) return 'undefined'
if (obj.constructor === Object) return 'Object'
if (obj.constructor === Array) return 'Array'
if (obj.constructor === Number) return 'Number'
if (obj.constructor === String) return 'String'
if (obj.constructor === Boolean) return 'Boolean'
},
handleClose (ary, tag) {
ary.splice(ary.indexOf(tag), 1)
},
showInput (i) {
this.$set(this.tagInputJson, `inputVisible${i}`, true)
this.$nextTick(_ => {
this.$refs[`saveTagInput${i}`][0].$refs.input.focus()
})
},
handleInputConfirm (ary, i) {
const val = this.tagInputJson[`inputValue${i}`]
if (val) ary.push(val)
this.$set(this.tagInputJson, `inputValue${i}`, '')
this.$set(this.tagInputJson, `inputVisible${i}`, false)
}
},
computed: {},
created () {
setInterval((_this = this) => {
_this.$emit('update:data', _this.data)
}, 1000)
},
watch: {}
}
</script>
<style lang="scss">
.recursive_form {
margin-bottom: 10px;
.el-form-item {
position: relative;
}
.el-form-item__label {
position: absolute;
text-align: justify;
word-break: break-all;
top: 50%;
transform: translate(0px, -50%);
}
}
</style>

