element文本域选择框_Element分析(组件篇)——Input


input组件相对来说复杂一点,我们先从它用到的一个工具库calcTextareaHeight.js进行分析。

calcTextareaHeight.js

calcTextareaHeight.js使用来计算文本框的高度的,我们根据代码顺序从上往下进行分析。

HIDDEN_STYLE

HIDDEN_STYLE是一个常量,存储隐藏时候的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

`;

CONTEXT_STYLE

CONTEXT_STYLE也是一个常量,用来存储要查询的样式名。

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'

];

calculateNodeStyling

calculateNodeStyling用来获取结点的某些样式。

function calculateNodeStyling(node) {undefined

const style = window.getComputedStyle(node); // 获取结点的计算后的样式,即实际渲染的样式

const boxSizing = style.getPropertyValue('box-sizing'); // 获取 box-sizing 的值

// 上下的 padding 之和

const paddingSize = (

parseFloat(style.getPropertyValue('padding-bottom')) +

parseFloat(style.getPropertyValue('padding-top'))

);

// 上下的边框宽度和(其实是看上去的高度)

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 };

}

calcTextareaHeight

calcTextareaHeight是最终暴露出去的函数,用来计算文本域的高度。

export default function calcTextareaHeight(

targetNode, // 要计算的结点

minRows = null, // 最小的行数

maxRows = null // 最大的行数

) {undefined

if (!hiddenTextarea) { // 来创建一个隐藏的文本域,所有的计算都是在这上面进行的

hiddenTextarea = document.createElement('textarea');

document.body.appendChild(hiddenTextarea);

}

// 获取结点一些样式值

let {undefined

paddingSize,

borderSize,

boxSizing,

contextStyle

} = calculateNodeStyling(targetNode);

// 设置相应的样式

hiddenTextarea.setAttribute('style', `${contextStyle};${HIDDEN_STYLE}`);

// 设置内容,按优先级一次是 结点的 value, 结点的 placeholder, 以及空字符串

hiddenTextarea.value = targetNode.value || targetNode.placeholder || '';

// 获取滚动高度

let height = hiddenTextarea.scrollHeight;

if (boxSizing === 'border-box') {undefined

// 如果是 border-box,说明高度得加上边框

height = height + borderSize;

} else if (boxSizing === 'content-box') {undefined

// 如果是 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); // 取二者最大值

}

if (maxRows !== null) { // 如果参数传递了 maxRows

let maxHeight = singleRowHeight * maxRows; // 说明最多只能有这么多行的高度

if (boxSizing === 'border-box') { // 如果是 border-box,还得加上上下内边距和上下边框的宽度

maxHeight = maxHeight + paddingSize + borderSize;

}

height = Math.min(maxHeight, height); // 取二者最小值

}

// 返回文本域应当设置的高度

return { height: height + 'px'};

};

input.vue

input组件较为繁琐,我们一点点分析。

生命周期

created

创建的时候会监听inputSelect事件,并调用inputSelect方法。

created() {undefined

this.$on('inputSelect', this.inputSelect);

},

inputSelect方法会调用refs上的input的原生的select方法,来选中该input。

methods: {undefined

inputSelect() {undefined

this.$refs.input.select();

},

}

mounted

挂载的时候,会调用resizeTextarea方法来设置文本域的大小。

mounted() {undefined

this.resizeTextarea();

}

methods: {undefined

resizeTextarea() {undefined

if (this.$isServer) return; // 如果是服务端渲染,直接返回,不进行下面的逻辑

var { autosize, type } = this;

if (!autosize || type !== 'textarea') return; // 如果 autosize 是 false,或者当前不是文本域,也直接返回

const minRows = autosize.minRows; // 最少行数

const maxRows = autosize.maxRows; // 最大行数

this.textareaStyle = calcTextareaHeight(this.$refs.textarea, minRows, maxRows); // 计算文本域的高度,并赋值

},

}

最外层

最外层是一个div,上面设置了一些动态的class。

type

type是一个prop,它默认设置为text,如果设置为textarea,表明当前是一个文本域。

props: {undefined

type: {undefined

type: String,

default: 'text'

},

}

size

size也是一个prop,用来设置输入框的大小,在textarea下无效。

props: {undefined

size: String,

}

disabled

disabled也是一个prop,用来设置是否可用。

props: {undefined

disabled: Boolean,

}

prepend、append

这两个都是在设置输入框组的时候使用的,通过具名slot传入,分别放置于input的首和尾。

input

然后,根据type的不同使用v-if分别渲染input或者textarea,我们先分析input部分。

前置元素

前置元素直接通过具名slot传入。

input 图标

图标也是通过具名slot传入的,也可以通过prop中的icon传入图标名。

class="el-input__icon"

:class="'el-icon-' + icon"

v-if="icon"

@click="handleIconClick">

上面还绑定了一个handleIconClick的点击事件,它会触发click事件:

methods: {undefined

handleIconClick(event) {undefined

this.$emit('click', event);

},

}

input

然后是最重要的input部分,上面大部分是prop,不进行讲解,其余的我们将一一讲解。

v-if="type !== 'textarea'"

class="el-input__inner"

:type="type" // 类型

:name="name" // 名字

:placeholder="placeholder" // 默认值

:disabled="disabled" // 是否禁用

:readonly="readonly" // 是否只读

:maxlength="maxlength" // 输入的最大长度

:minlength="minlength" // 输入的最小长度(暂时不支持)

:autocomplete="autoComplete" // 自动补全

:autofocus="autofocus" // 自动聚焦

:min="min" // 允许输入的最小值(数字或者日期)

:max="max" // 允许输入的最大值(数字或者日期)

:form="form" // 绑定的表单(不是原生的)

:value="currentValue" // 输入值

ref="input" // 引用

@input="handleInput" // 输入事件

@focus="handleFocus" // 获得焦点事件

@blur="handleBlur" // 失去焦点事件

>

value

value改变的时候会调用setCurrentValue。

watch: {undefined

'value'(val, oldValue) {undefined

this.setCurrentValue(val);

}

},

而setCurrentValue是用来改变当前值的。

methods: {undefined

setCurrentValue(value) {undefined

if (value === this.currentValue) return; // 如果新旧值一致直接返回

this.$nextTick(_ => {undefined

this.resizeTextarea(); // 下一个DOM更新周期时,重新设置文本域大小

});

this.currentValue = value; // 改变当前值

this.$emit('input', value); // 触发 input 事件

this.$emit('change', value); // 触发 change 事件

this.dispatch('ElFormItem', 'el.form.change', [value]); // 向父级的派发 el.form.change 事件

}

}

handleInput

处理输入事件。

methods: {undefined

handleInput(event) {undefined

this.setCurrentValue(event.target.value); // 改变当前值

},

}

handleFocus

handleFocus用来处理获得焦点的事件,会直接触发focus事件。

methods: {undefined

handleFocus(event) {undefined

this.$emit('focus', event);

},

}

handleBlur

handleBlur用来处理失去焦点的事件。

methods: {undefined

handleBlur(event) {undefined

this.$emit('blur', event); // 触发 blur 事件

this.dispatch('ElFormItem', 'el.form.blur', [this.currentValue]); // 向父组件派发 el.form.blur 事件

},

}

loading

loading会根据计算属性validating来决定是否渲染。

computed: {undefined

validating() {undefined

return this.$parent.validateState === 'validating';

}

},

后置元素

后置元素只能根据具名slot传入。

Textarea

如果type设置为textarea则会渲染textarea,上面绑定的都和input类似,不再多说,多了一个textareaStyle,是根据calcTextareaHeight计算出来的。

v-else

class="el-textarea__inner"

:value="currentValue"

@input="handleInput"

ref="textarea"

:name="name"

:placeholder="placeholder"

:disabled="disabled"

:style="textareaStyle"

:readonly="readonly"

:rows="rows"

:form="form"

:autofocus="autofocus"

:maxlength="maxlength"

:minlength="minlength"

@focus="handleFocus"

@blur="handleBlur">
————————————————
版权声明:本文为CSDN博主「weixin_39533896」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_39533896/article/details/111516689


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM