手搓vue3组件_1.封装一个button

news2024/10/7 18:26:57

我的icepro参考地址,内有参考代码,有条件的割割点点star

实现要求:

  • 基于vue3
  • 支持通过colors(更改颜色)
  • 支持点击事件
  • …支持其他的自定义样式(例如圆角,size等等)

最基础的第一步:

父组件引入并使用:

<template>
  <div class="buttonLim">
    我的按钮:
    <ice-button>
      primary
    </ice-button>
  </div>
</template>
<script setup>
import IceButton from '../../components/other/ice-button.vue'
</script>
<style scoped lang="less">
</style>

子组件中使用slot去展示:

<template>
  <div class="ice-button">
    <slot></slot>
  </div>
</template>
<script setup>
</script>
<style scoped lang="less">
</style>

run:

在这里插入图片描述

那么,把它的样式改的好看一些:

父组件:

<template>
  <div class="buttonLim">
    我的按钮:
    <ice-button>
      primary
    </ice-button>

  </div>
</template>

<script setup>
import IceButton from '../../components/other/ice-button.vue'</script>

<style scoped lang="less">
.buttonLim {
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
}
</style>

子组件:

<template>
  <div class="ice-button">
    <slot></slot>
  </div>
</template>

<script setup>

</script>

<style scoped lang="less">
.ice-button {
  border-radius: .3rem;
  border: rgba(0, 0, 0, .7) 1px solid;
  background: rgba(0, 0, 0, .2);
  width: fit-content;
  padding: .2rem .4rem;
  margin: .1rem .2rem;
  user-select: none;
}

</style>

在这里插入图片描述
当然,此时他的颜色并不够好看,那么如果想通过props向子组件自定义颜色:
子组件:

<template>
  <div class="ice-button">
    <slot></slot>
  </div>
</template>

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

这样你传过来了,但是想怎么用呢,

这里要求颜色有未hover时的颜色和hover时的颜色,hover时的颜色自动计算出来

而此时可以考虑使用到css的变量了,像是:
子组件:

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

<script setup>
const props = defineProps({
  color: {
    type: String,
    default: ''
  }
})
const hoverColor = (rgb) => {
  return rgb.replaceAll(')', ',.5)')
}
</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;
  background: rgba(0, 0, 0, .2);
}

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

  &:hover {
    color: var(--hover-color);
    border: var(--hover-color) 1px solid;
  }
}
</style>

父组件的调用:

<template>
  <div class="buttonLim">
    我的按钮:
    <ice-button color="rgb(251, 139, 5)">
      primary
    </ice-button>
    <ice-button color="rgb(234, 137, 88)">
      primary
    </ice-button>

  </div>
</template>

<script setup>
import IceButton from '../../components/other/ice-button.vue'</script>

<style scoped lang="less">
.buttonLim {
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
}
</style>

run:
在这里插入图片描述

解释一下:

子组件中,如果传入了color的值,那么子组件的类名hoverColor生效,反之defaultColor生效,这里是给class传入了一个数组,如果你查看elementui的源码,会发现他们也是这样实现组件的type的切换,用过了才知道这个技巧是如此好用

还有,这里只是传入了一个rgb的值,然后在子组件中自动计算出来另一个颜色值(直接改为rgba,opacity为0.5)

支持点击事件

如果你直接使用下面的方式来绑定:
父组件:

<template>
  <div class="buttonLim">
    我的按钮:
    <ice-button color="rgb(251, 139, 5)">
      primary
    </ice-button>
    <ice-button color="rgb(234, 137, 88)">
      primary
    </ice-button>

    <ice-button @click="clickTrigger" color="rgb(242, 72, 27)" ref="btn">
      click
    </ice-button>


  </div>
</template>

<script setup>
import IceButton from '../../components/other/ice-button.vue'
import { ref } from 'vue'

const btn = ref()
const clickTrigger = async () => {
  console.log('clickTrigger--->')
  const str = '我即将要赋值的文字'
  if (await copyText(str)) {
    console.log('success')
  } else {
    console.log('error')
  }
}

const copyText = function (str) {
  return navigator.clipboard.writeText(str)
      .then(() => {
        return true
      })
      .catch(() => {
        return false
      })
}

</script>

<style scoped lang="less">
.buttonLim {
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
}
</style>

子组件:

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

<script setup>
const props = defineProps({
  color: {
    type: String,
    default: ''
  }
})
const hoverColor = (rgb) => {
  return rgb.replaceAll(')', ',.5)')
}
</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;
  background: rgba(0, 0, 0, .2);
}

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

  &:hover {
    color: var(--hover-color);
    border: var(--hover-color) 1px solid;
  }
}
</style>

这样没问题可以,但是有时会报错,click不是原生事件,这里我没有复现,淡然,你也可以在复习bug的时候想起这篇文章

这里的逻辑是点击左侧的item,赋值文字,但是这里的子组件没有定义click的处理事件,上面的button也是,可能会报这种错,

  • 如何解决:

在子组件中定义click事件:
子组件:

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

<script setup>
const props = defineProps({
  color: {
    type: String,
    default: ''
  }
})
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;
  background: rgba(0, 0, 0, .2);
}

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

  &:hover {
    color: var(--hover-color);
    border: var(--hover-color) 1px solid;
  }
}
</style>

这里的clickCallBack接收并emit一下click事件
emit函数会触发父组件绑定的click事件。当用户点击按钮时,父组件会接收到这个事件,并执行相应的操作。

自定义圆角

这里其实还是使用props来自定义圆角,例如我实现下面几个(round和block)按钮:
在这里插入图片描述
父组件的调用:

    自定义圆角:
    <ice-button round>round</ice-button>
    <ice-button block>block</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>

当然,也可以混合使用:
在这里插入图片描述

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

以上说的功能能都实现了

注意这里的代码还有很多没有优化,颜色获取,其他自定义type之类的都没有处理,关于更多的细节优化,详见icepro

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/851201.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Zabbix监控华为交换机DHCP接口地址池

一、背景 最近工作中遇到一个因为DHCP地址池满载、导致用户无法获取到IP地址的故障&#xff0c;所以在想通过zabbix 监控DHCP地址池的状态、当DHCP 地址池数量小于某个值时触发zabbix告警。 网上找了一下没有相关的文档、和对应的OID值、于是用Python 脚本的方式实现 二、实现效…

第二课-一键安装SD-Stable Diffusion 教程

前言 看完这篇文章并跟着操作,就可以在本地开始 SD 绘图了。 理论上来说,这篇课程结束,想要画什么图都可以画了。 启动器介绍 SD 是开源的,可以在 github 上找到。但直接下载源码安装,非常费劲,而且因为国内外差异,就是我这样的秃头程序员也难以应对。 所以,我们改…

Spring中Bean的“一生”(生命周期)

文章目录 一、图解二、文字解析总结 一、图解 >注&#xff1a;处于同一行的执行顺序是从左往右 二、文字解析 SpringBean的生命周期总体分为四个阶段&#xff1a;实例化>属性注入>初始化>销毁 Step1 实例化Bean&#xff1a;根据配置文件中Bean的定义&#xff0c;…

设计模式(3)装饰模式

一、介绍&#xff1a; 1、应用场景&#xff1a;把所需的功能按正确的顺序串联起来进行控制。动态地给一个对象添加一些额外的职责&#xff0c;就增加功能来说&#xff0c;装饰模式比生成子类更加灵活。 当需要给一个现有类添加附加职责&#xff0c;而又不能采用生成子类的方法…

[RCTF2019]DontEatMe

前言 一道迷宫题&#xff0c;但是输入被加密后使用&#xff0c;迷宫也需要在程序中找出并没有直接输出 分析 反调试 发现有两个比较特殊的地方&#xff0c;随机数和创建了新线程&#xff0c;随机数后面又被重新赋值给覆盖了&#xff0c;暂时不用管&#xff0c;ZwSetInformat…

业务需求紧急,IT部门缺失,企业如何应对"影子IT"危机?

在当今数字化时代&#xff0c;业务部门的需求通常非常紧急&#xff0c;但IT部门的排期却跟不上&#xff0c;导致业务部门焦头烂额。IT部门面临着诸多需求&#xff0c;无法在规定时间范围内满足每一个需求&#xff0c;因此未授权的应用程序安全监管也变得愈发困难。 影子IT的频发…

互联网电影购票选座后台管理系统源码开发

搭建一个互联网电影购票选座后台管理系统需要进行以下步骤&#xff1a; 1. 需求分析&#xff1a;首先要明确系统的功能和需求&#xff0c;包括电影列表管理、场次管理、座位管理、订单管理等。 2. 技术选型&#xff1a;选择适合的技术栈进行开发&#xff0c;包括后端开发语言…

铸铝齿轮泵比例流量阀放大器

液压齿轮泵是一种常用的液压泵&#xff0c;被广泛应用于各种低压系统中&#xff0c;如采矿、冶金、建筑、航空、航海、农林等机械的中、高压液压系统中。 液压齿轮泵的特点是结构简单&#xff0c;制造方便&#xff0c;价格低廉&#xff0c;体积小&#xff0c;重量轻&#xff0…

探析STM32标准库与HAL库之间的差异与优劣

引言&#xff1a; 在嵌入式开发领域&#xff0c;STMicroelectronics的STM32系列芯片广受欢迎。STM32提供了两种主要的软件库&#xff0c;即标准库和HAL库&#xff0c;用于开发各种应用。本文将探讨这两种库之间的差异&#xff0c;比较它们的优劣&#xff0c;并分析在选择库时需…

[HDLBits] Exams/m2014 q4e

Implement the following circuit: module top_module (input in1,input in2,output out);assign out!(in1||in2); endmodule

【MySQL】

这里写目录标题 MySQL架构一条sql执行流程MySQL数据存放电脑位置ibd文件结构行溢出是什么MySQL行记录存储格式索引为什么InnoDB选择B树作为索引数据结构什么时候需要创建索引优化索引方法InnoDB内部怎么存储数据B 树如何进行查询聚簇索引和二级索引为什么MySQL要采用B树作为索引…

【linux】ssh 和adb connect区别

问&#xff1a;ssh 与ping的区别 答&#xff1a;SSH&#xff08;Secure Shell&#xff09;和Ping是两种完全不同的网络工具。 SSH是一种加密的网络协议&#xff0c;用于安全地远程管理或访问远程计算机。它提供了一种安全的通信方式&#xff0c;可以在不安全的网络上进行远程登…

无涯教程-Perl - fileno函数

描述 此函数返回指定的FILEHANDLE的文件描述符号(由C和POSIX函数使用)。通常,这仅在使用select函数和任何低级tty函数时才有用。 语法 以下是此函数的简单语法- fileno FILEHANDLE返回值 此函数返回FILEHANDLE的文件描述符(数字),失败时不确定。 Perl 中的 fileno函数 - 无…

c#设计模式-行为型模式 之 观察者模式

定义&#xff1a; 又被称为发布-订阅&#xff08;Publish/Subscribe&#xff09;模式&#xff0c;它定义了一种一对多的依赖关系&#xff0c;让多个观察者 对象同时监听某一个主题对象。这个主题对象在状态变化时&#xff0c;会通知所有的观察者对象&#xff0c;使他们能够自 …

Go Gin 中使用 JWT

一、JWT JWT全称JSON Web Token是一种跨域认证解决方案&#xff0c;属于一个开放的标准&#xff0c;它规定了一种Token实现方式&#xff0c;目前多用于前后端分离项目和OAuth2.0业务场景下。 二、为什么要用在你的Gin中使用JWT 传统的Cookie-Sesson模式占用服务器内存, 拓展性…

C++ 多态性——纯虚函数与抽象类

抽象类是一种特殊的类&#xff0c;它为一个类族提供统一的操作界面。抽象类是为了抽象和设计的目的而建立的。可以说&#xff0c;建立抽象类&#xff0c;就是为了通过它多态地使用其中的成员函数。抽象类处于类层次的上层&#xff0c;一个抽象类自身无法实例化&#xff0c;也就…

提升招标文件准确性:校对软件助力招标流程优化

招标文件的准确性对于一个招标项目的成功非常重要。校对软件可以在优化招标流程中发挥关键作用&#xff0c;帮助提升招标文件的准确性和质量。以下是一些校对软件如何助力招标流程优化的方式&#xff1a; 1.拼写和语法检查&#xff1a;校对软件可以自动检测和纠正招标文件中的拼…

企业进销存管理流程有哪些? 附进销存管理系统

阅读本文&#xff0c;您可以了解&#xff1a;1、进销存的定义&#xff1b;2、进销存的流程 首先&#xff0c;在了解进销存流程之前&#xff0c;我们必须厘清一个问题&#xff1f; 什么是进销存&#xff1f; 进销存是一个企业管理中常用的术语&#xff0c;是指企业在经营过程中…

机器学习竞赛、CV/NLP 竞赛入门没人带解决办法

我的第一个AI竞赛是在Datawhale夏令营的帮助下参加的。 一周左右的夏令营&#xff0c;让我从环境都配不好的小白到对pytorch基本入门。 夏令营的氛围督促我赶紧学习&#xff0c;赶紧进步&#xff1b;夏令营群里的大佬推荐的入门视频让我pytorch入门。 了解datawhale是通过b站…

【MySQL】deepin安装mysql的cpp开发包

在deepin下安装好mysql后&#xff0c;发现在c语言中没有<mysql.h>的头文件。 而根据ubuntu的办法直接按照mysql的开发包&#xff0c;会出现这种情况&#xff1a; ~/Desktop$ sudo apt-get install libmysqlclient-dev 正在读取软件包列表… 完成 正在分析软件包的依赖关…