文章目录
一、组件库介绍
有兴趣的同学 可以先着手看源码,之前写的一系列开源组件库项目(有帮助的同学也帮忙点个star👍)
名称 | 官网 | github |
---|---|---|
tinkerbell-ui(vue2.0) | http://tinkerbell.top | https://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 |
二、Checkbox、CheckboxGroup组件流程介绍
关于 CheckboxGroup 也就是用来包裹 Checkbox 的一个通用组件,用于处理 Checkbox 组件变化监听回调的这样一个组件,其实主要的也是如何使用父组件去监听子组件的变化这样一个点,所以我们要在 CheckboxGroup 组件当中去捕获 Checkbox 的一个value变化,所以我们给 Checkbox 一个 onChange,然后 CheckboxGroup 去抓取,因为 Checkbox、CheckboxGroup 是自定义组件所以我们使用React.Children.map、React.cloneElement 去对子组件内容进行捕获。
CheckBoxGroup
name?: string // 原生 name 属性
disabled: boolean // 是否统一禁用
options: any // js编程式组件列表
value: any // 绑定 value 值
CheckBox
type: string // 样式类型
checked: boolean // 是否选中
disabled: boolean // 是否禁用
checkGroupValue: any // 父 group 的 value 值
value: string | number // 单独 value 值
name?: string // 原生 name 属性
label: string // label 名称
indeterminate?: any // 是否为统一全选控制按钮组件
三、代码详解
3.1、CheckBoxGroup.tsx
import React from 'react'
import CheckBox from '../CheckBox/index'
interface Iprops {
name?: string // 原生 name 属性
disabled: boolean // 是否统一禁用
options: any // js编程式组件列表
value: any // 绑定 value 值
}
function CheckBoxGroup(props: any) {
const { name, value = [], options = [] }: Iprops = props
function handleChange(evt: any) {
// 有就删除 没有就新增
value.indexOf(evt.target.value) > -1
? value.splice(value.indexOf(evt.target.value), 1)
: value.push(evt.target.value)
// 判断check选中状态
console.log(value)
props.onChange && props.onChange(value, evt)
}
// options 循环遍历
const checkboxDom = options.map((item: any) => {
return (
<CheckBox
key={item.value}
value={item.value}
checkGroupValue={value}
name={name}
disabled={item.disabled ? item.disabled : null}
onChange={handleChange}
>
{item.label}
</CheckBox>
)
})
// 遍历dom子节点方式
const checkboxItems = React.Children.map(props.children, (item) => {
return React.cloneElement(item, {
item,
componentName: 'checkboxGroup',
checkGroupValue: value,
name,
onChange: handleChange
})
})
return (
<div className='tb-checkbox-group'>
{checkboxItems ? checkboxItems : checkboxDom}
</div>
)
}
export default CheckBoxGroup
3.2、Checkbox.tsx
import React, { useEffect, useState } from 'react'
import './index.scss'
const classnames = require('classnames')
interface Iprops {
type: string // 样式类型
checked: boolean // 是否选中
disabled: boolean // 是否禁用
checkGroupValue: any // 父 group 的 value 值
value: string | number // 单独 value 值
name?: string // 原生 name 属性
label: string // label 名称
indeterminate?: any // 是否为统一全选控制按钮组件
}
function CheckBox(props: any) {
const {
type = 'default',
disabled = false,
checked = false,
value,
name,
label,
checkGroupValue = [],
indeterminate
}: Iprops = props
const [checkBoxChecked, setCheckBoxChecked] = useState(checked || false)
const [isIndeterminate, setIsIndeterminate] = useState(false)
useEffect(() => {
// 监听 初始化判断是否为 多选组选项行为
if (!!checkGroupValue.length && checkGroupValue.includes(value)) {
setCheckBoxChecked(true)
} else if (
(indeterminate === 'undefined' && !checkGroupValue.length) ||
(indeterminate === undefined && !checkGroupValue.length) ||
(indeterminate === null && !checkGroupValue.length)
) {
setCheckBoxChecked(false)
}
}, [props.checkGroupValue]) // eslint-disable-line
useEffect(() => {
setCheckBoxChecked(checked)
}, [props.checked]) // eslint-disable-line
useEffect(() => {
console.log(checkBoxChecked, 3333)
}, [checkBoxChecked]) // eslint-disable-line
useEffect(() => {
setIsIndeterminate(!!indeterminate ? indeterminate : false)
}, [indeterminate]) // eslint-disable-line
function handleChange(evt: any) {
setCheckBoxChecked(evt.target.checked)
props.onChange && props.onChange(evt)
}
return (
<div
className={[
'tb-checkbox',
classnames({
'is-disabled': disabled
})
].join(' ')}
>
<label>
<input
type='checkbox'
checked={checkBoxChecked}
name={name}
disabled={disabled}
onChange={handleChange}
value={value || label}
className={[
`checkbox-type_${type}`,
classnames({
'is-disabled': disabled,
// 判断是否需要 全选,如果全选加标记
'is-indeterminate': isIndeterminate
})
].join(' ')}
/>
<span>{props.children ? props.children : label ? label : value}</span>
</label>
</div>
)
}
export default CheckBox
3.3、Checkbox / index.scss
@import '../../style/variables.scss';
$type:('success', 'primary', 'danger', 'warning', 'info', 'default');
@function typeFunction($t) {
@if $t==success {
@return $color-success
}
@else if $t==primary {
@return $color-primary
}
@else if $t==info {
@return $color-info
}
@else if $t==danger {
@return $color-danger
}
@else if $t==warning {
@return $color-warning
}
@return $color-primary
}
@function typeDisabledFunction($t) {
@if $t==success {
@return $color-success-light2
}
@else if $t==primary {
@return $color-primary-light2
}
@else if $t==info {
@return $color-info-light2
}
@else if $t==danger {
@return $color-danger-light2
}
@else if $t==warning {
@return $color-warning-light2
}
@return $color-primary-light2
}
.tb-checkbox {
display: inline-block;
label {
display: flex;
align-items: center;
cursor: pointer;
}
}
@each $t in $type {
.checkbox-type_#{$t} {
width: 20px;
height: 20px;
display: inline-block;
text-align: center;
vertical-align: baseline;
// line-height: 1.54rem;
position: relative;
outline: none;
-webkit-appearance: none;
border: 1px solid #fff;
-webkit-tab-highlight-color: rgba(0, 0, 0, 0);
color: #fff;
background: #fff;
margin-right: 3px;
}
.checkbox-type_#{$t}:checked+span {
color: typeFunction($t);
cursor: pointer;
}
.checkbox-type_#{$t}::before {
content: "";
position: absolute;
top: 0;
left: 0;
background: #fff;
width: 75%;
height: 75%;
border: 1px solid $color-text-placeholder;
color: #fff;
cursor: pointer;
}
.checkbox-type_#{$t}:checked::before {
content: "\2713";
background-color: typeFunction($t);
border: 1px solid typeFunction($t);
position: absolute;
top: 0;
left: 0;
width: 75%;
color: #fff;
cursor: pointer;
}
// .checkbox-type_#{$t}.is-indeterminate::before {
// background-color: typeFunction($t);
// // border: 1px solid typeFunction($t);
// width: 75%;
// padding: 10px;
// box-sizing: border-box;
// position: absolute;
// top: 0;
// left: 0;
// color: #fff;
// cursor: pointer;
// }
.checkbox-type_#{$t}.is-indeterminate:after {
content: "";
width: 45%;
height: 45%;
text-align: center;
background-color: typeFunction($t);
display: block;
position: absolute;
top: 20%;
left: 20%;
cursor: pointer;
}
.checkbox-type_#{$t}.is-disabled:checked::before {
content: "\2713";
background-color: $color-disabled-bg;
border: 1px solid $color-disabled-border;
position: absolute;
top: 0;
left: 0;
width: 75%;
color: $color-text-primary;
cursor: pointer;
}
.checkbox-type_#{$t}.is-disabled:before {
background-color: $color-disabled-bg;
border: 1px solid $color-disabled-border;
cursor: not-allowed;
}
.checkbox-type_#{$t}.is-disabled+span {
color: $color-text-disabled;
cursor: not-allowed;
}
}
3.4、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 官网持续开发中,也请大家持续关注博主
结语
✨ 每天创作一点点
✨ 开心快乐一整天
✨ 点赞关注加收藏
✨ 美好一天又一天
铁铁们 感谢支持 我需要你们的三连 👍👍👍