Element Plus表单子项label属性与插槽用法的小坑

问题描述

最近,测试给提了一个bug,在表单组件的某个子项前出现了一个冒号:

问题分析

作为一个刚进公司的菜鸟,第一反应可能是公司根据Element Plus二次封装的组件库出问题了,直接打开组件库一头扎进表单组件。好家伙,近两千行的.vue文件差点给我干蒙了。

好一阵寻找才发现,表单组件的布局是编写在另一个formLayout.js文件里,终于在该文件中找到了表单组件的渲染逻辑(为使代码简洁删除了部分属性)。

 

js

代码解读

复制代码

... <el-form-item label-width={labelWidth} ref={itemRef} // label={showLabel ? config.label : ''} style={itemStyle} v-slots={{ label: () => { return <span> <el-popover placement="top" width="200" trigger="hover" v-slots={{ reference: () => { return config.tips?<el-icon class='tip-style'><Warning /></el-icon>:null } }} > <span class='tip-style-span'>{config.tips}</span> </el-popover> {showLabel ? config.label : ''} </span> } }} > ...

其中这个label属性引起了我的注意,原来是某个同事根据需求将原来的label属性用插槽重写,在label前增加了一个气泡弹框。但是在插槽中根据showLabel的值来决定是否渲染label的逻辑并没有改变,那为啥会多一个冒号呢?

这个bug看起来就像隐藏了该表单子项的label文本但没隐藏冒号,毕竟原来使用label属性时没出现问题啊?怀着试一试的心情,我把插槽注释掉,仍采用原来的逻辑使用label属性来渲染,这时奇迹出现了:

冒号居然消失了,看来是使用插槽带来的问题,但为什么会这样呢?(暂且埋个伏笔~~~)

问题解决

虽然问题出在插槽上,可也不能不顾需求不使用插槽来渲染气泡框啊,这要咋办呢?转念一想既然问题的根源出在冒号上,那就去找找这个冒号是在哪里定义的。通过定位页面上的冒号,找到了冒号定义的逻辑:

原来是通过一个伪元素::after来增加的,在代码中全局搜索content: ':'(ps:全局搜索yyds!!!),终于找到了冒号产生的根源:

 

css

代码解读

复制代码

... .el-form-item__label { &::after { content: ':'; } } ...

既然找到了冒号产生的原因,那目前的一个思路就是找到label这个节点或组件,并根据showLabel的值来判断是否动态渲染这个CSS属性就行了。说干就干,又准备在全局搜索el-form-item__label这个类名,看看是在哪个DOM节点或组件定义的。结果尴尬了,根本就找不到该类名定义的地方,原来这是Element Plus内部定义的类名。

作为一个菜鸟这时我是没辙了,毕竟总不能找到依赖文件中去给这个组件加判断吧?还好在请教公司大佬后得到回复:“可以把伪元素定义的冒号放在label插槽里的span标签上。”一语惊醒梦中人,找不到label节点我还不能换个能找到的吗?修改后的代码如下:

 

js

代码解读

复制代码

... <el-form-item label-width={labelWidth} ref={itemRef} // label={showLabel ? config.label : ''} style={itemStyle} v-slots={{ label: () => { // 根据showLabel判断是否显示伪元素冒号: return <span class={showLabel ? 'el-form-item__label__span' : ''}> <el-popover placement="top" width="200" trigger="hover" v-slots={{ reference: () => { return config.tips?<el-icon class='tip-style'><Warning /></el-icon>:null } }} > <span class='tip-style-span'>{config.tips}</span> </el-popover> {showLabel ? config.label : ''} </span> } }} > ...

CSS中注释掉原类名,在span标签的类名上添加伪元素::after,代码如下:

 

css

代码解读

复制代码

... /*.el-form-item__label { &::after { content: ':'; } }*/ .el-form-item__label__span { &::after { content: ':'; } } ...

这下可解决问题了,大功告成!

伏笔回收

虽然解决了冒号的bug,可开头的问题还是使我困惑,为啥用插槽替换属性时就会出现冒号?带着这个疑问,我反复对比了label使用属性和插槽渲染时页面的DOM节点,终于让我发现了端倪:

使用label属性渲染:

使用label插槽渲染:

当渲染条件showLabel === false时,使用label属性会使labelDOM节点不会被渲染在DOM树上(v-if也给了提示);而使用label插槽会使labelDOM节点仍被渲染在DOM树上。 这也就间接导致了虽然label的值为空不会被渲染,但定义在label节点上的::after伪元素冒号仍然会被渲染。

到这里我恍然大悟,原来一切都是因为label值为空仍被渲染导致的,所以我又想到label值为空时能不能直接把label节点干掉,这样既能和原来的逻辑保持一致,又能减少DOM节点的渲染提高性能(有一丢丢丢提升吗?)。

想到这实现也就不难了:保持原有的CSS渲染逻辑,根据showLabel的值在插槽中决定要不要渲染label节点(考虑可读性可以将label的渲染结构抽出去)。代码如下:

 

js

代码解读

复制代码

... <el-form-item label-width={labelWidth} ref={itemRef} // label={showLabel ? config.label : ''} style={itemStyle} v-slots={{ // 根据showLabel判断是否渲染label标签 label: showLabel ? () => { return <span> <el-popover placement="top" width="200" trigger="hover" v-slots={{ reference: () => { return config.tips?<el-icon class='tip-style'><Warning /></el-icon>:null } }} > <span class='tip-style-span'>{config.tips}</span> </el-popover> {showLabel ? config.label : ''} </span> } : null // 这里值为''空字符串时DOM仍会渲染label节点? }} > ...

查看页面结构,成功消灭label节点:

总结

  1. Element Plus中表单子项el-form-itemlabel属性的值为空时不会被渲染在DOM树上,而在v-slots插槽中label的值为空时仍会被渲染在DOM树上。
  2. 在插槽中label属性的值要赋为null才不会被渲染在DOM树上,属性中传入空字符串''就可以。

原文链接:https://juejin.cn/post/7419532382803410994

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值