The research idea of this paper is to read Element source code, and then automatically write components step by step to improve their corresponding functions.
Layout Layout
After looking at Input and Button, let’s look at the implementation of the Element layout. Let’s see what we can learn.
Element is a quick and easy way to create a layout with 24 columns. The implementation principle is to use percentages, treating a row as 100% width and dividing it into 24 equal parts.
- If your columns span :span=24. El-col-24 {width: 100%;
}. 2. If your columns span :span=12 El-col-12 {width: 50%; }. 3. If your columns span: SPAN =8 El-col-8 {width: 33.3333%; }. And so on.
The principle is to control col component styles based on the SPAN property.
Detailed code in the code cloud: gitee.com/DaBuChen/my…
Link Text Link component
The logic of the Link component is much simpler than that of the Button component. Different from native A tags, add type, disable attributes, and support for underline control, beautify the style.
Here’s a quick summary of how Element encapsulates a component.
First, it expands the function of native tags. Make some commonly used functions directly supported by attributes. For example, disable Link. You can do this by configuring the Disable attribute. If we write with native tag A, we need to write our own logic.
Second, it provides a unified visual style. Allows us to stack components to get a good visual effect. For example, Button and Link have several fixed types. Display major, success, information, warning, danger and other feedback to the user.
Detailed code in the code cloud: gitee.com/DaBuChen/my…
Radio Radio buttons
Continue our research tour to see what features Radio extends native.
Native radio must have the same name in order to achieve radio function.
<form> Which color do you prefer? <br> <input type="radio" name="colors" Checked ID ="red"> red <br> <input type="radio" name="colors" ID ="blue"> blue <br> <input Type ="radio" name="colors" id="green">Copy the code
Native radio uses the Checked property to indicate that the check is not checked. Element’s radio approach is completely different. Multiple radio v-models are bound to the same attribute. If the attribute value is the same as lablel’s, the item is selected.
<el-radio V-model ="radio" label="1"> alternative </el-radio> <el-radio V-model ="radio" label="2"> Alternative </el-radio>Copy the code
The most basic implementation
What is new is that computed Model attributes are used to store values using GET /set, and checked to control native radio is not checked:
<template> <label class="el-radio" :class="[ { 'is-checked': model === label } ]" > <span class="el-radio__input" :class="{ 'is-checked': model === label }" > <span class="el-radio__inner"></span> <input ref="radio" class="el-radio__original" :value="label" type="radio" v-model="model" @change="handleChange" > </span> <span class="el-radio__label" @keydown.stop> <slot></slot> <template v-if="! $slots.default">{{label}}</template> </span> </label> </template> <script> export default { name: 'ElRadio', props: { value: {}, label: {}, }, computed: { model: { get() { return this.value; }, set(val) { this.$emit('input', val); this.$refs.radio && (this.$refs.radio.checked = this.model === this.label); } }, }, methods: { handleChange() { this.$nextTick(() => { this.$emit('change', this.model); }); } } } </script>Copy the code
The effect is as follows:
Disabled state
Add the disable style {‘ IS-disabled ‘: disabled} for the outer tag and bind the input[‘radio’] tag :disabled=”disabled”.
The effect is as follows:
Radio button group
Binding v-Models for each el-radio was a bit of a hassle, so an el-radio-group was added. Attach the V-Model to it. That would be an interesting implementation.
<template> <el-radio-group V-model ="radio"> <el-radio :label="3"> Alternative </el-radio> <el-radio :label="6"> Alternative </el-radio> <el-radio :label="9"> Alternative </el-radio> </el-radio-group> </template> <script> export default {data () {return {radio: 3}; } } </script>Copy the code
Let’s implement a basic el-radio-group:
<template>
<div
class="el-radio-group"
role="radiogroup"
>
<slot></slot>
</div>
</template>
<script>
export default {
name: 'ElRadioGroup',
componentName: 'ElRadioGroup',
props: {
value: {},
}
}
</script>
Copy the code
Very simply, use value to receive the value of the V-Model. Identify yourself with componentName, easy for EL-Radio to find. The big story is the implementation of EL-Radio.
First of all to achieve a broadcast, is to let the event layer by layer bubble up, the specific code is not posted here, you can see my follow-up to the code cloud on the source code. And then we introduce it with mixins.
import Emitter from '.. /.. /mixins/emitter' ... mixins: [Emitter],Copy the code
Alter model get/set
model: { get() { return this.isGroup() ? this._radioGroup.value : this.value; }, set(val) { if (this.isGroup()) { this.dispatch('ElRadioGroup', 'input', [val]); } else { this.$emit('input', val); } this.$refs.radio && (this.$refs.radio.checked = this.model === this.label); }},... isGroup() { let parent = this.$parent; while (parent) { if (parent.$options.componentName ! == 'ElRadioGroup') { parent = parent.$parent; } else { this._radioGroup = parent; return true; } } return false; },Copy the code
Check whether the current el-radio is in the el-radio-group by using isGroup. If, the get of model will take the value of el-radio-group, and the set will trigger the input event of el-radio-group by using the dispatch method of the broadcaster, so as to change the value of the v-Model binding attribute of the user in el-radio-Group.
With a frame
This is the style addition. Add {‘ IS-bordered ‘: border} to the root tag class. The effect is as follows:
Button style
For button-style radio, Element writes a new component, radio-button. The basic logic is similar to that of the Radio component. Post the code below:
<template> <label class="el-radio-button" :class="[ { 'is-active': value === label }, { 'is-disabled': disabled }, { 'is-focus': focus } ]" > <input class="el-radio-button__orig-radio" :value="label" type="radio" v-model="value" @change="handleChange" :disabled="disabled" > <span class="el-radio-button__inner" @keydown.stop> <slot></slot> <template v-if="! $slots.default">{{label}}</template> </span> </label> </template> <script> import Emitter from '.. /.. /mixins/emitter' export default { name: 'ElRadioButton', mixins: [Emitter], props: { label: {}, disabled: Boolean, }, computed: { value: { get() { return this._radioGroup.value; }, set(value) { this._radioGroup.$emit('input', value); } }, _radioGroup() { let parent = this.$parent; while (parent) { if (parent.$options.componentName ! == 'ElRadioGroup') { parent = parent.$parent; } else { return parent; } } return false; }, }, methods: { handleChange() { this.$nextTick(() => { this.$emit('change', this.model); }); }, } } </script>Copy the code
The effect is as follows:
Detailed code in the code cloud: gitee.com/DaBuChen/my…
Other component source code study:
Element component source research -Button
Element component source research -Input Input box
Element component source research -Layout, Link, Radio
Element component source research -Checkbox multi-checkbox
Element component source research -InputNumber counter
Element component source code study -Loading component
Element component source research -Message component