高仿Element.ui搭建属于自己的ui组件库(1)

新建vue脚手架项目

  1. Element.ui内部使用的css预编译为scss,所以我们选择dart-scss即可,其余正常创建;
  2. 剃干净初始化的项目,什么helloworld组件统统清理掉
  3. /components下新建button.vue文件,作为我们第一个尝试的button组件
  4. main.js中导入该组件并注册为全局组件
import Vue from 'vue'
import App from './App.vue'
import HButton from './components/button'
import './static/iconfont.css'

Vue.config.productionTip = false
Vue.component(HButton.name, HButton)

new Vue({
  render: h => h(App)
}).$mount('#app')

搭建button组件

常用属性

  1. /App.vue父组件
<h-button plain round circle icon='hButton-icon-gou' @click="showClick">默认h-button>
<h-button plain round circle icon='hButton-icon-shanchu1' @click="showClick" type='primary'>主要h-button>
<h-button plain round circle icon='hButton-icon-shanchu1' @click="showClick" type='success'>成功h-button>
<h-button plain round circle icon='hButton-icon-shanchu1' @click="showClick" type='info'>信息h-button>
<h-button plain round circle icon='hButton-icon-shanchu1' @click="showClick" type='warning'>警告h-button>
<h-button plain round circle icon='hButton-icon-gou' @click="showClick" type='danger'>危险h-button>

说明:plain就表示:plain = true;round表示:round = true;以此类推

我们通过父组件向子组件传值的方式,来处理

  1. /button.vue子组件

这里有五个常用的属性,type,plain,round,circle,disabled

<div class="hButton" :class='[
    `hButton-${type}`,
    {"is-plain":plain},
    {"is-round":round},
    {"is-circle":circle},
    {"is-disabled":disabled}]'
    @click="handleClick">
    <i v-if="icon" :class="[icon]">i>
    <span v-if="$slots.default"><slot>slot>span>
div>
  1. 通过绑定类的语法糖来对传递过来的属性分别给予不同的类(每个类样式不一)
.hButton-primary.is-plain{
    color: #409eff;
    background: #ecf5ff;
    margin-left: 20px;
    &:hover,
    &:focus{
        background: #409eff;
        border-color: #409eff;
        color: #fff;
    }
}
.hButton-primary{
    color:#fff;
    background-color: #409eff;
    border-color: #409eff;
    margin-left: 20px;
    &:hover,
    &:focus{
        background: #66b1ff;
        background-color: #66b1ff;
        color: #fff;
    }
}

// 设置圆角
.hButton.is-round{
    border-radius: 20px;
    padding: 12px 23px;
}

// 设置圆形
.hButton.is-circle{
    border-radius: 50%;
    padding: 12px;
}

//设置disabled
.hButton.is-disabled{
    cursor: no-drop;
}
  1. 通过props校验来获取父子通信传递的值
//组件名
name: 'HButton',
// prop校验,无需校验可传入数组
props: {
    type: {
        type: String,
        default: 'default'
    },
    plain: {
        type: Boolean,
        default: false
    },
    round: {
        type: Boolean,
        default: false
    },
    circle: {
        type: Boolean,
        default: false
    },
    disabled: {
        type: Boolean,
        default: false
    },
    icon: {
        type: String,
        default: ''
    }
},

字体图标

  1. 借助阿里图标库在文件目录新疆 /static.iconfont.css文件
  2. main.js中导入iconfont.css文件
  3. 将iconfont统一改为我们命名的组件名
[class*='hButton-icon'] {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.hButton-icon-gou:before {
  content: "\e610";
}

.hButton-icon-shanchu1:before {
  content: "\e63c";
}
  1. 在组件中通过icon借助父子通信来实现
<h-button plain round circle icon='hButton-icon-gou' @click="showClick" type='danger'>危险h-button>
<i v-if="icon" :class="[icon]">i>

事件

  1. 我们通过自定义事件来处理事件

子向父传递的事件名一定要和要触发的事件名保持一致

@click="handleClick"
methods: {
     handleClick (e) {
         // 此处的事件名要和子组件的事件名一致
         this.$emit('**click**', e)
     }
 },
  1. 父组件接受该事件
<h-button plain round circle icon='hButton-icon-gou' @**click**="showClick" type='danger'>危险h-button>
methods: {
  showClick () {
    console.log('按钮被点击了')
  }
}

效果图

高仿Element.ui搭建属于自己的ui组件库(1)_第1张图片

总结与展望

1.现在有没有觉得封装一个ui组件就是利用vue的一些常见知识:如v-model,父子通信,绑定类.样式,自定义事件等等来实现,此处我们是借助Element.ui的样式来开始我们的案例,但具体我们想封装什么样的组件,我们只需要改变样式,改变事件方法,改变属性的内容等等即可。
2. 本文的主要目的是通过一个入门案例来阐述封装组件的套路和思路,接下来我们还有好多好多组件要去实现,input,dialog,calendar,等等。当我们组件库有一定数量和质量了,我们可以将我们的组件库代码发布到github上,让更多人看到和使用。

附源代码

/App.vue父组件

<template>
  <div id="app">
    <h-button>默认</h-button>
    <h-button type='primary'>主要</h-button>
    <h-button type='success'>成功</h-button>
    <h-button type='info'>信息</h-button>
    <h-button type='warning'>警告</h-button>
    <h-button type='danger'>危险</h-button>
    <hr/>
    <h-button plain>默认</h-button>
    <h-button plain type='primary'>主要</h-button>
    <h-button plain type='success'>成功</h-button>
    <h-button plain type='info'>信息</h-button>
    <h-button plain type='warning'>警告</h-button>
    <h-button plain type='danger'>危险</h-button>
    <hr/>
    <h-button plain round class='hButton-icon-gou'>默认</h-button>
    <h-button plain round type='primary'>主要</h-button>
    <h-button plain round type='success'>成功</h-button>
    <h-button plain round type='info'>信息</h-button>
    <h-button plain round type='warning'>警告</h-button>
    <h-button plain round type='danger'>危险</h-button>
    <hr/>
    <h-button plain round circle icon='hButton-icon-gou' @click="showClick">默认</h-button>
    <h-button plain round circle icon='hButton-icon-shanchu1' @click="showClick" type='primary'>主要</h-button>
    <h-button plain round circle icon='hButton-icon-shanchu1' @click="showClick" type='success'>成功</h-button>
    <h-button plain round circle icon='hButton-icon-shanchu1' @click="showClick" type='info'>信息</h-button>
    <h-button plain round circle icon='hButton-icon-shanchu1' @click="showClick" type='warning'>警告</h-button>
    <h-button plain round circle icon='hButton-icon-gou' @click="showClick" type='danger'>危险</h-button>
    <hr/>
    <h-button plain round circle icon='hButton-icon-gou' disabled @click="showClick"></h-button>
    <h-button plain round circle icon='hButton-icon-shanchu1' disabled @click="showClick" type='primary'></h-button>
    <h-button plain round circle icon='hButton-icon-shanchu1' disabled @click="showClick" type='success'></h-button>
    <h-button plain round circle icon='hButton-icon-shanchu1' disabled @click="showClick" type='info'></h-button>
    <h-button plain round circle icon='hButton-icon-shanchu1' disabled @click="showClick" type='warning'></h-button>
    <h-button plain round circle icon='hButton-icon-gou' disabled @click="showClick" type='danger'></h-button>
  </div>
</template>

<script>

export default {
  methods: {
    showClick () {
      console.log('按钮被点击了')
    }
  }
}
</script>

<style lang="scss">
  hr{
    margin: 30px auto;
  }
</style>

/button.vue子组件

<template>
    <div class="hButton" :class='[
        `hButton-${type}`,
        {"is-plain":plain},
        {"is-round":round},
        {"is-circle":circle},
        {"is-disabled":disabled}]'
        @click="handleClick">
        <i v-if="icon" :class="[icon]"></i>
        <span v-if="$slots.default"><slot></slot></span>
    </div>
    
</template>

<script>
export default {
    name: 'HButton',
    // prop校验,无需校验可传入数组
    props: {
        type: {
            type: String,
            default: 'default'
        },
        plain: {
            type: Boolean,
            default: false
        },
        round: {
            type: Boolean,
            default: false
        },
        circle: {
            type: Boolean,
            default: false
        },
        disabled: {
            type: Boolean,
            default: false
        },
        icon: {
            type: String,
            default: ''
        }
    },
    methods: {
        handleClick (e) {
            // 此处的事件名要和子组件的事件名一致
            this.$emit('click', e)
        }
    },
    created () {
        // 获取插槽内容
        console.log(this.$slots)
    }
}
</script>

<style lang="scss" scoped>
    // 默认样式
    .hButton{
        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: 0.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;
        &:hover,
        &:focus{
            color: #409eff;
            border-color: #c6e2ff;
            background-color: #ecf5ff;
        }
    }

    // 各种类型样式
    .hButton-primary{
        color:#fff;
        background-color: #409eff;
        border-color: #409eff;
        margin-left: 20px;
        &:hover,
        &:focus{
            background: #66b1ff;
            background-color: #66b1ff;
            color: #fff;
        }
    }
    .hButton-success{
        color:#fff;
        background-color: #67c23a;
        border-color: #67c23a;
        margin-left: 20px;
        &:hover,
        &:focus{
            background: #85ce61;
            background-color: #85ce61;
            color: #fff;
        }
    }
    .hButton-info{
        color:#fff;
        background-color: #909399;
        border-color: #909399;
        margin-left: 20px;
        &:hover,
        &:focus{
            background: #a6a9ad;
            background-color: #a6a9ad;
            color: #fff;
        }
    }
    .hButton-warning{
        color:#fff;
        background-color: #e6a23c;
        border-color: #e6a23c;
        margin-left: 20px;
        &:hover,
        &:focus{
            background: #ebb563;
            background-color: #ebb563;
            color: #fff;
        }
    }
    .hButton-danger{
        color:#fff;
        background-color: #f56c6c;
        border-color: #f56c6c;
        margin-left: 20px;
        &:hover,
        &:focus{
            background: #f78989;
            background-color: #f78989;
            color: #fff;
        }
    }

    // 各种类型朴素样式
    .hButton.is-plain{
        &:hover,
        &:focus{
            background: #fff;
            border-color: #489eff;
            color: #409eff;
        }
    }
    .hButton-primary.is-plain{
        color: #409eff;
        background: #ecf5ff;
        margin-left: 20px;
        &:hover,
        &:focus{
            background: #409eff;
            border-color: #409eff;
            color: #fff;
        }
    }
    .hButton-success.is-plain{
        color: #67c23a;
        background: #c2e7b0;
        margin-left: 20px;
        &:hover,
        &:focus{
            background: #67c23a;
            border-color: #67c23a;
            color: #fff;
        }
    }
    .hButton-info.is-plain{
        color: #909399;
        background: #d3d4d6;
        margin-left: 20px;
        &:hover,
        &:focus{
            background: #909399;
            border-color: #909399;
            color: #fff;
        }
    }
    .hButton-warning.is-plain{
        color: #e6a23c;
        background: #f5dab1;
        margin-left: 20px;
        &:hover,
        &:focus{
            background: #e6a23c;
            border-color: #e6a23c;
            color: #fff;
        }
    }
    .hButton-danger.is-plain{
        color: #f56c6c;
        background: #fbc4c4;
        margin-left: 20px;
        &:hover,
        &:focus{
            background: #f56c6c;
            border-color: #f56c6c;
            color: #fff;
        }
    }

    // 设置圆角
    .hButton.is-round{
        border-radius: 20px;
        padding: 12px 23px;
    }

    // 设置圆形
    .hButton.is-circle{
        border-radius: 50%;
        padding: 12px;
    }

    //设置disabled
    .hButton.is-disabled{
        cursor: no-drop;
    }

    //所有图标后的span左边距
    [class*='hButton-icon']+span{
        margin-left: 5px;
    }
</style>

/main.js文件入口

import Vue from 'vue'
import App from './App.vue'
import HButton from './components/button'
import './static/iconfont.css'

Vue.config.productionTip = false
Vue.component(HButton.name, HButton)

new Vue({
  render: h => h(App)
}).$mount('#app')

你可能感兴趣的:(组件化,vue)