The input component is relatively complex. Let's start with a tool library it uses.Conduct analysis.
To calculate the height of the text box, we analyze it from top to bottom according to the code order.
HIDDEN_STYLE
HIDDEN_STYLE is a constant that stores the css style when hidden.
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 is also a constant used to store the style name to be queried.
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 is used to obtain certain styles of nodes.
function calculateNodeStyling(node) { const style = (node); // Get the calculated style of the node, that is, the actual rendering style const boxSizing = ('box-sizing'); // Get the value of box-sizing // The sum of paddings on the upper and lower const paddingSize = ( parseFloat(('padding-bottom')) + parseFloat(('padding-top')) ); // The width and width of the upper and lower borders (actually the height that looks) const borderSize = ( parseFloat(('border-bottom-width')) + parseFloat(('border-top-width')) ); // Some other styles const contextStyle = CONTEXT_STYLE .map(name => `${name}:${(name)}`) .join(';'); return { contextStyle, paddingSize, borderSize, boxSizing }; }
calcTextareaHeight
calcTextareaHeight is the ultimate exposed function to calculate the height of the text field.
export default function calcTextareaHeight( targetNode, // The node to be calculated minRows = null, // Minimum number of rows maxRows = null // Maximum number of rows) { if (!hiddenTextarea) { // Create a hidden text field, all calculations are performed on it hiddenTextarea = ('textarea'); (hiddenTextarea); } // Get some style values of nodes let { paddingSize, borderSize, boxSizing, contextStyle } = calculateNodeStyling(targetNode); // Set the corresponding style ('style', `${contextStyle};${HIDDEN_STYLE}`); // Set content, once according to priority, the value of the node, the placeholder of the node, and the empty string = || || ''; // Get scrolling height let height = ; if (boxSizing === 'border-box') { // If it is border-box, the height must be added with a border height = height + borderSize; } else if (boxSizing === 'content-box') { // If it is a content-box, it means that the upper and lower margins must be subtracted. height = height - paddingSize; } // Calculate the height of a single line and clear the content first = ''; // Use the scroll height to subtract the upper and lower inner margins let singleRowHeight = - paddingSize; if (minRows !== null) { // If the parameter is passed minRows let minHeight = singleRowHeight * minRows; // It means that there should be at least so many rows of heights if (boxSizing === 'border-box') { // If it is a border-box, you must add the upper and lower inner margins and the width of the upper and lower borders. minHeight = minHeight + paddingSize + borderSize; } height = (minHeight, height); // Take the maximum value of both } if (maxRows !== null) { // If the parameter is passed maxRows let maxHeight = singleRowHeight * maxRows; // It means that at most you can only have so many rows of heights if (boxSizing === 'border-box') { // If it is a border-box, you must add the upper and lower inner margins and the width of the upper and lower borders. maxHeight = maxHeight + paddingSize + borderSize; } height = (maxHeight, height); // Take the minimum value of both } // Returns the height that the text field should set return { height: height + 'px'}; };
The input component is quite complicated, so let's analyze it little by little.
life cycle
created
When created, the inputSelect event will be listened to and the inputSelect method will be called.
created() { this.$on('inputSelect', ); },
The inputSelect method will call the native select method of the input on refs to select the input.
methods: { inputSelect() { this.$(); }, }
mounted
When mounted, the resizeTextarea method will be called to set the size of the text field.
mounted() { (); }
methods: { resizeTextarea() { if (this.$isServer) return; // If it is server rendering, return directly without performing the following logic var { autosize, type } = this; if (!autosize || type !== 'textarea') return; // If autosize is false, or is not currently a text field, it will also be returned directly const minRows = ; // Minimum number of rows const maxRows = ; // Maximum number of rows = calcTextareaHeight(this.$, minRows, maxRows); // Calculate the height of the text field and assign values }, }
The outermost layer
The outermost layer is a div with some dynamic classes set on it.
<div :class="[ type === 'textarea' ? 'el-textarea' : 'el-input', size ? 'el-input--' + size : '', { 'is-disabled': disabled, 'el-input-group': $ || $, 'el-input-group--append': $, 'el-input-group--prepend': $ } ]"> </div>
type
type is a prop, which is set to text by default. If set to textarea, it indicates that it is currently a text field.
props: { type: { type: String, default: 'text' }, }
size
size is also a prop, used to set the size of the input box, which is invalid under textarea.
props: { size: String, }
disabled
disabled is also a prop to set whether it is available or not.
props: { disabled: Boolean, }
prepend、append
Both of these are used when setting the input box group. They are passed in through a named slot and placed at the beginning and end of the input respectively.
input
Then, use v-if to render input or textarea respectively according to different types. We first analyze the input part.
Prefixed elements
The prefix element is passed directly through the named slot.
<div class="el-input-group__prepend" v-if="$"> <slot name="prepend"></slot> </div>
input icon
The icon is also passed through the named slot, and the icon name can also be passed through the icon in the prop.
<slot name="icon"> <i class="el-input__icon" :class="'el-icon-' + icon" v-if="icon" @click="handleIconClick"> </i> </slot>
There is also a click event of handleIconClick, which will trigger the click event:
methods: { handleIconClick(event) { this.$emit('click', event); }, }
input
Then there is the most important input part. Most of the above are props and will not be explained. We will explain the rest one by one.
<input v-if="type !== 'textarea'" class="el-input__inner" :type="type" // type :name="name" // name :placeholder="placeholder" // default value :disabled="disabled" // Whether to disable :readonly="readonly" // Whether to read only :maxlength="maxlength" // Maximum length of input :minlength="minlength" // The minimum length of input (not supported for the time being) :autocomplete="autoComplete" // Automatic completion :autofocus="autofocus" // Autofocus :min="min" // Minimum value allowed (number or date) :max="max" // The maximum value allowed to enter (number or date) :form="form" // The bound form (not native) :value="currentValue" // Enter value ref="input" // Quote @input="handleInput" // Enter an event @focus="handleFocus" // Get focus events @blur="handleBlur" // Lost focus event>
value
SetCurrentValue will be called when the value changes.
watch: { 'value'(val, oldValue) { (val); } },
setCurrentValue is used to change the current value.
methods: { setCurrentValue(value) { if (value === ) return; // If the old and new values are consistent, return directly this.$nextTick(_ => { (); // Reset the text field size during the next DOM update cycle }); = value; // Change the current value this.$emit('input', value); // Trigger input event this.$emit('change', value); // Trigger change event ('ElFormItem', '', [value]); // Dispatch events to parent } }
handleInput
Process input events.
methods: { handleInput(event) { (); // Change the current value }, }
handleFocus
handleFocus is used to handle events that gain focus and will directly contact the focus event.
methods: { handleFocus(event) { this.$emit('focus', event); }, }
handleBlur
handleBlur is used to handle events that lose focus.
methods: { handleBlur(event) { this.$emit('blur', event); // Trigger the blur event ('ElFormItem', '', []); // Send events to the parent component }, }
loading
Loading will determine whether to render based on the computed property validating.
computed: { validating() { return this.$ === 'validating'; } },
<i class="el-input__icon el-icon-loading" v-if="validating"></i>
Post-elements
Post-elements can only be passed in according to the named slot.
<div class="el-input-group__append" v-if="$"> <slot name="append"></slot> </div>
Textarea
If the type is set to textarea, the textarea will be rendered. The bounds above are similar to input. I won’t say more. There is an additional textareaStyle, which is calculated based on 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>
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.