利用contenteditable模拟一个input组件,解决字体在IOS和安卓上的偏移问题

西梁 2020年04月22日 242次浏览

效果图

input垂直居中效果,在IOS中字体稍稍偏下,在安卓中偏上。
传统的办法是判断机型,通过控制行高或Padding去解决偏移问题,这种办法还需要去获取DOM高度。

我利用DOM的contenteditable属性,模拟一个input组件可以完美解决这个问题。

直接上代码:

// 组件名:Myinput
<template>
  <div
    class="input"
    ref="Input"
    contenteditable="plaintext-only"
    :placeholder="placeholder"
    :style="{ color: color,
              fontSize: fontSize / 100 + 'rem',
              fontWeight: fontWeight,
              width : width / 100 + 'rem'}"
    @blur="isBlur"
    @compositionstart="lockInput = true"
    @compositionend="change()"
    @input="change('input')">{{value}}</div>
</template>
<script>
let sel = window.getSelection()
let range = document.createRange()
export default {
  props: {
    value: {
      type: String,
      default: ''
    },
    placeholder: String,
    color: {
      type: String,
      default: '#474245'  // 字体颜色
    },
    width: {
      type: String,
      default: ''  // input宽度,方便布局
    },
    fontSize: {
      type: String,
      default: '28'  // 字体大小
    },
    fontWeight: {
      type: String,
      default: 'normal' // 字体粗细  'bold'
    },
    maxlength: {
      type: String,
      default: '0'  // 最大输入长度 0:不限制
    },
    type: {
      type: String,
      default: 'text'  // text:文本,number:数字类型
    }
  },
  data () {
    return {
      lockInput: false
    }
  },
  methods: {
    isBlur () {
      window.scrollTo(0, 0)  // IOS页面回弹
    },
    change (type) {
      if (type === 'input' && this.lockInput) {
        return
      } else {
        this.lockInput = false
      }
      let text = this.$refs['ypInput'].innerText
      if (this.type === 'number') {
	// 只允许输入数字
        text = text.replace(/[^0-9]/ig, '')
      }
      if (this.maxlength > 0 && text.length > this.maxlength) {
        text = text.substr(0, 16)
      }
      this.$refs['ypInput'].innerText = text
      this.keyEnd()
      this.$emit('input', text.replace(/\s/g, ''))
    },
    keyEnd () {
  	// 解决光标移位问题
      range.selectNodeContents(this.$refs['ypInput'])
      range.collapse(false)
      sel.removeAllRanges()
      sel.addRange(range)
    }
  }
}
</script>
<style lang="less" scoped>
.input {
  outline: none;
  flex-grow: 1;
  &:empty:before {
    content: attr(placeholder);
    display: block;
    color: #969696;
    font-weight: normal;
  }
}
</style>
// 使用组件
<my-input
  v-model='mobile'
  placeholder="请输入手机号"
  fontWeight="bold"
  maxlength="11"
  type="number"
/>
import MyInput from '@/components/MyInput'
components: { MyInput }