element-ui input组件源码分析整理笔记(六)


input 输入框组件

源码:




如下图所示:

(2)核心部分 input 输入框


1、 :tabindex="tabindex" 是控制tab键按下后的访问顺序,由用户传入tabindex;如果设置为负数则无法通过tab键访问,设置为0则是在最后访问。

2、 v-bind="$attrs" 为了简化父组件向子组件传值,props没有注册的属性,可以通过$attrs来取。

3、inputDisabled :返回当前input是否被禁用;readonly:input的原生属性,是否是只读状态;

4、 原生方法compositionstart、compositionupdate、compositionend

compositionstart 官方解释 : 触发于一段文字的输入之前(类似于 keydown 事件,但是该事件仅在若干可见字符的输入之前,而这些可见字符的输入可能需要一连串的键盘操作、语音识别或者点击输入法的备选词),通俗点,假如我们要输入一段中文,当我们按下第一个字母的时候触发 。
compositionupdate在我们中文开始输入到结束完成的每一次keyup触发。
compositionend则在我们完成当前中文的输入触发 。

这三个事件主要解决中文输入的响应问题,从compositionstart触发开始,意味着中文输入的开始且还没完成,所以此时我们不需要做出响应,在compositionend触发时,表示中文输入完成,这时我们可以做相应事件的处理。

 handleComposition(event) {
        // 如果中文输入已完成
        if (event.type === 'compositionend') {
          //  isOnComposition设置为false
          this.isOnComposition = false;
          this.currentValue = this.valueBeforeComposition;
          this.valueBeforeComposition = null;
          //触发input事件,因为input事件是在compositionend事件之后触发,这时输入未完成,不会将值传给父组件,所以需要再调一次input方法
          this.handleInput(event);
        } else {  //如果中文输入未完成
          const text = event.target.value;
          const lastCharacter = text[text.length - 1] || '';
          //isOnComposition用来判断是否在输入拼音的过程中
          this.isOnComposition = !isKorean(lastCharacter);
          if (this.isOnComposition && event.type === 'compositionstart') {
            //  输入框中输入的值赋给valueBeforeComposition
            this.valueBeforeComposition = text;
          }
        }
      },
      handleInput(event) {
        const value = event.target.value;
        //设置当前值
        this.setCurrentValue(value);
        //如果还在输入中,将不会把值传给父组件
        if (this.isOnComposition) return;
        //输入完成时,isOnComposition为false,将值传递给父组件
        this.$emit('input', value);
      },

(3)calcTextareaHeight.js使用来计算文本框的高度

//原理:让height等于scrollHeight,也就是滚动条卷去的高度,这里就将height变大了,然后返回该height并绑定到input的style中从而动态改变textarea的height
let hiddenTextarea;
//存储隐藏时候的css样式的
const HIDDEN_STYLE = `
  height:0 !important;
  visibility:hidden !important;
  overflow:hidden !important;
  position:absolute !important;
  z-index:-1000 !important;
  top:0 !important;
  right:0 !important
`;
//用来存储要查询的样式名
const CONTEXT_STYLE = [
  'letter-spacing',
  'line-height',
  'padding-top',
  'padding-bottom',
  'font-family',
  'font-weight',
  'font-size',
  'text-rendering',
  'text-transform',
  'width',
  'text-indent',
  'padding-left',
  'padding-right',
  'border-width',
  'box-sizing'
];

function calculateNodeStyling(targetElement) {
  // 获取目标元素计算后的样式,即实际渲染的样式
  const style = window.getComputedStyle(targetElement);
  // getPropertyValue方法返回指定的 CSS 属性的值;这里返回box-sizing属性的值
  const boxSizing = style.getPropertyValue('box-sizing');
  // padding-bottom和padding-top值之和
  const paddingSize = (
    parseFloat(style.getPropertyValue('padding-bottom')) +
    parseFloat(style.getPropertyValue('padding-top'))
  );
  // border-bottom-width和border-top-width值之和
  const borderSize = (
    parseFloat(style.getPropertyValue('border-bottom-width')) +
    parseFloat(style.getPropertyValue('border-top-width'))
  );
  // 其他属性以及对应的值
  const contextStyle = CONTEXT_STYLE
    .map(name => `${name}:${style.getPropertyValue(name)}`)
    .join(';');

  return { contextStyle, paddingSize, borderSize, boxSizing };
}

export default function calcTextareaHeight(
  targetElement, //目标元素
  minRows = 1, //最小行数
  maxRows = null //最大行数
) {
    // 创建一个隐藏的文本域
  if (!hiddenTextarea) {
    hiddenTextarea = document.createElement('textarea');
    document.body.appendChild(hiddenTextarea);
  }
  //获取目标元素的样式
  let {
    paddingSize,
    borderSize,
    boxSizing,
    contextStyle
  } = calculateNodeStyling(targetElement);
  //设置对应的样式属性
  hiddenTextarea.setAttribute('style', `${contextStyle};${HIDDEN_STYLE}`);
  hiddenTextarea.value = targetElement.value || targetElement.placeholder || '';

  // 获取滚动高度
  let height = hiddenTextarea.scrollHeight;
  const result = {};

  if (boxSizing === 'border-box') {
    // 如果是 border-box,高度需加上边框
    height = height + borderSize;
  } else if (boxSizing === 'content-box') {
   // 如果是 content-box,高度需减去上下内边距
    height = height - paddingSize;
  }
  // 计算单行高度,先清空内容
  hiddenTextarea.value = '';
  // 再用滚动高度减去上下内边距
  let singleRowHeight = hiddenTextarea.scrollHeight - paddingSize;

  if (minRows !== null) {  // 如果参数传递了 minRows
      // 最少的高度=单行的高度*行数
    let minHeight = singleRowHeight * minRows;
    if (boxSizing === 'border-box') {
      // 如果是 border-box,还得加上上下内边距和上下边框的宽度
      minHeight = minHeight + paddingSize + borderSize;
    }
    // 高度取二者最大值
    height = Math.max(minHeight, height);
    result.minHeight = `${ minHeight }px`;
  }
  if (maxRows !== null) {
    let maxHeight = singleRowHeight * maxRows;
    if (boxSizing === 'border-box') {
      maxHeight = maxHeight + paddingSize + borderSize;
    }
    height = Math.min(maxHeight, height);
  }
  result.height = `${ height }px`;
  hiddenTextarea.parentNode && hiddenTextarea.parentNode.removeChild(hiddenTextarea);
  hiddenTextarea = null;
  return result;
};

参考博文:https://www.jianshu.com/p/74ba49507fe6
https://juejin.im/post/5b7d18e46fb9a01a12502616