1. 程式人生 > 其它 >element文字域選擇框_Element分析(元件篇)——Input

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