ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

模仿element-ui封装vue组件库(button)

2022-05-24 13:00:48  阅读:202  来源: 互联网

标签:vue color button element ra background 组件 border


实例内容

封装常见的功能组件(Button,Modal,Form相关),封装完成后封装成UI组件库发布到NPM上。

涉及知识点

vue基础语法
组件基本语法
字键通讯(sync,provide,inject)
插槽使用
prop校验
过渡与动画处理
计算属性与监听属性
v-model语法糖
vue插件机制
npm发布

实例目的

掌握组件封装的语法和技巧学会造轮子,了解组件库实现原理搭建和积累自己的组件库学习前提有一定vue基础,懂vue语法熟悉ES6的一些常见语法对vue感兴趣

----------------------------------------------------------------------------分割线---------------------------------------------------------------------------------

一、使用vue脚手架初始化一个项目

使用vue created rainbow-ui,创建一个名为rainbow-ui的项目。

按照自己的习惯设置脚手架风格,这里不多做介绍。

脚手架搭建完毕后,将App.vue文件下的自带内容清理一下,为后续开发做准备。

二、如何封装,注册和使用一个组件

在componet下创建一个button.vue的文件,放置button组件代码。创建一个组建的button组件,,并且指定name为RaButton。

<template>
<button class="ra-button">
按钮组件
</button>
</template>

<script>

export default {
name: 'ra-button'
}

</script>

<style lang="scss">

</style>


创建组件完成后,不能在项目中直接使用,需要到main.js中注册才可以使用。

import Vue from 'vue'
import App from './App.vue'
// 第一步:导入button组件
import RaButton from './components/button.vue'

Vue.config.productionTip = false

// 第二步:注册组件,设置(组件名,组件)
Vue.component(RaButton.name, RaButton)

new Vue({
render: h => h(App)
}).$mount('#app')
注册完成后,组件就可以在项目中使用了。

<template>
<div>
<ra-button></ra-button>
</div>
</template>

按钮效果:

 

 

 

 

组件最简单的封装,注册和使用方法就是这样一个流程。

三、封装一个element-ui风格的按钮

需要使用到的知识:

组件通讯
组件插槽
props校验
参数支持:

参数名   

参数描述 参数类型 默认值
type  按钮类型(primary/success/warning/danger/info) string default
plain  是否为朴素按钮 boolean false
round  是否圆角按钮 boolean false
circle 是否圆形按钮 boolean false
disabled 是否禁用 boolean false
icon 图标类型 string


事件支持:

事件名

 事件描述
click 点击事件


使用插槽:

简单来说,凡是希望组件中内容可以灵活设置的地方,都需要用到slot插槽来自定义内容。

使用slot来定义按钮上的文本内容:

<template>
<button class="-button">
<span><slot></slot></span>
</button>
</template>
在使用时就可以直接输入文本,定义按钮文本内容了:

<template>
<div>
<ra-button>登录</ra-button>
<ra-button>删除</ra-button>
<ra-button>取消</ra-button>
</div>
</template>

效果:

 

button组件基础样式:

<style lang="scss">
.ra-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>


效果:

 

3.1button组件的type属性

让按钮支持type属性,使得按钮支持不同样式:

第一步:父组件组件传递type属性

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


第二步:子组件接收负组件传递的数据

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


此时对type进行校验,如果传递了非String类型的值(这里我传递了123),将会报错。

failed for prop "type". Expected String with value "123", got Number with value 123.


第三步:通过绑定类名的方法动态控制样式

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


第四步:设置不同类型的样式

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

第五步:至此就完成了对于按钮样式的设置,查看一下效果

3.2button组件的plain属性

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

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

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


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

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

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

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

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

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

第五步:至此就完成了对于按钮样式的设置,查看一下效果

 

3.3button组件的round属性

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

获取属性值:

round: {
type: Boolean,
default: false
}

round样式:

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

效果图:

 

3.4button组件的circle属性

circle同样是上面的方法,样式为:

.ra-button.is-circle{
border-radius: 50%;
padding: 12px;
}

3.5button组件中使用字体图标
在项目中使用字体图标,首先需要有字体图标,我们可以去阿里巴巴矢量图标库下载。

下载完成后,在asset目录下新建一个fonts目录,存放我们下载到的字体图标。

做完准备工作后,我们就可以开始把字体图标运用到项目中了。

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

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

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

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

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

父组件传值:

<div class="row">
<ra-button plain icon='ra-icon-delete' circle></ra-button>
<ra-button plain icon='ra-icon-delete' circle type="primary"></ra-button>
<ra-button plain icon='ra-icon-delete' circle type="success"></ra-button>
<ra-button plain icon='ra-icon-delete' circle type="info"></ra-button>
<ra-button plain icon='ra-icon-message' circle type="danger"></ra-button>
<ra-button plain icon='ra-icon-check' circle type="warning"></ra-button>
</div>

子组件接收:

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

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

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

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

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

第五步:查看效果

 

3.6button组件中的点击事件

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

组件中的定义点击事件:

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

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

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

 

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

<div class="row">
<ra-button @click="getInfo">按钮</ra-button>
</div>
methods: {
getInfo () {
console.log('获取信息!!')//获取信息!!
}
}

3.7button组件中的disabled属性

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

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

disabled样式:

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

------------------------------------------------------------------至此,按钮组件封装完成!------------------------------------------------------------------

附组件代码:

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

<script>

export default {
  name: 'ra-button',
  props: {
    type: {
      type: String,
      // 设置默认值:如果不传值,那么使用default
      default: 'default'
    },
    plain: {
      type: Boolean,
      default: false
    },
    round: {
      type: Boolean,
      default: false
    },
    circle: {
      type: Boolean,
      default: false
    },
    icon: {
      type: String,
      default: ''
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  methods: {
    handleClick (e) {
      this.$emit('click', e)
    }
  }
}
</script>

<style lang="scss" scope>
.ra-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;
    }
}

.ra-button-primary{
  color:#fff;
  background-color: #409eff;
  border-color: #409eff;
  &:hover,
  &:focus{
    background: #66b1ff;
    background-color: #66b1ff;
    color: #fff;
    }
  }
  .ra-button-success{
  color:#fff;
  background-color: #67c23a;
  border-color: #67c23a;
  &:hover,
  &:focus{
    background: #85ce61;
    background-color: #85ce61;
    color: #fff;
    }
  }
  .ra-button-info{
  color:#fff;
  background-color: #909399;
  border-color: #909399;
  &:hover,
  &:focus{
    background: #a6a9ad;
    background-color: #a6a9ad;
    color: #fff;
    }
  }
  .ra-button-warning{
  color:#fff;
  background-color: #e6a23c;
  border-color: #e6a23c;
  &:hover,
  &:focus{
    background: #ebb563;
    background-color: #ebb563;
    color: #fff;
    }
  }
  .ra-button-danger{
  color:#fff;
  background-color: #f56c6c;
  border-color: #f56c6c;
  &:hover,
  &:focus{
    background: #f78989;
    background-color: #f78989;
    color: #fff;
    }
  }
  // 朴素按钮样式
.ra-button.is-plain{
  &:hover,
  &:focus{
    background: #fff;
    border-color: #489eff;
    color: #409eff;
  }
}
.ra-button-primary.is-plain{
  color: #409eff;
  background: #ecf5ff;
  &:hover,
  &:focus{
    background: #409eff;
    border-color: #409eff;
    color: #fff;
  }
}
.ra-button-success.is-plain{
  color: #67c23a;
  background: #c2e7b0;
  &:hover,
  &:focus{
    background: #67c23a;
    border-color: #67c23a;
    color: #fff;
  }
}
.ra-button-info.is-plain{
  color: #909399;
  background: #d3d4d6;
  &:hover,
  &:focus{
    background: #909399;
    border-color: #909399;
    color: #fff;
  }
}
.ra-button-warning.is-plain{
  color: #e6a23c;
  background: #f5dab1;
  &:hover,
  &:focus{
    background: #e6a23c;
    border-color: #e6a23c;
    color: #fff;
  }
}
.ra-button-danger.is-plain{
  color: #f56c6c;
  background: #fbc4c4;
  &:hover,
  &:focus{
    background: #f56c6c;
    border-color: #f56c6c;
    color: #fff;
  }
}
.ra-button.is-round{
  border-radius: 20px;
  padding: 12px 23px;
}

.ra-button.is-circle{
  border-radius: 50%;
  padding: 12px;
}

.ra-button.is-disabled{
   cursor: no-drop;
}
.ra-button [class*=ra-icon-]+span{
  margin-left: 5px;
}
</style>

标签:vue,color,button,element,ra,background,组件,border
来源: https://www.cnblogs.com/Rainbow5421/p/16305174.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有