CSS 并不简单 -- 一个人性化输入框的实践

6,964 阅读3分钟
原文链接: www.jianshu.com

这次通过这个个性化的输入框,给大家介绍一些容易忽略的知识点。(新手注意:本文的html采用的是jade,css采用的sass,js采用的vue)

一、效果

 大家先看一下效果动态图,思考一波,带着你的思考来看接下来的内容,可能效果更好一点。


image

PC端demo地址

二、需求

 当我们开始做一样东西的时候一定要先分析它的需求:

  • 当输入框获取焦点时,提示文字发生上移动画,同时下面线条产生动画;
  • 当输入框失去焦点时,并且未填写内容时,提示文字和线条恢复之前的状态。
  • 当输入框失去焦点时,填写内容时,状态不变。

三、结构

 看了上面的效果图,首先就是要确定html的结构:

div.item
    input(type="text" name="card" id="card" placeholder="身份证" v-card="" maxlength="18")
    label(for="card") Card
    div.focusline

 这里唯一遗憾的是input不支持伪元素(::after、::before),所以不得不采用一个额外的div。
 这里额外提一下,maxlength 只能用于input的type为password和text的情况,所以不要再问为什么maxlength不起作用了。

四、表现

 其实对于上面所要实现的效果,我们完全可以通过JS来控制,但是一直在强调表现(CSS)与行为(JS)分离,所以我们完全通过CSS的特性解决表现上的问题,更加完美。但是并不是所有CSS属性浏览器多支持(这就尴尬了)。这里我要用的几个特性,大家最好在Chrome中实验。

 其实需求1与需求2是同一个需求,通过伪类focus和过渡属性就能搞定。

    input:focus + label {
        color: rgb(82,97,107);
        transform: translate(10px, 0) scale(.9);
    }
    input:focus ~ div {
        width: 100%;
    }

 对于第三个需求,我们就得用一些新玩意了,第一个就是伪元素placeholder(伪类采用: 而伪元素采用::), 这里我们要隐藏placeholder,好显示我们的label:

    input {
      &:placeholder {
          opacity: 0;
      }
    }

 我们知道当输入文字后,placeholder就不再显示了,所以这里来了一个伪类placeholder-shown(可以通过can i use 查一下它的兼容性):

    input:not(:placeholder-shown) + label {
      color: rgb(82,97,107);
      transform: translate(10px, 0) scale(.9);
    }
    input:not(:placeholder-shown) ~ div {
      width: 100%;
    }

五、行为

 这里我还要唠叨一下,从上面可以看出这是一个身份证输入框,我们多知道身份证是由数字和字母,而且字母只出现在第18位,而且只能是字母x。所以我上面采用了text类型的输入框,为了让用户很好的输入,会出现这几种问题:

  • 切换为中文输入法时存在的问题;
  • 复制粘贴的问题;
  • 输入其他非法字符的处理。

 这里我们主要通过input、compositionstart、compositionend、paste四个事件解决。

    let legalContent, //开启输入法之前的输入内容
        LOCK = false; //是否开启中文输入法
    el.addEventListener('compositionstart', (e) => {
      /**
       * --------------
       *  开启中文输入法
       * --------------
       */
      legalContent = e.target.value; //保存中文输入法之前的内容
      LOCK = true; //加上锁
    }, false);

    el.addEventListener('compositionend', (e) => {
      /**
       * ---------------------
       *  结束中文输入法
       * ---------------------
       */
      e.target.value = legalContent;
      LOCK = false; // 解锁
    }, false);


    el.addEventListener('input', (e) => {
      const len = e.target.value.length;

      /**
       * 在中文触发时 不进行处理
       * 当身份证号码少于18位时只能输入数字
       * 当身份证号码为18位时可以输入数字和字母
       */
      if (!LOCK) {
        if (len <= 17) {
          e.target.value = e.target.value.replace(/\D/,'');
        } else {
          e.target.value = e.target.value.replace(/[^0-9Xx]/,'');
        }
      }

    }, false);


    el.addEventListener('paste', (e) => {
      /**
       * ----------
       *  粘贴
       * ----------
       */
      e.preventDefault();  //阻止默认事件
    }, false);

觉得不错的同学,来一波关注吧,你的关注就是我写作的动力。
更多文章 简书
源码: GitHub