需求小能手——嵌入文本的开关按钮

前言

开关组件是日常开发中常见的一个组件,公司产品中也用到了开关组件,使用的是ElementUI中的el-switch,但是el-switch的描述文字是放到开关外面的,项目UI要求描述文字在里面,只能想办法将描述文字放到开关里面,本节我们来看一下具体的实现思路。

思路

经过搜索思路,得出了三种思路,下面我们一个个地看下具体实现思路。

更换组件库

如果有封装好的组件满足描述文字在里面,直接拿来使用,这是最简单,刚好el的升级版el-plus,实现了将描述文字放到开关里面。plus中新增了inline-prompt,设置为ture时描述文本就会在里面。

js 复制代码
   <el-switch v-model="flag" inline-prompt active-text="你好" inactive-text="世界" />

一个属性直接搞定,如果我们是一个新项目并且用的vue3那么可以直接将组件升级成plus,老项目就不适用。

修改样式

el-switch描述文字在外面,我们修改样式把文字定位到开关里面,根据不同的值去切换里面的值。打开页面我们可以看到描述文字与按钮的class名,通过class名称将描述文字定位到按钮中。

我们将中间按钮设置position为relative,将左右两边pisition设置为absolute,并且进行位置移动,将描述文字放到按钮里。

css 复制代码
   .el-switch__core {
    position: relative;
  }
  .is-active {
    color: aliceblue !important;
  }
  .el-switch__label--left {
    position: absolute;
    top: 0;
    left: 20px;
    z-index: 9;
  }
  .el-switch__label--right {
    position: absolute;
    top: 0;
    right: 20px;
    display: none;
  }

注意,我们假设初始化的值为false,这时候显示的是--left的内容,所以把--righ的display设置为none,此时false的描述文字就在按钮当中,接下来我们在按钮发生变化时,修改两者的display值。当按钮为开时,--right显示,--left隐藏;当按钮为关时,刚好相反。根据className获取对应的dom,然后设置display的属性值。

js 复制代码
   handleSwitchChange(val) {
    const leftE = document.getElementsByClassName('el-switch__label--left')[0]
    leftE.style.display = val ? 'none' : 'block'
    const rightE = document.getElementsByClassName('el-switch__label--right')[0]
    rightE.style.display = val ? 'block' : 'none'
  }

当我们修改开关时,按钮内部就会出现对应的文字。该方法虽然达到我们的要求,但是限制比较多,不能很好地组件化。

自定义组件

没有工具创造工具,我们自定义一个可以将描述文本放到开关中的组件,当然上述两种思路我们也可以用到自定义组件的开发中。我们在修改样式的时候看到过开关的dom结构,所以我们直接用el-switch的样式以及对应的dom结构去封装,之所以不直接封装el-switch,因为el当中没有对应属性,不如直接用h5标签方便。 首先完成开关布局,根据el-switch页面标签,我们可以得出开关是input标签生成的,它里面有三个span子标签:

  • label--left显示关闭描述文本。
  • label--right显示开启描述文本。
  • core显示中间的按钮。

我们把left与right放到core里面,那么描述文本不就放到了按钮当中,非常的简单。

js 复制代码
     <span
        class="el-switch__core inner-mode"
        ref="core"
        :class="{ 'is-checked': checked }"
        :style="{ 'width': coreWidth + 'px', 'min-width': minCoreWidth }"
      >
        <span v-if="!checked && inactiveText" :aria-hidden="checked">{{ inactiveText }}</span>
        <span v-else-if="checked && activeText" :aria-hidden="!checked">{{ activeText }}</span>
      </span>

上面的样式直接沿用el-switch的原有样式,并且我们可以自定义一个innerMode属性去控制是否将描述文本放到其中,当为ture时显示上述代码,当为false时还是el-switch的dom结构。到此我们的功能大致已经得到了,接下来就是一些细节处理,比如给每个开关按钮生成一个唯一的key,毕竟一个页面可能存在多个按钮。

js 复制代码
   function guid() {
      return 'xxxxxxxx'.replace(/[xy]/g, function (c) {
        const r = (Math.random() * 16) | 0
        const v = c === 'x' ? r : (r & 0x3) | 0x8
        return v.toString(16)
      })
      }

还有一个需要注意的是按钮的宽度,我们需要把描述文本完全展示出来,所以按钮的宽度最好能跟着文字多少去变动。我们声明一个变量表示按钮的最小宽度,该值就由文字的多少动态的计算出来,通过比较开关描述文本得到最大宽度,然后按照一个字1px去累加基础宽度。

js 复制代码
   // 计算宽度
   get minCoreWidth() {
    const maxTextLen = Math.max(
      this.activeText.length,
      this.inactiveText.length
    )
    return `calc(${maxTextLen}em + 30px)`
  }

剩下的就是根据check去动态修改样式,我们可以根据自己的需求去设置props跟样式。

总结

如果我们碰到描述文本在内部的开关,并且不能随意升级的话,可以尝试自己去封装一个组件,本质上还是在现有组件基础上进行二次封装。

相关推荐
玖釉-5 小时前
解决PowerShell执行策略导致的npm脚本无法运行问题
前端·npm·node.js
Larcher6 小时前
新手也能学会,100行代码玩AI LOGO
前端·llm·html
徐子颐6 小时前
从 Vibe Coding 到 Agent Coding:Cursor 2.0 开启下一代 AI 开发范式
前端
小月鸭6 小时前
如何理解HTML语义化
前端·html
jump6807 小时前
url输入到网页展示会发生什么?
前端
诸葛韩信7 小时前
我们需要了解的Web Workers
前端
brzhang7 小时前
我觉得可以试试 TOON —— 一个为 LLM 而生的极致压缩数据格式
前端·后端·架构
yivifu7 小时前
JavaScript Selection API详解
java·前端·javascript
这儿有一堆花7 小时前
告别 Class 组件:拥抱 React Hooks 带来的函数式新范式
前端·javascript·react.js
十二春秋7 小时前
场景模拟:基础路由配置
前端