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.

  1. 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