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

前言

开关组件是日常开发中常见的一个组件,公司产品中也用到了开关组件,使用的是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跟样式。

总结

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

相关推荐
weixin_382395235 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__5 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.5 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~6 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华7 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子9 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅9 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni10 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学11 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端