preface

In order to practice the ability of packaging components, I plan to study Elment UI components and learn their design and code.

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.

The first thing we want to study is the Button component, which is the most commonly used and most familiar. We will implement the Button features introduced in the official documentation one by one.

The preparatory work

Create a new empty project using vue-CLI

vue create my-element-ui
Copy the code

Create a Button folder under the Components folder in your project, create an index.vue, and write the code for the Button component. In the root directory, create the Views folder, create the ButtonShownPage folder, and create the index.vue folder to display the button components.

In ButtonShownPage I’ll write

<template> <el-button @click="handleClick"> </el-button> </template> <script> import ElButton from '.. /.. /components/Button/index' export default { name: 'ButtonShownPage', methods: { handleClick(evt) { console.log('handleClick', evt); } }, components: { ElButton } } </script>Copy the code

So we started to focus on coding the Button and getting it rendered properly

Write a basic Button

After some simple fumbling, I wrote the following code in the Button component:

<template>
    <button 
        class="el-button"
        @click="handleClick"
    >
        <span v-if="$slots.default"><slot></slot></span>
    </button>
</template>

<script>

export default {
    name: 'Button',
    methods: {
        handleClick(evt) {
            this.$emit('click', evt);
        }
    }
}
</script>

<style>
.el-button {
    display: inline-block;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    background: #fff;
    border: 1px solid #dcdfe6;
    color: #606266;
    -webkit-appearance: none;
    text-align: center;
    box-sizing: border-box;
    outline: none;
    margin: 0;
    transition: .1s;
    font-weight: 500;
    -moz-user-select: none;
    -webkit-user-select: none;
    -ms-user-select: none;
    padding: 12px 20px;
    font-size: 14px;
    border-radius: 4px;
}

.el-button:focus, .el-button:hover {
    color: #409eff;
    border-color: #c6e2ff;
    background-color: #ecf5ff;
}

.el-button:active {
    color:#3a8ee6;
    border-color:#3a8ee6;
    outline:none
}
</style>
Copy the code

Use the button tag as the base of the component to write styles that include default, focus, hover, and active states. With slot containing the button content, the click event is exposed. The basic buttons are there.

To increase type

Now let’s make our button support type: primary, success, Info, Warning, danger.

Write the test code in ButtonShownPage first:

<el-button @click="handleClick"> default button </el-button> <el-button type="primary"> Main button </el-button> <el-button </el-button> <el-button type="info"> </el-button> <el-button type="warning"> <el-button type="danger"> </el-button>Copy the code

Write logic code in Button:

<template>
    <button 
        class="el-button"
        :class="[type ? 'el-button--' + type : '']"
        @click="handleClick"
    >
        <span v-if="$slots.default"><slot></slot></span>
    </button>
</template>

<script>

export default {
    name: 'Button',
    props: {
        type: {
            type: String,
            default: 'default',
        },
    },
    methods: {
        handleClick(evt) {
            this.$emit('click', evt);
        }
    }
}
</script>
Copy the code

Add a prop named Type, default to default, and style the button label based on the value passed in. El-button –primary class = “primary”;

.el-button--primary {
    color: #fff;
    background-color: #409eff;
    border-color: #409eff;
}

.el-button--primary:focus, .el-button--primary:hover {
    background: #66b1ff;
    border-color: #66b1ff;
    color: #fff;
}
Copy the code

Add another style like this:

.el-button+.el-button {
    margin-left: 10px;
}
Copy the code

You can increase the spacing of the buttons next to each other, as shown in the picture below:

Plain, round and circle

All three are the same as Type in that they add classes to control style

<template>
    <button 
        class="el-button"
        :class="[type ? 'el-button--' + type : '',
         {
            'is-plain': plain,
            'is-round': round,
            'is-circle': circle
        }]"
        @click="handleClick"
    >
        <span v-if="$slots.default"><slot></slot></span>
    </button>
</template>
Copy the code

Add the plain, round, and circle properties to props.

props: {
        type: {
            type: String,
            default: 'default',
        },
        plain: Boolean,
        round: Boolean,
        circle: Boolean
    },
Copy the code

Because there are so many styles to reference and the principle is the same, I use the browser developer tools to copy the elementUI styles directly into assets.

In this way, the effect is as follows:

Our buttons now support multiple forms.

Here, we have copied all the styles of Elemnnt, so we do not need to care about the style writing in the future, but only care about the logic of tags and JS to realize the corresponding functions. However, we can use browser tools to continue to study the style details in the presentation results.

Support icon

Add an Icon component:

<template>
  <i :class="'el-icon-' + name"></i>
</template>

<script>
  export default {
    name: 'ElIcon',
    props: {
      name: String
    }
  };
</script>
Copy the code

Introduce the Icon component into the Button,

<template>
    <button 
        class="el-button"
        :class="[type ? 'el-button--' + type : '',
         {
            'is-plain': plain,
            'is-round': round,
            'is-circle': circle
        }]"
        @click="handleClick"
    >
        <el-i :class="icon" v-if="icon"></el-i>
        <span v-if="$slots.default"><slot></slot></span>
    </button>
</template>
Copy the code

This works:

Disabled state

  1. Add a property disabled to the component
  2. Bind the disabled component to the button tag property to ensure that the click event does not take effect
  3. Add ‘IS-disabled’ to :class: disabled.

The effect is as follows:

Text button, icon button

Our component now supports both styles of buttons.

Button group

Add a ButtonGroup component. Again, the key is the control style

<template>
  <div class="el-button-group">
    <slot></slot>
  </div>
</template>
<script>
  export default {
    name: 'ElButtonGroup'
  };
</script>
Copy the code

Use as follows:

<el-button-group> <el-button type="primary" icon="el-icon-arrow-left"> </el-button> <el-button type="primary"> next < I class="el-icon-arrow-right el-icon--right"></i></el-button> </el-button-group>Copy the code

The rendering looks like this:

In the load

  1. Add a property loading to the component
  2. To give the class a ‘is – loading: loading, make disabled, disabled = “disabled | | loading”
<el-i class="el-icon-loading" v-if="loading"></el-i> <el-i :class="icon" v-if="icon && ! loading"></el-i>Copy the code

The effect is as follows:

Size of the button

Same routine as type, add a size attribute, control class.

conclusion

So much for the basic button components. All examples are as follows:

All code for this article has been uploaded to 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