【笔记】手写checkbox组件

762 阅读2分钟

如何使用:


const AuthWrap: React.FC<AuthWrapProps> = (props) => {

...

    const AllCheckedEl = useMemo(
        () => (
          <CheckNode
            text="全选"
            checkStatus={allCheckedStatus}
            value="allChecked"
            onChange={(checkStatus) => handleAllChecked(checkStatus)}
          />
        ),
        [allCheckedStatus, handleAllChecked],
      );

      return (
        <>
          {AllCheckedEl}
          ...
        </>
      );
 
  ...
  
  }

组件页面

/* eslint-disable no-param-reassign */
import React from 'react';
import type { CheckItemProps } from './index.d';

import './index.less';

const CheckNode: React.FC<CheckItemProps> = (props) => {
  const { checkStatus, text, onChange } = props;
  const classMap = {
    NOTCHECKED: "",
    CHECKED: "checked",
    INDETERMINATE: "indeterminate"
  }

  const handleClick = () => {
    if (checkStatus === "CHECKED" || checkStatus === "INDETERMINATE") {
      onChange("NOTCHECKED");
    } else {
      onChange("CHECKED");
    }
  }

  return (
    <>
      <span
        onClick={handleClick}
        className={`select-tree-checkbox select-tree-checkbox-${classMap[checkStatus]}`}
      >
        <span className="select-tree-checkbox-inner"></span>
      </span>
      <span className={`select-tree-text select-tree-text-${classMap[checkStatus]}`}>
        {text}
      </span>
    </>
  );
};

export default CheckNode;

css

  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  color: rgba(0, 0, 0, 0.85);
  font-size: 14px;
  font-variant: tabular-nums;
  line-height: 1.5715;
  list-style: none;
  -webkit-font-feature-settings: 'tnum';
  font-feature-settings: 'tnum';
  position: relative;
  top: -0.09em;
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
  vertical-align: middle;
  outline: none;
  cursor: pointer;
}

.select-tree-checkbox-wrapper:hover .select-tree-checkbox-inner,
.select-tree-checkbox:hover .select-tree-checkbox-inner,
.select-tree-checkbox-input:focus+.select-tree-checkbox-inner {
  border-color: #1890ff;
}

.select-tree-checkbox-checked::after {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 1px solid #1890ff;
  border-radius: 2px;
  visibility: hidden;
  -webkit-animation: antCheckboxEffect 0.36s ease-in-out;
  animation: antCheckboxEffect 0.36s ease-in-out;
  -webkit-animation-fill-mode: backwards;
  animation-fill-mode: backwards;
  content: '';
}

.select-tree-checkbox:hover::after,
.select-tree-checkbox-wrapper:hover .select-tree-checkbox::after {
  visibility: visible;
}

.select-tree-checkbox-inner {
  position: relative;
  top: 0;
  left: 0;
  display: block;
  width: 16px;
  height: 16px;
  direction: ltr;
  background-color: #fff;
  border: 1px solid #d9d9d9;
  border-radius: 2px;
  border-collapse: separate;
  -webkit-transition: all 0.3s;
  transition: all 0.3s;
}

.select-tree-checkbox-inner::after {
  position: absolute;
  top: 50%;
  left: 22%;
  display: table;
  width: 5.71428571px;
  height: 9.14285714px;
  border: 2px solid #fff;
  border-top: 0;
  border-left: 0;
  -webkit-transform: rotate(45deg) scale(0) translate(-50%, -50%);
  transform: rotate(45deg) scale(0) translate(-50%, -50%);
  opacity: 0;
  -webkit-transition: all 0.1s cubic-bezier(0.71, -0.46, 0.88, 0.6), opacity 0.1s;
  transition: all 0.1s cubic-bezier(0.71, -0.46, 0.88, 0.6), opacity 0.1s;
  content: ' ';
}

.select-tree-checkbox-input {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  cursor: pointer;
  opacity: 0;
}

.select-tree-checkbox-checked .select-tree-checkbox-inner::after {
  position: absolute;
  display: table;
  border: 2px solid #fff;
  border-top: 0;
  border-left: 0;
  -webkit-transform: rotate(45deg) scale(1) translate(-50%, -50%);
  transform: rotate(45deg) scale(1) translate(-50%, -50%);
  opacity: 1;
  -webkit-transition: all 0.2s cubic-bezier(0.12, 0.4, 0.29, 1.46) 0.1s;
  transition: all 0.2s cubic-bezier(0.12, 0.4, 0.29, 1.46) 0.1s;
  content: ' ';
}

.select-tree-checkbox-checked .select-tree-checkbox-inner {
  background-color: #1890ff;
  border-color: #1890ff;
}

.select-tree-checkbox-disabled {
  cursor: not-allowed;
}

.select-tree-checkbox-disabled.select-tree-checkbox-checked .select-tree-checkbox-inner::after {
  border-color: rgba(0, 0, 0, 0.25);
  -webkit-animation-name: none;
  animation-name: none;
}

.select-tree-checkbox-disabled .select-tree-checkbox-input {
  cursor: not-allowed;
}

.select-tree-checkbox-disabled .select-tree-checkbox-inner {
  background-color: #f5f5f5;
  border-color: #d9d9d9 !important;
}

.select-tree-checkbox-disabled .select-tree-checkbox-inner::after {
  border-color: #f5f5f5;
  border-collapse: separate;
  -webkit-animation-name: none;
  animation-name: none;
}

.select-tree-text {
  margin-left: 8px;
}

.select-tree-text-indeterminate,
.select-tree-text-checked {
  color: #1890ff;
}

.select-tree-checkbox-indeterminate .select-tree-checkbox-inner {
  background-color: #fff;
  border-color: #d9d9d9;
}

.select-tree-checkbox-indeterminate .select-tree-checkbox-inner::after {
  top: 50%;
  left: 50%;
  width: 8px;
  height: 8px;
  background-color: #1890ff;
  border: 0;
  -webkit-transform: translate(-50%, -50%) scale(1);
  transform: translate(-50%, -50%) scale(1);
  opacity: 1;
  content: ' ';
}

.select-tree-checkbox-indeterminate.select-tree-checkbox-disabled .select-tree-checkbox-inner::after {
  background-color: rgba(0, 0, 0, 0.25);
  border-color: rgba(0, 0, 0, 0.25);
}

.auth-table {
  border-collapse: collapse;
  margin-top: 40px;
  table-layout: fixed;
  max-width: 100%;
  min-width: 1200px;
}

.auth-table td {
  border: 1px solid #f0f0f0;
  min-width: 120px;
  font-size: 14px;
  color: #333;
  line-height: 40px;
  padding: 2px 20px;
  max-width: 200px;

  .ant-checkbox-wrapper {
    user-select: none;
    margin: 4px 10px;

    .ant-checkbox {
      margin-right: 4px;
    }
  }
}

.auth-table tr>td:nth-child(1) {
  background: #fcfcfc;
}

.auth-table thead tr>td {
  color: rgba(0, 0, 0, .85);
  font-weight: 500;
  text-align: left;
  background: #f0f0f0 !important;
  border-bottom: 1px solid #f0f0f0;
  transition: background .3s ease;
}