不知道怎么的,突然想绘制一个标签,比如el-button什么的。

今天研究一下吧,不知道能不能整出来

以后就可以绘制自己的组件,弄自己的组件库了。不知道有朝一日能不能让越组件青史留名?

嘻嘻,百日梦做差不多了,接着去查查资料。

文章分为三个部分:

1.按钮组件实现(根据查阅的一个文章实现基础)

2.效仿el-button样式组件内容(复现type和plain功能)

最终结果:

 

看了一会儿感觉和普通的组件封装好像是差不多的原理,和平常使用的整体组件是一个道理,可能自定义上之前没有那么强。按照之前的技术能力应该也是没有问题的,这是我看的up主的内容

一.按钮组件实现

父组件:

<ice-button block color="rgb(242, 72, 27)">混合</ice-button>

子组件:

<template>
  <div class="ice-button"
       @click="clickCallBack"
       :class="[
           color?'hoverColor':'defaultColor',
           round?'round':'',
           block?'block':''
       ]"
       :style="{ '--color': color,'--hover-color': hoverColor(color) }"
  >
    <slot></slot>
  </div>
</template>

<script setup>
const props = defineProps({
  color: {
    type: String,
    default: ''
  },
  round: {
    type: Boolean,
    default: false
  },
  block: {
    type: Boolean,
    default: false
  }
})
const hoverColor = (rgb) => {
  return rgb.replaceAll(')', ',.5)')
}

const emit = defineEmits(['click'])
const clickCallBack = (evt) => {
  emit('click', evt)
}
</script>

<style scoped lang="less">
.ice-button {
  border-radius: .3rem;
  width: fit-content;
  padding: .2rem .4rem;
  margin: .1rem .2rem;
  user-select: none;
  transition-duration: .3s;
}

.defaultColor {
  border: rgba(0, 0, 0, .7) 1px solid;
  color: rgba(0, 0, 0, .7);
  transition-duration: .3s;

  &:hover {
    color: rgba(0, 0, 0, .4);
    border: rgba(0, 0, 0, .4) 1px solid;
  }
}

.hoverColor {
  color: var(--color);
  border: var(--color) 1px solid;

  &:hover {
    color: var(--hover-color);
    border: var(--hover-color) 1px solid;
  }
}

.round {
  border-radius: 2rem;
}

.block {
  border-radius: 0;
}
</style>

实现效果:

虽然说不是很好看,但是基本的方法和原理还是特别透彻了已经。

1.父组件调用组件,通过props添加样式

2.less动态修改css样式

3.条件编译减少bug

二.按钮组件样式升级

在以上的基础上我们就可以发挥下自己的小猪脑了(哦,是我的猪脑)

1.el-button中有个type属性,通过type的切换实现效果,而其中的color和round都是基本样式,我该如何实现同样的效果呢

首先肯定是在props定义一个type

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

修改:

<template>
  <div class="ice-button"
       @click="clickCallBack"
       :class="[
           type === 'blue' ? 'primaryColor' : '',
           type === 'danger' ? 'dangerColor' : '',
           color?'hoverColor':'',
           round?'round':'',
           block?'block':''
       ]"
       :style="{ '--color': color,'--hover-color': hoverColor(color) }"
  >
    <slot></slot>
  </div>
</template>

<script setup>
//ok
const props = defineProps({
  color: {
    type: String,
    default: ''
  },
  type: {
    type: String,
    default: ''
  },
  round: {
    type: Boolean,
    default: false
  },
  block: {
    type: Boolean,
    default: false
  }
})


const hoverColor = (rgb) => {
  return rgb.replaceAll(')', ',.5)')
}

//ok??
const emit = defineEmits(['click'])
const clickCallBack = (evt) => {
  emit('click', evt)
}
</script>

<style scoped lang="less">
.ice-button {
  border-radius: 3px;
  width: fit-content;
  padding: 2px 2px;
  margin: 1px 2px;
  user-select: none;
  transition-duration: .3s;
}

.defaultColor {
  border: rgba(0, 0, 0, .7) 1px solid;
  color: rgba(0, 0, 0, .7);
  transition-duration: .3s;

  &:hover {
    color: rgba(64, 0, 255, 0.4);
    border: rgba(64, 0, 255, 0.4) 1px solid;
  }
}

.hoverColor {
  color: var(--color);
  border: var(--color) 1px solid;

  &:hover {
    color: var(--hover-color);
    border: var(--hover-color) 1px solid;
  }
}

//ok
.round {
  border-radius: 5px;
}

//ok
.block {
  border-radius: 0;
}

.dangerColor {
  border: rgba(255, 0, 0, .7) 1px solid;
  color: rgba(255, 0, 0, .7);

  &:hover {
    color: rgba(255, 0, 0, .4);
    border: rgba(255, 0, 0, .4) 1px solid;
  }
}

.primaryColor {
  border: rgba(0, 0, 255, 0.7) 1px solid;
  color: rgba(0, 0, 255, .7);

  &:hover {
    color: rgba(0, 0, 255, .4);
    border: rgba(0, 0, 255, .4) 1px solid;
  }
}
</style>

这样就可以实现同el-button类似的感觉了(虽然好像还是有点丑)

    <ActionBtn2 round type="blue">混合</ActionBtn2>

(这边有个小内容,就是命名时使用驼峰,比如HyButton,标签名就可以使用hy-button了)

再看下el-button的

行。算你好看。这边看按钮整体可以分为这几部分

1.框色 2.字色 3.底色

default逻辑 默认框底色 字白色 悬浮降低透明度

plain逻辑 默认字框色 底白色 悬浮 字白色 底色(这是我罗里吧嗦的废话啦)

这边根据default逻辑来优化一下type样式

子组件:

定义了三个type满足三个type的情况

<template>
  <div class="ice-button"
       @click="clickCallBack"
       :class="[
           type === 'primary' ? 'primaryColor' : '',
           type === 'danger' ? 'dangerColor' : '',
           type === 'warn' ? 'warnColor' : '',
           color?'hoverColor':'',
           round?'round':'',
           block?'block':''
       ]"
       :style="{ '--color': color,'--hover-color': hoverColor(color) }"
  >
    <slot></slot>
  </div>
</template>

<script setup>
//ok
const props = defineProps({
  color: {
    type: String,
    default: ''
  },
  type: {
    type: String,
    default: ''
  },
  round: {
    type: Boolean,
    default: false
  },
  block: {
    type: Boolean,
    default: false
  }
})


const hoverColor = (rgb) => {
  return rgb.replaceAll(')', ',.5)')
}

//ok??
const emit = defineEmits(['click'])
const clickCallBack = (evt) => {
  emit('click', evt)
}
</script>

<style scoped lang="less">
.ice-button {
  width:fit-content;
  height: 30px;
  text-align: center;
  line-height: 30px;
  font-size: 16px;
  padding: 2px 20px;
  margin: 1px 2px;
  user-select: none;
  transition-duration: .3s;
  font-weight: 600;
}

.dangerColor {
  border: rgba(255, 0, 0, 1) 1px solid;
  color: rgb(255, 255, 255);
  background-color: rgba(255, 0, 0, 1);

  &:hover {
    color: rgb(255, 255, 255);
    border: rgb(255, 0, 0, .7) 1px solid;
    background-color: rgba(255, 0, 0, .7);
  }
}
.warnColor {
  border: rgb(160, 160, 0) 1px solid;
  color: rgb(255, 255, 255);
  background-color: rgba(160, 160, 0, 1);

  &:hover {
    color: rgb(255, 255, 255);
    border: rgb(160, 160, 0, .7) 1px solid;
    background-color: rgba(160, 160, 0, .7);
  }
}
.primaryColor {
  border: rgb(82, 82, 255) 1px solid;
  color: rgb(255, 255, 255);
  background-color: rgba(82, 82, 255, 1);

  &:hover {
    color: rgb(255, 255, 255);
    border: rgba(82, 82, 255, .7) 1px solid;
    background-color: rgba(82, 82, 255, .7);
  }
}

.hoverColor {
  color: var(--color);
  border: var(--color) 1px solid;
  background-color: rgba(0, 0, 0, .7);

  &:hover {
    color: var(--hover-color);
    border: var(--hover-color) 1px solid;
    background-color: rgba(0, 0, 0, .7);
  }
}

//ok
.round {
  border-radius: 10px;
}

//ok
.block {
  border-radius: 0;
}
</style>

父组件

调用3个type查看效果

import HyButton from './ActionBtn2.vue'    

<hy-button round type="primary">坏越大帅哥</hy-button>
<hy-button round type="danger">坏越大帅哥</hy-button>
<hy-button round type="warn">坏越大帅哥</hy-button>

有点那个味道了~!

这是type的设定,然后还有一个就是plain的设定,plain情况下的话,默认底色为白,框和字有色。hover时底色和框有色,字为白。这么说可能不太形象。我们可以从元素的变化来理解~

1.type情况下

文字:白色

边框:type色

底色:type色

悬浮:整体变浅

2.plain情况下

文字:type色

边框:type色

底色:白色

悬浮:文字变白,边框不动,底色变为type色

*这边要考虑到没有type的时候要给一个默认值~

由此可以看到基本所有的改变都是根据type来的,只要可以得到type,就可以简化封装~

以下为优化后的代码(可能不是最简的,这块也是第一次运用)

<template>
  <div class="ice-button"
       @click="clickCallBack"
       :class="[
           (type === 'primary'||type ==='danger'||type ==='warn') ? 'typeColor' : '',
           round ? 'round' : '',
           block ? 'block' : '',
           plain ? 'plain' :''
       ]"
       :style="{
       '--normalcolor':colors[type + 'Color'],'--hovercolors':colors[type + 'HoverColor'],
       '--plaincolor':type?colors[type + 'HoverColor']:'black','--plainhover':type?colors[type + 'Color']:'black' }"
  >
    <slot></slot>
  </div>
</template>

<script setup>
const props = defineProps({
  type: {
    type: String,
    default: ''
  },
  round: {
    type: Boolean,
    default: false
  },
  block: {
    type: Boolean,
    default: false
  },
  plain: {
    type: Boolean,
    default: false
  }
})

import { ref } from 'vue'
const colors=ref({
 dangerColor:('rgb(255, 0, 0)'),
 dangerHoverColor:('rgb(255, 0, 0, .7)'),
 warnColor:('rgb(160, 160, 0)'),
 warnHoverColor:('rgb(160, 160, 0, .7)'),
 primaryColor:('rgb(82, 82, 255)'),
 primaryHoverColor:('rgba(82, 82, 255, .7)')
})


const emit = defineEmits(['click'])

const clickCallBack = (evt) => {
  emit('click', evt)
}

</script>

<style scoped lang="less">
.ice-button {
  border-radius: 8px;
  border: 1px solid black;
  width:fit-content;
  height: 30px;
  text-align: center;
  line-height: 30px;
  font-size: 16px;
  padding: 2px 20px;
  margin: 1px 2px;
  user-select: none;
  transition-duration: .3s;
  font-weight: 600;
  &:hover {
    color: rgba(0, 0, 0,0.7);
  }
}
.typeColor {
  border: var(--normalcolor)1px solid;
  color: rgb(255, 255, 255);
  background-color: var(--normalcolor);

  &:hover {
    color: rgb(255, 255, 255);
    border: var(--hovercolors) 1px solid;
    background-color: var(--hovercolors);
  }
}

.round {
  border-radius: 20px;
}

.block {
  border-radius: 0;
}
.plain{
  background-color: rgb(255, 255, 255);
  color: var(--plaincolor);
  border: var(--plaincolor) 1px solid;

  &:hover {
    color: rgb(255, 255, 255);
    border: var(--plainhover) 1px solid;
    background-color: var(--plainhover);
  }
}
</style>

比较之前优化了type赋色的代码,通过type的赋值调用一次即可,plain也可以根据此进行自动变化。下面来看看效果

父组件:

import HyButton from './ActionBtn2.vue'   

<hy-button type="primary">坏越大帅哥</hy-button>
<hy-button block type="danger">坏越大帅哥</hy-button>
<hy-button round type="warn">坏越大帅哥</hy-button>
<hy-button type="primary" plain>坏越大帅哥</hy-button>
<hy-button block type="danger" plain>坏越大帅哥</hy-button>
<hy-button round type="warn" plain>坏越大帅哥</hy-button>
<hy-button block  plain>坏越大帅哥</hy-button>

主要运用的技能也就这两个吧:

1.less(今天也是第一次用,也是小刀拉屁股,开眼了)

2.父子通信

再加一点吧。以上都是实现和他一样,加点不一样,比如我还想加一个type-special

           type==='special'?'specialColor':'',

样式:

.specialColor {
      color: white;
      background: linear-gradient(90deg,
          #0f1ad4,
          #f528d1,
          #f736de,
          #09d3ab);
      background: linear-gradient(90deg,
          #03a9f4,
          #f441a5,
          #ffeb3b,
          #03a9f4);
      background-size: 400%;
      position: relative;
      &:hover {
      animation: animate 10s linear infinite;
      z-index:1;
      color: white;
    }

    &:before {
      content: '';
      top: -5px;
      left: -5px;
      right: -5px;
      bottom: -5px;
      position: absolute;
      background: linear-gradient(90deg,
          #03a9f4,
          #f441a5,
          #ffeb3b,
          #03a9f4);
      z-index: -1;
      opacity: 0;
      filter: blur(20px)
    }

    &:hover:before {
      opacity: 1;
    }


    }

    @keyframes animate {
      0% {
        background-position: 0 0;
      }

      100% {
        background-position: 400% 0;
      }

    }

组件运用:

    <div style="width: 100vw;height: 500px;background-color: black;display: flex;justify-content: center;align-items: center;">
        <hy-button type='special'>下次再见咯</hy-button>
    </div>

效果:

hover:

感觉还是不错的~

第一部分参考文章:手搓vue3组件_1.封装一个button_vue3封装按钮组件-CSDN博客

Logo

前往低代码交流专区

更多推荐