使用 label 标签 解决 IE10 以下 input 的 placeholder 不显示问题

8/12/2020 HTML

IE 是前端一生的夙敌

# 问题引出

没人不认识这个把:

<input name="username" placeholder="请输入用户名" />
1

就一个输入框,然后没输入值情况下显示 请输入用户名
偏偏 IE10 以下就不认识 placeholder 兼容性 (opens new window)

我真是,惊呆了。。。

# 冷静分析

采用 <label></label> 标签

为何?

我们需要把文字,用定位的方式定在输入框上,可是又不能挡住 input 的聚焦,所以不论是普通的 div 还是伪元素都不行

  • 而 label 标签有一个 for 属性,点击的时候可以触发对应的组件
  • input 不支持伪元素,所以就算用伪元素写,也是写在父级 div

# 撸码解决

# html 结构

先确定下 html。既然要用定位,那我们还是给 input 多包裹一层 div。正常 input 也会有 div 包裹了~

由于我们要解决的只是 IE 的问题,所以 label 默认不写,通过 js 来动态添加

<div class="form-item user-name">
  <input name="username" placeholder="请输入用户名" />
</div>
1
2
3

# css 样式

label-placeholder 是将要动态添加的 label 的样式

还用到了 css 的兄弟选择器(+)用于控制输入框获得焦点后,lable 隐藏

.form-item {
  position: relative;
}

.label-placeholder {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 28px;
  font-size: 14px;
  text-align: left;
  z-index: 10;
  color: #999;
}

/* input聚焦的时候,lable自动隐藏 */
.form-item input:focus + .label-placeholder {
  display: none;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 重头戏 JS

  • initPlaceholder

    • 这里采用闭包,避免多次创建的时候还要重复判断 IE 版本
    • 其次尽量减少全局变量的使用,避免造成污染
  • window.onload

    • 所有的操作在 dom 节点挂载后才操作
  • 只有 IE 6-9 的版本才使用

initPlaceholder 方法主要接收一个对象,其中对象包含 targetId,placeholder,blur
分别对应 input 的 id 属性,要显示的 placeholder 和 失去焦点的方法

这里必须要通过 ID 传递,因为 lable 的 for 标签只认 ID 属性

接下来,JS 封装好了,要用的时候就是调用 initPlaceholder 方法,然后自动判断版本,如果非 IE,或者非 IE6-9 版本的,直接用浏览器的功能,不过还是注册上了 blur 事件

 



















 





















 










var initPlaceholder = (function() {
  var userAgent = navigator.userAgent //取得浏览器的userAgent字符串
  var isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1 //判断是否IE<11浏览器
  var reIE = new RegExp('MSIE (\\d+\\.\\d+);')
  var fIEVersion = parseFloat(RegExp['$1']) || -1 // 代表不是IE
  return function(data) {
    var _data = data || {}
    var targetId = _data.targetId || null
    var blurFn = _data.blur || null
    if (!targetId) {
      throw Error('targetId is cannot be null')
      return false
    }
    var target = document.getElementById(targetId)
    if (!target) {
      throw Error(targetId + ' is does not exist')
      return false
    }

    // IE 环境
    if (fIEVersion >= 6 && fIEVersion <= 9) {
      var parent = target.parentNode
      var childLabel = document.createElement('label')
      childLabel.setAttribute('class', 'label-placeholder')
      childLabel.setAttribute('for', targetId)
      childLabel.innerHTML = _data.placeholder || ''
      parent.appendChild(childLabel)
      target.onblur = function(event) {
        blurFn && blurFn.call(this, event)
        if (this.value != '') {
          childLabel.style.display = 'none'
        } else {
          childLabel.style.display = ''
        }
      }
    } else if (blurFn) {
      // 非IE环境,不过有回调方法,直接注册回调方法
      target.onblur = blurFn
    }
  }
})()

window.onload = function() {
  initPlaceholder({
    targetId: 'username',
    placeholder: '请输入用户名',
    blur: function(e) {
      console.log(e)
      console.log(this.value)
    }
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# 完整的 demo

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .form-item {
        position: relative;
      }

      .label-placeholder {
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        font-size: 14px;
        text-align: left;
        z-index: 10;
        color: #999;
      }

      /* input聚焦的时候,lable自动隐藏 */
      .form-item input:focus + .label-placeholder {
        display: none;
      }
    </style>
  </head>
  <body>
    <div class="form-item username">
      <input name="username" placeholder="请输入用户名" id="username" />
    </div>
    <div class="form-item">
      <input name="username" placeholder="请输入用户名" id="password" />
    </div>
    <script>
      var initPlaceholder = (function() {
        var userAgent = navigator.userAgent //取得浏览器的userAgent字符串
        var isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1 //判断是否IE<11浏览器
        var reIE = new RegExp('MSIE (\\d+\\.\\d+);')
        var fIEVersion = parseFloat(RegExp['$1']) || -1 // 代表不是IE
        return function(data) {
          var _data = data || {}
          var targetId = _data.targetId || null
          var blurFn = _data.blur || null
          if (!targetId) {
            throw Error('targetId is cannot be null')
            return false
          }
          var target = document.getElementById(targetId)
          if (!target) {
            throw Error(targetId + ' is does not exist')
            return false
          }

          // IE 环境
          if (fIEVersion >= 6 && fIEVersion <= 9) {
            var parent = target.parentNode
            var childLabel = document.createElement('label')
            childLabel.setAttribute('class', 'label-placeholder')
            childLabel.setAttribute('for', targetId)
            childLabel.innerHTML = _data.placeholder || ''
            parent.appendChild(childLabel)
            target.onblur = function(event) {
              blurFn && blurFn.call(this, event)
              if (this.value != '') {
                childLabel.style.display = 'none'
              } else {
                childLabel.style.display = ''
              }
            }
          } else if (blurFn) {
            // 非IE环境,不过有回调方法,直接注册回调方法
            target.onblur = blurFn
          }
        }
      })()

      window.onload = function() {
        initPlaceholder({
          targetId: 'username',
          placeholder: '请输入用户名',
          blur: function(e) {
            console.log(e)
            console.log(this.value)
          }
        })

        initPlaceholder({
          targetId: 'password',
          placeholder: '请输入密码'
        })
      }
    </script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

# 总结

对于 initPlaceholder 只是一个简单的封装,而且尽可能用 JS 原生语法,毕竟考虑到是 IE 浏览器

其次其实这个 demo 局限性还是很大的,比如 label 的文本并没有垂直居中,然而垂直居中最快的方式就是 line-height。所以这个还是留给具体的业务场景,拿到高度,在设置line-height.

其次这个方法必须依赖于 input 的父级 div,并且对应父级 div 还必须有相对定位才可以

虽然局限性很大,不过对于能解决 IE 的问题,我觉得这已经是非常欣慰了~

Last Updated: 5/9/2021, 10:45:03 PM