手撸一个纯纯的css表盘读数

259 阅读4分钟

前两天项目中遇到一个需求,实现一个水表/电表读数表盘,附上UI给的原型

image.png

刚看到说实话,一脸懵,有没有第三方插件use use,找了一圈没找到个合适的,没有捷径就老老实实手写吧

先分析,别小看样式没有清晰思路,还真写出来 首先了解个常识,水电表一般在99999.9的时候会清零进入下一轮,所以算上小数点,8位差不多够了.(你想多几个都可以)

自言自语balabala:左上角和右下角可以用图标解决,左上角标题下有一个梯形灰色背景 ,中间的读数,可以用一个带有圆角的背景框,然后再框子上放八个圆角矩形,倒数第二个不给高宽,没有值得时候显示为0,且颜色区分开,数字一看就不是通用的字体呈现出来的效果

正文开始:

html部分:

            <div v-for="(item, index) in waterDataList" :key="index">
              <p class="titleData">
                <img src="../image/waterIcon.png" alt="">
                <span>{{ item.name }}</span> <span> {{ item.date }}</span></p>
              <p>当前读表数/m³</p>
              <p class="numList">
                <span v-for="(num, index2) in item.numList" :key="index2" :class="num == null ? 'greyNum': ''">{{ num == null? '0': num }}</span>
              </p>
              <i class="el-icon-s-data"></i>
            </div>
          </div>

css部分:(这个项目没有less/sass咱也不知道为啥,咱也也不敢问,咱也不敢装)

{
    font-family: myFirstFont;
    src: url('../css/font/AzureoN.ttf'); // 自己找的字体
}
#app {
    background-color: rgb(243, 240, 240);
    padding: 20px;
}
p {
    margin: 0;
}
.waterPage {
    overflow-y: auto;
  }
  .waterPage  div {
    width: 30%;
    height: 26vh;
    display: inline-block;
    background: #fff;
    box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.1);
    border-radius: 4px;
    margin: 0px 20px 20px 0px;
  }
  .titleData img {
    width: 18px;
    height: 15px;
    margin-left: 16px;
  }
  .titleData span:nth-child(2){
    display: inline-block;
    width: 45%;
    height: 50px;
    background: linear-gradient(90deg, #FEFEFE, #F1F1F1);
    clip-path: polygon(100% 0, 75% 100%, 0% 100%, 0 0);
    line-height: 50px;
    padding-left: 12px;
    color: #505BD2;
    font-size: 16px;
    font-weight: bold;

  }
  .titleData span:nth-child(3) {
    float: right;
    padding-right: 16px;
    display: inline-block;
    height: 50px;
    line-height: 50px;
    font-size: 14px;
    font-weight: 400;
    color: #959595;
  }
  .waterPage p:nth-child(2){
    font-size: 20px;
    font-weight: 400;
    color: #959595;
    line-height: 50px;
    text-align: center;
    margin: 12px 0px;
  }
  .numList {
    width: 70%;
    height: 25%;
    max-height: 70px;
    background: #1C5971;
    border-radius: 10px;
    margin: 0 auto;
    color: #ffffff;
    padding: 12px;
    display: flex;
    justify-content: space-between;
  }
  .numList span{
    display: inline-block;
    width: 11%;
    height: 80%;
    line-height: 100%;
    text-align: center;
    font-size: 3rem;
    margin: auto 0;
    background: rgba(0, 0, 0, 0.4);
    box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.88), 0px -1px 0px 0px rgba(255, 255, 255, 0.35);
    border-radius: 4px;
    font-family: myFirstFont;
    padding-left: 1%;

  }
  .numList span:nth-child(7){
    width: 5%;
    height: 70%;
    background: none;
    box-shadow: none;
    color: #FFA32C;
  }
  .numList span:nth-child(8){
    background: #FFA32C;
  }
  .greyNum {
    color: rgba(255, 255, 255, 0.05);
  }
  .waterPage i{
    color: #505BD2;
    float: right;
    padding-right: 16px;
    opacity: 0.5;
  }

最后就是data数据填充了,最开始模拟的时候是写死的,先上一年级要求(先把效果实现)

waterDataList: [
                    {name: '设备1', date: '2021-11-22 15:30', numList: [null,null,null,1,8,0,'.',1]},
                    {name: '设备2', date: '2021-11-23 08:20', numList: [null,null,null,1,9,0,'.',5]},
                    {name: '设备3', date: '2021-11-24 14:50', numList: [null,null,1,2,3,0,'.',7]},
                    {name: '设备4', date: '2021-11-25 16:50', numList: [null,1,1,2,3,0,'.',9]},

                    ],

从数据可以看出来,固定数组长度为8,倒数第二个必须是小数点,获取到的值截取之后位数不够补null,为啥要补null,因为html判断中就是根据它判断的,喜欢与否,任君选择. 可是后端返回的数据是这样式的:

const res = [
                        {
                            "id": 37,
                            "name": "添加设备测试2",
                            "reading": 56.4,
                            "time": "2021-11-24 14:46:49"
                        },
                        {
                            "id": 40,
                            "name": "测试添加5-修改",
                            "reading": 0,
                            "time": "2021-11-24 16:49:53"
                        },
                        {
                            "id": 42,
                            "name": "测试绑定盒子非必要编辑",
                            "reading": 0,
                            "time": "2021-11-24 16:49:53"
                        },
                        {
                            "id": 43,
                            "name": "能耗设备测试",
                            "reading": 665544.12,
                            "time": "2021-11-24 15:31:13"
                        }
                    ]
                   

这里面我要把reading字段的值处理成data中合适的格式,再上个三年级水平的处理:

this.waterDataList = res.map(item => {
  // 处理返回的数据保留一位小数,再拆分字符串为单个字符组成数组,不够8位补null
  const str = item.reading.toFixed(1)
  const numList = str.split('')
  if(numList.length !== 8) {
    const count = 8 - numList.length
    for (let i =0; i<count; i++){
      numList.unshift(null)
    }
  }
  return {
    id: item.id,
    name: item.name,
    time: item.time,
    reading: item.reading,
    numList: numList
  }
})

看到这个,有大佬会说了,你不知道unshift多影响性能吗,不知道尽量不要用他吗? 但咱的数组固定呀,拢共就八位,你说能内耗到哪里,存在即合理,你用不用它都在那里.

为了展示下咱也是有小学五年级水平的,再思考下,大不了拆分后我反转呗,

this.waterDataList = res.map(item => {
 const numList = (item.reading).toFixed(1).split('').reverse().concat(null,null,null,null,null,null,null,null).splice(0,8).reverse()
  }
  return {
    id: item.id,
    name: item.name,
    time: item.time,
    reading: item.reading,
    numList: numList
  }
})

OK,水平有限的我只能实现到这了,最后上上前端的效果图

image.png

这还原度产品经理再挑刺我也没话说了,代码吗,反正他挑不来,不过我还是非常欢迎五年级以上水平大佬的留下您老宝贵的精简的实现方式O(∩_∩)O哈哈~