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

前言

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

总结

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

相关推荐
轻口味1 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王2 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发2 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀2 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪3 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef4 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6415 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻5 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云5 小时前
npm淘宝镜像
前端·npm·node.js