需求效果
接到一个需求,制作一个卡片选择器组件,就是类似商品卡片选中效果,显示一个边框,右下角显示一个小对勾表示选中,卡片内的内容随意。
代码实现
外边的壳:边框、选中效果、选中后右下角的对勾,都是固定的
唯一变化的是内部的内容,内部的内容可能是文字、图片,或者其他东西,需要动态渲染。
首选,用v-if、v-else-if 把可能的标签都写死在template中,这肯定不合理。
其次,就是用jsx的能力,来动态渲染模版了,
render() {
return (
<div class="lc-radioCard">
{
this.options.map(option => {
return (
<div
key={option._key}
style={{ borderColor: this.borderColor }}
class={["lc-radioCard__option",this.hasSelectedClass(option.value)]}
onClick={() => this.handleSelected(option.value)}
>
{
option.template.map(tmp => {
return this.$createElement(tmp.tag, { class: tmp.className, style:tmp.style }, tmp.content)
})
}
{
this.hasSelectedClass(option.value) ? (<i class="el-icon-check lc-radioCard__selectedIcon" />) : ''
}
</div>
)
})
}
</div >
)
}
最后,并没有采用jsx的方式,因为项目其他任何地方都没有使用jsx,为了保持统一和变异维护,而是用vue提供的<component>动态组件来实现动态渲染。
意外发现,普通的html标签也是可以被<component>渲染出来的。
<template>
<div class="lc-radioCard">
<div
v-for="option in options" :key="option._key" :style="{ 'border-color': borderColor }"
class="lc-radioCard__option"
@click="handleSelected(option.value)"
>
<component
:is="item.componentName"
v-for="(item,index) in option.template"
:key="index"
v-bind="item.props"
>
{{ item.props.content || '' }}
</component>
<i v-if="hasSelectedClass(option.value)" class="el-icon-check lc-radioCard__selectedIcon" />
</div>
</div>
</template>