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