首先我们知道vue里面包含有父子组件

但是你知道如果要进行一个element的手动组件封装

怎么封装吗

1首先第一步

首先我们建立一个组件

最好设置在一个文件目录下比如components

只是一个普通的组件

叫做OneButton.vue

    <template>
      <button class="one-button">
       按钮组件
      </button>
    </template>
     
    <script>
     
    export default {
      name: 'oneButton'
    }
</script>
     
    <style lang="scss">
</style>

要想使用该组件

就需要进行全局注册

就是在main.js里面注册了

 import Vue from 'vue'
    import App from './App.vue'
    // 第一步:导入button组件
    import OneButton from './components/button.vue'
     
    Vue.config.productionTip = false
     
    // 第二步:注册组件,设置(组件名,组件)
    Vue.component(OneButton.name, OneButton)
     
    new Vue({
      render: h => h(App)
    }).$mount('#app')

注册完成以后就可以进行使用了

<template>
  <div id="app">
    <one-button>按钮</one-button>

  </div>
</template>

<script>
export default {
  name: 'App',
  components: {}
}
</script>

<style lang="scss">
</style>

到这里

我们可以看到 就会显示一个普通按钮了

但是吧 这样的封装过于简单

能不能实现更加复杂的操作呢

于是

我们需要封装一个有element-ui风格的组件

好 那我们继续实现

我们先让文字可以自由的输入

那就要利用插槽了

 <template>
      <button class="one-button">
       <span><slot></slot></span>
      </button>
    </template>

我们的文件需要做以上处理

 <template>
      <div>
        <one-button>歌谣</one-button>
        <one-button>帅气</one-button>
        <one-button>关注我</one-button>
      </div>
    </template>

加上基本样式

 <style lang="scss">
      .one-button{
        display: inline-block;
        line-height: 1;
        white-space: nowrap;
        cursor: pointer;
        background: #ffffff;
        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;
        -moz-user-select: none;
        -ms-user-select: none;
        padding: 12px 20px;
        font-size: 14px;
        border-radius: 4px;
        &:hover,
        &:hover{
          color: #409eff;
          border-color: #c6e2ff;
          background-color: #ecf5ff;
        }
      }
    </style>

这样文字的效果就实现了

到了这里 你又想element里面可以控制type属性控制按钮样式

怎么可以实现呢

父元素传递type值

    <template>
      <div id="app">
        <div class="row">
        <one-button>按钮</one-button>
        <one-button type="primary">primary按钮</one-button>
        <one-button type="success">success按钮</one-button>
        <one-button type="info">info按钮</one-button>
        <one-button type="danger">danger按钮</one-button>
        <one-button type="warning">warning按钮</one-button>
        </div>
      </div>
    </template>

子元素接收当然props了

 export default {
      name: 'oneButton',
      // 此时对props进行校验,值接收string类型的type值
      props: {
        type:{
          type: String// 设置默认值:如果不传值,那么使用default
          default: 'default'
        }
      },
      created () {
        console.log(this.type)//defalut primary success info danger warning
      }
    }

做过处理以后根据type就可以实现数据的操作了

动态绑定样式

  <template>
      <button class="one-button" :class="`one-button-${type}`">
       <span><slot></slot></span>
      </button>
    </template>

最后定义好样式

  .one-button-primary{
      color:#fff;
      background-color: #409eff;
      border-color: #409eff;
      &:hover,
      &:focus{
        background: #66b1ff;
        background-color: #66b1ff;
        color: #fff;
        }
      }
      .one-button-success{
      color:#fff;
      background-color: #67c23a;
      border-color: #67c23a;
      &:hover,
      &:focus{
        background: #85ce61;
        background-color: #85ce61;
        color: #fff;
        }
      }
      .one-button-info{
      color:#fff;
      background-color: #909399;
      border-color: #909399;
      &:hover,
      &:focus{
        background: #a6a9ad;
        background-color: #a6a9ad;
        color: #fff;
        }
      }
      .one-button-warning{
      color:#fff;
      background-color: #e6a23c;
      border-color: #e6a23c;
      &:hover,
      &:focus{
        background: #ebb563;
        background-color: #ebb563;
        color: #fff;
        }
      }
      .one-button-danger{
      color:#fff;
      background-color: #f56c6c;
      border-color: #f56c6c;
      &:hover,
      &:focus{
        background: #f78989;
        background-color: #f78989;
        color: #fff;
        }
      }

运行

nice呀 有没有

这个时候你可能会想

如果设置plain属性怎么设置呢

和type类型相同,我们只要将样式先设置好,然后通过父组件传递过来的值进行判断,就可以设置plain属性了。

和type类型相同,我们只要将样式先设置好,然后通过父组件传递过来的值进行判断,就可以设置plain属性了。

第一步:父组件组件传递plain值

    <template>
      <div id="app">
        <div class="row">
        <one-button plain>按钮</one-button>
        <one-button plain type="primary">primary按钮</one-button>
        <one-button plain type="success">success按钮</one-button>
        <one-button plain type="info">info按钮</one-button>
        <one-button plain type="danger">danger按钮</one-button>
        <one-button plain type="warning">warning按钮</one-button>
        </div>
      </div>
    </template>

第二步:子组件接收负组件传递的数据,同样进行props校验,并且设置默认值为false

      props: {
        plain: {
          type: Boolean,
          default: false
        }
      }

第三步:通过绑定类名的方法动态控制样式,由于plain类型是布尔值,所以在类型中我们使用对象的形式来控制样式

    <template>
      <button class="one-button" :class="[`one-button-${type}`,{
        'is-plain':plain
      }]">
       <span><slot></slot></span>
      </button>
    </template>

第四步:设置不同类型的样式,由于plain类型是以对象的形式在类中定义的,所以使用获取属性的方法定义样式

    // 朴素按钮样式
    .one-button.is-plain{
      &:hover,
      &:focus{
        background: #fff;
        border-color: #489eff;
        color: #409eff;
      }
    }
    .one-button-primary.is-plain{
      color: #409eff;
      background: #ecf5ff;
      &:hover,
      &:focus{
        background: #409eff;
        border-color: #409eff;
        color: #fff;
      }
    }
    .one-button-success.is-plain{
      color: #67c23a;
      background: #c2e7b0;
      &:hover,
      &:focus{
        background: #67c23a;
        border-color: #67c23a;
        color: #fff;
      }
    }
    .one-button-info.is-plain{
      color: #909399;
      background: #d3d4d6;
      &:hover,
      &:focus{
        background: #909399;
        border-color: #909399;
        color: #fff;
      }
    }
    .one-button-warning.is-plain{
      color: #e6a23c;
      background: #f5dab1;
      &:hover,
      &:focus{
        background: #e6a23c;
        border-color: #e6a23c;
        color: #fff;
      }
    }
    .one-button-danger.is-plain{
      color: #f56c6c;
      background: #fbc4c4;
      &:hover,
      &:focus{
        background: #f56c6c;
        border-color: #f56c6c;
        color: #fff;
      }
    }

nice呀 有没有

round属性也是一样

button组件的round属性

设置round属性和之前的相似,只要在组件中定义好了样式,动态获取属性值即可。

获取属性值:

        round: {
          type: Boolean,
          default: false
        }

round样式:

    .one-button.is-round{
      border-radius: 20px;
      padding: 12px 23px;
    }

看看效果

nice有没有

到这里

我们看看字体图标怎么实现

字体图标也是要引入的

第一步:在main.js中引入字体图标

import './assets/fonts/iconfont.css'

第二步:将下载的字体图标css文件中的类名做修改,我将icon全部改为了one-icon,并且将初始的iconfont类改为了[class*='one-icon'],当类名中有one-icon时使用,如下

    [class*='one-icon'] {
      font-family: "iconfont" !important;
      font-size: 16px;
      font-style: normal;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
    }
    .one-icon-bluetoothoff:before {
      content: "\e697";
    }

第三步:父组件传递图标名,子组件接收并且放到图标中

父组件传值:

        <div class="row">
          <one-button icon="bluetoothon"></one-button>
          <one-button type="primary" icon="camera">照相机</one-button>
          <one-button type="success" icon="course"></one-button>
          <one-button type="info" icon="bluetooth_link"></one-button>
          <one-button type="danger" icon="addto"></one-button>
          <one-button type="warning" icon="audio"></one-button>
        </div>

子组件接收:

        icon: {
          type: String,
          default: ''
        }

使用接收到的字体图标。在没有传入icon时隐藏<i>标签,在slot插槽没有传入值时,不显示<span>标签

    <template>
      <button class="one-button" :class="[`one-button-${type}`,{
        'is-plain':plain,
        'is-round':round,
        'is-circle':circle,
      }]">
      <i v-if="icon" :class="`one-icon-${icon}`"></i>
      <!-- 如果没传入文本插槽,则不显示span内容 -->
       <span v-if="$slots.default"><slot></slot></span>
      </button>
    </template>

第四步:设置icon配套样式,使图标和文字之间有一定间隔

    .one-button [class*=one-icon-]+span{
      margin-left: 5px;
    }

查看效果

nice有没有

到这里

我们想一想element里面还有点击事件怎么实现

button组件中的点击事件

我们在使用组件时,直接给组件定义事件是不会被触发的。我们需要在组件中定义一个点击事件,这个点击事件不进行其他操作,只出发父组件中的点击事件。

组件中的定义点击事件:

    <template>
      <button class="one-button" :class="[`one-button-${type}`,{
        'is-plain':plain,
        'is-round':round,
        'is-circle':circle,
      }]"
      @click="handleClick"
      >
      <i v-if="icon" :class="`one-icon-${icon}`"></i>
      <!-- 如果没传入文本插槽,则不显示span内容 -->
       <span v-if="$slots.default"><slot></slot></span>
      </button>
    </template>

 定义一个点击事件,这个点击事件的作用是调用父组件中的点击事件,并且回调 

      methods: {
        handleClick (e) {
          this.$emit('click', e)
        }
      }

父组件在使用时定义自己的点击事件,其本质是子组件中的点击事件触发父组件中的点击事件。

    <div class="row">
      <one-button @click="getInfo">按钮</one-button>
    </div>

      methods: {
        getInfo () {
          console.log('获取信息!!')//获取信息!!
        }
      }

就很nice

按钮中会设置是否禁用

我们可以通过父子传值

给子组件设置样式实现

button组件中的disabled属性

和之前相似,只要父子组件传值并且动态获取这个值并且赋给disabled属性,并且设置一个disabled样式即可。

    <div class="row">
      <one-button @click="getInfo" disabled>按钮</one-button>
    </div>

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

        disabled: {
          type: Boolean,
          default: false
        }

 disabled样式:

    .one-button.is-disabled{
       cursor: no-drop;
    }

至此 element中的button组件就封装完成了 是不是很nice

下次有时间继续封转其他的

看看封装的总代码

<template>
  <button class="one-button" :class="[`one-button-${type}`,{
    'is-plain':plain,
    'is-round':round,
    'is-circle':circle,
    'is-disabled':disabled
  }]"
  @click="handleClick"
  :disabled="disabled"
  >
  <i v-if="icon" :class="`one-icon-${icon}`"></i>
  <!-- 如果没传入文本插槽,则不显示span内容 -->
   <span v-if="$slots.default"><slot></slot></span>
  </button>
</template>

<script>

export default {
  name: 'oneButton',
  // 此时对props进行校验,值接收string类型的type值
  props: {
    type: {
      type: String,
      // 设置默认值:如果不传值,那么使用default
      default: 'defalut'
    },
    plain: {
      type: Boolean,
      default: false
    },
    round: {
      type: Boolean,
      default: false
    },
    circle: {
      type: Boolean,
      default: false
    },
    icon: {
      type: String,
      default: ''
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  created () {
    // 显示所有插槽
    // console.log(this.$slots)
  },
  methods: {
    // 定义一个点击事件,这个点击事件的作用是调用父组件中的点击事件,并且回调
    handleClick (e) {
      this.$emit('click', e)
    }
  }
}
</script>

<style lang="scss" scoped>
  .one-button{
    display: inline-block;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    background: #ffffff;
    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;
    -moz-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;
    }
  }
.one-button-primary{
  color:#fff;
  background-color: #409eff;
  border-color: #409eff;
  &:hover,
  &:focus{
    background: #66b1ff;
    background-color: #66b1ff;
    color: #fff;
    }
  }
  .one-button-success{
  color:#fff;
  background-color: #67c23a;
  border-color: #67c23a;
  &:hover,
  &:focus{
    background: #85ce61;
    background-color: #85ce61;
    color: #fff;
    }
  }
  .one-button-info{
  color:#fff;
  background-color: #909399;
  border-color: #909399;
  &:hover,
  &:focus{
    background: #a6a9ad;
    background-color: #a6a9ad;
    color: #fff;
    }
  }
  .one-button-warning{
  color:#fff;
  background-color: #e6a23c;
  border-color: #e6a23c;
  &:hover,
  &:focus{
    background: #ebb563;
    background-color: #ebb563;
    color: #fff;
    }
  }
  .one-button-danger{
  color:#fff;
  background-color: #f56c6c;
  border-color: #f56c6c;
  &:hover,
  &:focus{
    background: #f78989;
    background-color: #f78989;
    color: #fff;
    }
  }
// 朴素按钮样式
.one-button.is-plain{
  &:hover,
  &:focus{
    background: #fff;
    border-color: #489eff;
    color: #409eff;
  }
}
.one-button-primary.is-plain{
  color: #409eff;
  background: #ecf5ff;
  &:hover,
  &:focus{
    background: #409eff;
    border-color: #409eff;
    color: #fff;
  }
}
.one-button-success.is-plain{
  color: #67c23a;
  background: #c2e7b0;
  &:hover,
  &:focus{
    background: #67c23a;
    border-color: #67c23a;
    color: #fff;
  }
}
.one-button-info.is-plain{
  color: #909399;
  background: #d3d4d6;
  &:hover,
  &:focus{
    background: #909399;
    border-color: #909399;
    color: #fff;
  }
}
.one-button-warning.is-plain{
  color: #e6a23c;
  background: #f5dab1;
  &:hover,
  &:focus{
    background: #e6a23c;
    border-color: #e6a23c;
    color: #fff;
  }
}
.one-button-danger.is-plain{
  color: #f56c6c;
  background: #fbc4c4;
  &:hover,
  &:focus{
    background: #f56c6c;
    border-color: #f56c6c;
    color: #fff;
  }
}
// round属性
.one-button.is-round{
  border-radius: 20px;
  padding: 12px 23px;
}
// circle属性
.one-button.is-circle{
  border-radius: 50%;
  padding: 12px;
}
// icon配套样式
.one-button [class*=one-icon-]+span{
  margin-left: 5px;
}
// disabled属性
.one-button.is-disabled{
   cursor: no-drop;
}
</style>