场景
很多时候我们需要对一些UI框架进行二次封装,比如对elementUI进行二次封装
<template>
<div>
<el-input v-model="value"/>
</div>
</template>
这个时候我们需要能在组件外面设置el-input的属性,那我们的第一反应都是,通过props传值进来,然后一个一个进行设置
<template>
<div>
<el-input
v-model="value"
:placeholder="placeholder"
...
/>
</div>
</template>
这样虽然行的通,但是缺点也很明显,单属性多的时候会导致代码的可读性差,增加维护的难度,而且容易遗漏
利用v-bind="$attrs"实现透传
首先我们来看看文档对$attrs的解释
当我们在组件中没有声明,即显式的使用props去接收父组件传过来的属性时,传入相关的属性,会直接将属性传到根节点上
红框中的placeholder和maxleng都是父组件传入的属性
怎么样将属性简单、便捷的将属性传入到el-input中呢,只需要给el-input加一个v-bind="$attrs"就行了
<template>
<div>
<el-input v-model="value" v-bind="$attrs"/>
</div>
</template>
利用render函数实现动态表单
首先看看文档中对render的详细说明
render接收三个参数:
1: 渲染的tag
2:tag所拥有的属性
3:子节点
参数说明地址
根据这些参数,我们可以直接实现动态表单,上代码
父组件:
// 父组件
<template>
<div>
<div>child-components-A</div>
<childComponentB :configJsonArr="configJsonArr"></childComponentB>
</div>
</template>
<script>
import childComponentB from './childComponentB'
export default {
components: {
childComponentB,
},
data () {
return {
configJsonArr: [
{
type: 'Input',
props: {
placeholder: 'dfsdffsdfsdfds',
maxlength: 12
}
},
{
type: 'Select',
props: {
placeholder: 'dfsdffsdfsdfds',
options: [
{ value: 1, key: '111' },
{ value: 2, key: '222' },
{ value: 3, key: '333' },
]
}
}
]
}
},
methods: {
}
}
</script>
子组件:
<template>
<div>
<div>child-components-B</div>
<childComponentC v-bind="$attrs"></childComponentC>
<form-item :configJson="item" v-for="(item, index) in configJsonArr" :key="index"></form-item>
</div>
</template>
<script>
import childComponentC from './childComponentC'
import Input from './Input'
import Select from './Select'
const FormItem = {
components: {
Input,
Select
},
props: [ 'configJson' ],
render(h) {
console.log(this.configJson);
return h(
`${this.configJson.type}`,
{
props: {
...this.configJson.props
},
attrs: {
...this.configJson.props
},
},
)
}
}
export default {
components: {
childComponentC,
FormItem
},
data () {
return {
test: {
id: 1234234,
length: 12,
},
configJsonArr: []
}
},
mounted() {
console.log(this.$attrs)
this.configJsonArr = this.$attrs.configJsonArr
},
methods: {
}
}
</script>
input组件
<template>
<div>
<el-input v-bind="$attrs" v-model="value"/>
</div>
</template>
<script>
export default {
data() {
return {
value: '',
}
}
}
</script>
这里只列出input组件的代码,其余控件类推就行了
当然我们也可以使用component去实现,但是使用component时,我们直接在 el-input 设置 v-bind="$attrs" 是不行的,原因在于动态组件传入的属性 configProps 是一个对象,而不是解构后的对象属性