React-Hook 轮子公开课(从零开始)用最基础的方式写出一个简单的组件库——第四课【Link】文字链接组件

一、组件库介绍

有兴趣的同学 可以先着手看源码,之前写的一系列开源组件库项目(有帮助的同学也帮忙点个star👍)

名称官网github
tinkerbell-ui(vue2.0)http://tinkerbell.tophttps://github.com/hanbingxu82/tinkerbell-ui
tinkerbell-ui(vue3.0)https://github.com/hanbingxu82/tinkerbell-ui-next
tinkerbell-ui(react-hook)https://github.com/hanbingxu82/tinkerbell-ui-react

二、Link组件流程介绍

其实谈到文本链接组件,我们可以参考向element、antd这些其实可以把这些看成是一个个的文字按钮组件,只不过底层就是使用a标签去实现的,又或者,我不想让其拥有a标签的href属性的话,底层完全就可以使用span标签来包裹文本,总的来说其实就相当于对文本进行了一个封装,我们可以通过属性进行判断到底是一个链接组件,还是一个单纯类似按钮功能的文本样式组件,简单的来讲我们只需要对其进行一个颜色封装即可,当然主要的也是要捋清楚代码该如何去写:

1、首先肯定还是需要来对其进行一个判断,判断Link组件的类型到底是文本呢?还是链接呢?所以我们需要一个type属性,这是其一。

2、其次,我们可以根据文本内容加入 Icon 图标,让其内容多元化,就不需要再去手动在前置位,后置位填写 i 标签写class样式了,再有当然我们也要将 disabled 禁用属性添加上 实现对应的权限功能。

3、最后也是归笼一下我们的属性功能等,因为如果设置了a标签,默认a标签是带有着下划线的,那么我也同样也要判断是否带有着下划线?
type: string // 类型 primary / success / warning / danger / info
href: string // 原生 href 属性
target: string // a标签 原生target属性
disabled: boolean // 是否禁用状态
underline: true // 是否下划线
icon: string // 图标类名

三、代码详解

3.1、index.tsx


import React, { useState, useEffect } from 'react'
import './index.scss'
interface Iprops {
  type: string // 类型 primary / success / warning / danger / info
  href: string // 原生 href 属性
  target: string // a标签 原生target属性
  disabled: boolean // 是否禁用状态
  underline: true // 是否下划线
  icon: string // 图标类名
}
function Link(props: any) {
  const [tbType, setTbType] = useState('')
  const [tbDisabled, setTbDisabled] = useState('')
  const [tbUnderline, setTbUnderline] = useState('')
  const [tbIcon, setTbIcon] = useState('')
  const {
    type = '',
    href = '',
    target = '_blank',
    disabled = false,
    underline = true,
    icon = ''
  }: Iprops = props
  // 类似于 componentDidMount 和 componentDidUpdate:
  useEffect(() => {
    Ptype()
    PDisabled()
    Punderline()
    Picon()
  }, [])
  // 页面加载判断当前按钮类型
  function Ptype() {
    if (type == 'primary') {
      setTbType('a_primary')
    } else if (type == 'success') {
      setTbType('a_success')
    } else if (type == 'info') {
      setTbType('a_info')
    } else if (type == 'warning') {
      setTbType('a_warning')
    } else if (type == 'danger') {
      setTbType('a_danger')
    }
  }
  // 判断是否是禁用
  function PDisabled() {
    if (disabled) {
      setTbDisabled(' is_disabled')
    } else {
      setTbDisabled(' ')
    }
  }
  // 判断是否有下划线
  function Punderline() {
    console.log(underline)
    if (!underline) {
      setTbUnderline(' is_underline')
    } else {
      setTbUnderline(' ')
    }
  }
  // 页面加载判断是否为图标按钮
  function Picon() {
    if (icon) {
      setTbIcon(' iconfont ' + icon)
    } else {
      setTbIcon('')
    }
  }
  if (!tbIcon && href) {
    return (
      <a
        {...props}
        target={target}
        href={href}
        className={`tb-link ${tbType} ${tbDisabled} ${tbUnderline}`}
      >
        {props.children}
      </a>
    )
  } else if (tbIcon && href) {
    return (
      <a
        {...props}
        target={target}
        href={href}
        className={`tb-link ${tbIcon} ${tbType} ${tbDisabled} ${tbUnderline}`}
      >
        {props.children}
      </a>
    )
  } else if (tbIcon && !href) {
    return (
      <span
        {...props}
        target={target}
        className={`tb-link ${tbIcon} ${tbType} ${tbDisabled} ${tbUnderline}`}
      >
        {props.children}
      </span>
    )
  } else {
    return (
      <span
        {...props}
        className={`tb-link ${tbType} ${tbDisabled} ${tbUnderline}`}
      >
        {props.children}
      </span>
    )
  }
}
export default Link

3.2、index.scss

@import '../../style/variables.scss';


/* is_disabled 禁用 */
.is_disabled {
  pointer-events: none;
  /* cursor:not-allowed!important; */
  opacity: 0.6;
}

/* is_underline 下划线 */
.is_underline {
  text-decoration: none !important;
}

.tb-link.iconfont {
  vertical-align: baseline;
}

.tb-link {
  color: #606266;
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  position: relative;
  text-decoration: none;
  outline: none;
  cursor: pointer;
  padding: 1px;
  font-size: 14px;
  font-weight: 500;
  box-sizing: border-box;
  -webkit-tap-highlight-color: #606266;
}

.tb-link:focus,
.tb-link:hover {
  color: $color-primary-light1;
  text-decoration: underline;
}

/* .tb-link:visited,
  .tb-link:active {
    text-decoration: none;
  } */
/* type样式 */
.tb-link.a_primary {
  color: $color-primary;
}

.tb-link.a_primary:focus,
.tb-link.a_primary:hover {
  color: $color-primary-light1;
}

.tb-link.a_success {
  color: $color-success;
}

.tb-link.a_success:focus,
.tb-link.a_success:hover {
  color: $color-success-light1;
}

.tb-link.a_info {
  color: $color-info;
}

.tb-link.a_info:focus,
.tb-link.a_info:hover {
  color: $color-info-light1;
}

.tb-link.a_warning {
  color: $color-warning;
}

.tb-link.a_warning:focus,
.tb-link.a_warning:hover {
  color: $color-warning-light1;
}

.tb-link.a_danger {
  color: $color-danger;
}

.tb-link.a_danger:focus,
.tb-link.a_danger:hover {
  color: $color-danger-light1;
}

3.3、variables.scss

// $font-path : './fonts'

/* Color
-------------------------- */
$color-white : #FFFFFF;
$color-white-light : rgba(255, 255, 255, 0.65);
$color-white-light2 : rgba(255, 255, 255, 0.35);

$color-primary : #1089ff;
$color-primary-light1 : mix(#FFFFFF, $color-primary, 20%);
$color-primary-light2 : mix(#FFFFFF, $color-primary, 40%);
$color-primary-light3 : mix(#FFFFFF, $color-primary, 60%);
$color-primary-light4 : mix(#FFFFFF, $color-primary, 80%);
$color-primary-light5 : mix(#FFFFFF, $color-primary, 90%);
$color-primary-light6 : mix(#FFFFFF, $color-primary, 95%);
$color-primary-active : mix(#000000, $color-primary, 10%);

$color-success :#52c41a;
$color-success-light1 : mix(#FFFFFF, $color-success, 20%);
$color-success-light2 : mix(#FFFFFF, $color-success, 40%);
$color-success-light3 : mix(#FFFFFF, $color-success, 60%);
$color-success-light4 : mix(#FFFFFF, $color-success, 80%);
$color-success-light5 : mix(#FFFFFF, $color-success, 90%);
$color-success-light6 : mix(#FFFFFF, $color-success, 95%);
$color-success-active : mix(#000000, $color-success, 10%);

$color-info : #35495E;
$color-info-light1 : mix(#FFFFFF, $color-info, 20%);
$color-info-light2 : mix(#FFFFFF, $color-info, 40%);
$color-info-light3 : mix(#FFFFFF, $color-info, 60%);
$color-info-light4 : mix(#FFFFFF, $color-info, 80%);
$color-info-light5 : mix(#FFFFFF, $color-info, 90%);
$color-info-light6 : mix(#FFFFFF, $color-info, 95%);
$color-info-active : mix(#000000, $color-info, 10%);

$color-warning : #fea638;
$color-warning-light1 : mix(#FFFFFF, $color-warning, 20%);
$color-warning-light2 : mix(#FFFFFF, $color-warning, 40%);
$color-warning-light3 : mix(#FFFFFF, $color-warning, 60%);
$color-warning-light4 : mix(#FFFFFF, $color-warning, 80%);
$color-warning-light5 : mix(#FFFFFF, $color-warning, 90%);
$color-warning-light6 : mix(#FFFFFF, $color-warning, 95%);
$color-warning-active : mix(#000000, $color-warning, 10%);

$color-danger : #ff4d4f;
$color-danger-light1 : mix(#FFFFFF, $color-danger, 20%);
$color-danger-light2 : mix(#FFFFFF, $color-danger, 40%);
$color-danger-light3 : mix(#FFFFFF, $color-danger, 60%);
$color-danger-light4 : mix(#FFFFFF, $color-danger, 80%);
$color-danger-light5 : mix(#FFFFFF, $color-danger, 90%);
$color-danger-light6 : mix(#FFFFFF, $color-danger, 95%);
$color-danger-active : mix(#000000, $color-danger, 10%);

/* text-color
-------------------------- */
$color-text-primary : rgba(0, 0, 0, .85);
$color-text-default : rgba(0, 0, 0, .65);
$color-text-secondary : rgba(0, 0, 0, .45);
$color-text-disabled : rgba(0, 0, 0, .25);
$color-text-placeholder : #C0C4CC;
$btn-disable-color : #c5c8ce;
$color-disabled-bg:rgb(245, 245, 245);
$color-disabled-border:rgb(217, 217, 217);

/* bg-color
-------------------------- */
$color-bg-fa : #fafafa;
$color-select-hover : #f5f5f5;
$color-effect-shadow : alpha($color-primary);
$color-input-shadow : alpha($color-primary);
$color-input-error-shadow : alpha($color-danger);

/* border
-------------------------- */
$border-color-base : #d9d9d9;
$border-color-light : #f0f0f0;
$border-base : 1px solid $border-color-base;
$border-width:1px;
$border-base-light : 1px solid $border-color-light;
$border-table : 1px solid #e8eaec;
$border-table-color : #e8eaec;

/* radius font-size
-------------------------- */
$border-base-radius : 2px;
$base-font-size : 14px;
$header-font-size : 16px;

/* height
-------------------------- */
$large-height : 36px;
$default-height : 32px;
$small-height : 28px;
$mini-height : 24px;
$base-line-height : 1.5715;

$animation-duration-slow : 0.3s;
$animation-duration-base : 0.2s;
$animation-duration-fast : 0.1s;

// placeholder
$placeholder-color : #c0c4cc;

四、效果呈现

在这里插入图片描述
在这里插入图片描述
至此效果实现

react 官网持续开发中,也请大家持续关注博主

结语

✨ 每天创作一点点
✨ 开心快乐一整天
✨ 点赞关注加收藏
✨ 美好一天又一天

铁铁们 感谢支持 我需要你们的三连 👍👍👍
请添加图片描述

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

归来巨星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值