import Vue, { VNode, CreateElement } from 'vue'
import { Component } from 'vue-property-decorator'
import type { Option } from 'element-ui'
import omit from 'lodash/omit'
import { cloneDeep } from 'lodash'
function transformKeyValue(
o: any,
{
labelName = 'label',
valueName = 'value',
}: { labelName?: string, valueName?: string }
): any {
return {
...omit(o, [labelName, valueName]),
label: o[labelName],
value: o[valueName],
}
}
@Component
export default class SelectPlus extends Vue {
render(h: CreateElement): VNode {
const { labelName = 'label', valueName = 'value' } = this.$attrs
// 组装插槽及作用域插槽
const scopedSlots: any = this.$scopedSlots
const slots = []
const customScopedSlots: any = {}
for (const slot in scopedSlots) {
// el-select内部使用了 v-if="$slots.[slotName]"来判断是否有插槽
// 因此这一步是骗它有插槽,然后再用scopedSlots来实现自定义渲染函数渲染插槽内容
slots.push({ name: slot, value: [h('template')] })
// 插槽额外增加h函数,便于生成vnode
customScopedSlots[slot] = () => {
return scopedSlots[slot]({ h, value: this.$attrs.value })
}
}
const renderOptions = (options: any) => {
return options.map((o: any) => {
const transformObj = transformKeyValue(o, { labelName, valueName })
const { value, slot } = transformObj
return (
{slot ? slot({ attr: transformObj }) : ''}
)
})
}
const renderGroupOption = () => {
const { groupOptions = [], options = [] } = cloneDeep(this.$attrs)
const optionEl: any = []
// groupOptions只要存在,就渲染分组select
if (groupOptions) {
(groupOptions as any).forEach((o: any) => {
o.options = o.options.map((m: any) =>
transformKeyValue(m, { labelName, valueName })
)
const { options: gOptions } = o
// 除options之外的配置项均为group参数
const restAttrs = omit(o, 'options')
const el = (
{renderOptions(gOptions)}
)
optionEl.push(el)
})
}
return optionEl.concat(renderOptions(options))
}
return (
{renderGroupOption()}
{slots.map(o => {
return {o.value}
})}
)
}
}