Element Input組件分析小結(jié)
input組件相對來說復(fù)雜一點,我們先從它用到的一個工具庫calcTextareaHeight.js進(jìn)行分析。
calcTextareaHeight.js
calcTextareaHeight.js使用來計算文本框的高度的,我們根據(jù)代碼順序從上往下進(jìn)行分析。
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用來獲取結(jié)點的某些樣式。
function calculateNodeStyling(node) {
const style = window.getComputedStyle(node); // 獲取結(jié)點的計算后的樣式,即實際渲染的樣式
const boxSizing = style.getPropertyValue('box-sizing'); // 獲取 box-sizing 的值
// 上下的 padding 之和
const paddingSize = (
parseFloat(style.getPropertyValue('padding-bottom')) +
parseFloat(style.getPropertyValue('padding-top'))
);
// 上下的邊框?qū)挾群停ㄆ鋵嵤强瓷先サ母叨龋?
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是最終暴露出去的函數(shù),用來計算文本域的高度。
export default function calcTextareaHeight(
targetNode, // 要計算的結(jié)點
minRows = null, // 最小的行數(shù)
maxRows = null // 最大的行數(shù)
) {
if (!hiddenTextarea) { // 來創(chuàng)建一個隱藏的文本域,所有的計算都是在這上面進(jìn)行的
hiddenTextarea = document.createElement('textarea');
document.body.appendChild(hiddenTextarea);
}
// 獲取結(jié)點一些樣式值
let {
paddingSize,
borderSize,
boxSizing,
contextStyle
} = calculateNodeStyling(targetNode);
// 設(shè)置相應(yīng)的樣式
hiddenTextarea.setAttribute('style', `${contextStyle};${HIDDEN_STYLE}`);
// 設(shè)置內(nèi)容,按優(yōu)先級一次是 結(jié)點的 value, 結(jié)點的 placeholder, 以及空字符串
hiddenTextarea.value = targetNode.value || targetNode.placeholder || '';
// 獲取滾動高度
let height = hiddenTextarea.scrollHeight;
if (boxSizing === 'border-box') {
// 如果是 border-box,說明高度得加上邊框
height = height + borderSize;
} else if (boxSizing === 'content-box') {
// 如果是 content-box,說明得減去上下內(nèi)邊距
height = height - paddingSize;
}
// 計算單行高度,先清空內(nèi)容
hiddenTextarea.value = '';
// 再用滾動高度減去上下內(nèi)邊距
let singleRowHeight = hiddenTextarea.scrollHeight - paddingSize;
if (minRows !== null) { // 如果參數(shù)傳遞了 minRows
let minHeight = singleRowHeight * minRows; // 說明最少應(yīng)當(dāng)有這么多行的高度
if (boxSizing === 'border-box') { // 如果是 border-box,還得加上上下內(nèi)邊距和上下邊框的寬度
minHeight = minHeight + paddingSize + borderSize;
}
height = Math.max(minHeight, height); // 取二者最大值
}
if (maxRows !== null) { // 如果參數(shù)傳遞了 maxRows
let maxHeight = singleRowHeight * maxRows; // 說明最多只能有這么多行的高度
if (boxSizing === 'border-box') { // 如果是 border-box,還得加上上下內(nèi)邊距和上下邊框的寬度
maxHeight = maxHeight + paddingSize + borderSize;
}
height = Math.min(maxHeight, height); // 取二者最小值
}
// 返回文本域應(yīng)當(dāng)設(shè)置的高度
return { height: height + 'px'};
};
input.vue
input組件較為繁瑣,我們一點點分析。
生命周期
created
創(chuàng)建的時候會監(jiān)聽inputSelect事件,并調(diào)用inputSelect方法。
created() {
this.$on('inputSelect', this.inputSelect);
},
inputSelect方法會調(diào)用refs上的input的原生的select方法,來選中該input。
methods: {
inputSelect() {
this.$refs.input.select();
},
}
mounted
掛載的時候,會調(diào)用resizeTextarea方法來設(shè)置文本域的大小。
mounted() {
this.resizeTextarea();
}
methods: {
resizeTextarea() {
if (this.$isServer) return; // 如果是服務(wù)端渲染,直接返回,不進(jìn)行下面的邏輯
var { autosize, type } = this;
if (!autosize || type !== 'textarea') return; // 如果 autosize 是 false,或者當(dāng)前不是文本域,也直接返回
const minRows = autosize.minRows; // 最少行數(shù)
const maxRows = autosize.maxRows; // 最大行數(shù)
this.textareaStyle = calcTextareaHeight(this.$refs.textarea, minRows, maxRows); // 計算文本域的高度,并賦值
},
}
最外層
最外層是一個div,上面設(shè)置了一些動態(tài)的class。
<div :class="[
type === 'textarea' ? 'el-textarea' : 'el-input',
size ? 'el-input--' + size : '',
{
'is-disabled': disabled,
'el-input-group': $slots.prepend || $slots.append,
'el-input-group--append': $slots.append,
'el-input-group--prepend': $slots.prepend
}
]">
</div>
type
type是一個prop,它默認(rèn)設(shè)置為text,如果設(shè)置為textarea,表明當(dāng)前是一個文本域。
props: {
type: {
type: String,
default: 'text'
},
}
size
size也是一個prop,用來設(shè)置輸入框的大小,在textarea下無效。
props: {
size: String,
}
disabled
disabled也是一個prop,用來設(shè)置是否可用。
props: {
disabled: Boolean,
}
prepend、append
這兩個都是在設(shè)置輸入框組的時候使用的,通過具名slot傳入,分別放置于input的首和尾。
input
然后,根據(jù)type的不同使用v-if分別渲染input或者textarea,我們先分析input部分。
前置元素
前置元素直接通過具名slot傳入。
<div class="el-input-group__prepend" v-if="$slots.prepend"> <slot name="prepend"></slot> </div>
input 圖標(biāo)
圖標(biāo)也是通過具名slot傳入的,也可以通過prop中的icon傳入圖標(biāo)名。
<slot name="icon"> <i class="el-input__icon" :class="'el-icon-' + icon" v-if="icon" @click="handleIconClick"> </i> </slot>
上面還綁定了一個handleIconClick的點擊事件,它會觸發(fā)click事件:
methods: {
handleIconClick(event) {
this.$emit('click', event);
},
}
input
然后是最重要的input部分,上面大部分是prop,不進(jìn)行講解,其余的我們將一一講解。
<input v-if="type !== 'textarea'" class="el-input__inner" :type="type" // 類型 :name="name" // 名字 :placeholder="placeholder" // 默認(rèn)值 :disabled="disabled" // 是否禁用 :readonly="readonly" // 是否只讀 :maxlength="maxlength" // 輸入的最大長度 :minlength="minlength" // 輸入的最小長度(暫時不支持) :autocomplete="autoComplete" // 自動補(bǔ)全 :autofocus="autofocus" // 自動聚焦 :min="min" // 允許輸入的最小值(數(shù)字或者日期) :max="max" // 允許輸入的最大值(數(shù)字或者日期) :form="form" // 綁定的表單(不是原生的) :value="currentValue" // 輸入值 ref="input" // 引用 @input="handleInput" // 輸入事件 @focus="handleFocus" // 獲得焦點事件 @blur="handleBlur" // 失去焦點事件 >
value
value改變的時候會調(diào)用setCurrentValue。
watch: {
'value'(val, oldValue) {
this.setCurrentValue(val);
}
},
而setCurrentValue是用來改變當(dāng)前值的。
methods: {
setCurrentValue(value) {
if (value === this.currentValue) return; // 如果新舊值一致直接返回
this.$nextTick(_ => {
this.resizeTextarea(); // 下一個DOM更新周期時,重新設(shè)置文本域大小
});
this.currentValue = value; // 改變當(dāng)前值
this.$emit('input', value); // 觸發(fā) input 事件
this.$emit('change', value); // 觸發(fā) change 事件
this.dispatch('ElFormItem', 'el.form.change', [value]); // 向父級的派發(fā) el.form.change 事件
}
}
handleInput
處理輸入事件。
methods: {
handleInput(event) {
this.setCurrentValue(event.target.value); // 改變當(dāng)前值
},
}
handleFocus
handleFocus用來處理獲得焦點的事件,會直接觸發(fā)focus事件。
methods: {
handleFocus(event) {
this.$emit('focus', event);
},
}
handleBlur
handleBlur用來處理失去焦點的事件。
methods: {
handleBlur(event) {
this.$emit('blur', event); // 觸發(fā) blur 事件
this.dispatch('ElFormItem', 'el.form.blur', [this.currentValue]); // 向父組件派發(fā) el.form.blur 事件
},
}
loading
loading會根據(jù)計算屬性validating來決定是否渲染。
computed: {
validating() {
return this.$parent.validateState === 'validating';
}
},
<i class="el-input__icon el-icon-loading" v-if="validating"></i>
后置元素
后置元素只能根據(jù)具名slot傳入。
<div class="el-input-group__append" v-if="$slots.append"> <slot name="append"></slot> </div>
Textarea
如果type設(shè)置為textarea則會渲染textarea,上面綁定的都和input類似,不再多說,多了一個textareaStyle,是根據(jù)calcTextareaHeight計算出來的。
<textarea 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"> </textarea>
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
原生JS實現(xiàn)Vue transition fade過渡動畫效果示例
這篇文章主要為大家介紹了原生JS實現(xiàn)Vue transition fade過渡動畫效果示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
vue+element table表格實現(xiàn)動態(tài)列篩選的示例代碼
這篇文章主要介紹了vue+element table表格實現(xiàn)動態(tài)列篩選的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
關(guān)于el-form中el-input輸入框的寬度問題詳解
自從用了element-ui,確實好用,該有的組件都有,下面這篇文章主要給大家介紹了關(guān)于el-form中el-input輸入框的寬度問題的相關(guān)資料,需要的朋友可以參考下2023-01-01
vue中循環(huán)多個li(表格)并獲取對應(yīng)的ref的操作代碼
我想要獲取每一個循環(huán)并獲取每一個li(或者其它循環(huán)項)的ref,以便于后續(xù)的操作,接下來通過本文給大家分享vue中循環(huán)多個li(表格)并獲取對應(yīng)的ref的操作代碼,感興趣的朋友跟隨小編一起看看吧2024-02-02
vue使用showdown并實現(xiàn)代碼區(qū)域高亮的示例代碼
這篇文章主要介紹了vue使用showdown并實現(xiàn)代碼區(qū)域高亮的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
vue-cli如何修改打包項目結(jié)構(gòu)及前綴
這篇文章主要介紹了vue-cli如何修改打包項目結(jié)構(gòu)及前綴問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07

