react+antd Input回车输入生成tag组件

EditableTagGroup.tsx:

javascript 复制代码
import React, { useState, useRef, useEffect } from 'react'
import { Input, Tag, Tooltip, message } from 'antd'
import { CloseCircleFilled } from '@ant-design/icons'
import isEqual from 'lodash/isEqual'
import { useTranslation } from 'react-i18next'
import './index.scss'

interface ITagProps {
  value?: string[]
  onChange?: (value: string[]) => void
}

const EditableTagGroup: React.FC<ITagProps> = ({ value = [], onChange }: any) => {
  const [tags, setTags] = useState<any>(value)
  const [inputValue, setInputValue] = useState<string>('')
  const inputRef = useRef<any>(null)
  const { t } = useTranslation()

  // Sync props.value to state when it changes
  useEffect(() => {
    if (!isEqual(value, tags)) {
      setTags(value)
    }
  }, [value])

  // Notify parent component when tags change
  // useEffect(() => {
  //   if (onChange && !isEqual(value, tags)) {
  //     console.log(value, tags)
  //     onChange(tags)
  //   }
  // }, [tags])

  const handleClose = (removedTag: any) => {
    const newTags = tags.filter((tag: any) => tag.id !== removedTag.id)
    setTags(newTags)
    onChange(newTags)
  }

  const inputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setInputValue(e.target.value)
  }

  const isValidEntityToken = (t: string): boolean => {
    const re = /^(?:\p{Script=Han}|[A-Za-z])+$/u
    return t.length >= 1 && t.length <= 64 && re.test(t)
  }

  const addTag = (e: React.KeyboardEvent<HTMLInputElement>) => {
    const value = (e.target as HTMLInputElement).value
    if (value) {
      if (isValidEntityToken(value)) {
        let now = Date.now()
        const newTags = [...tags, { id: now, text: value }]
        setTags(newTags)
        setInputValue('')
        onChange(newTags)
      } else {
        message.info(t('models.entityTypesWarning'))
      }
    }
  }

  const clickEdit = () => {
    inputRef.current?.focus()
  }

  const renderTags = () => {
    return (
      <>
        {tags?.map((tag: any, index: any) => {
          const isLongTag = tag.text.length > 20
          const tagElem = (
            <Tag key={tag.id} onClose={() => handleClose(tag)} closeIcon={<CloseCircleFilled className="close-icon" />}>
              {isLongTag ? `${tag.text.slice(0, 20)}...` : tag.text}
            </Tag>
          )

          return isLongTag ? (
            <Tooltip title={tag.text} key={tag.id}>
              {tagElem}
            </Tooltip>
          ) : (
            tagElem
          )
        })}
      </>
    )
  }

  return (
    <div className="editable" onClick={clickEdit}>
      <div className="show">{renderTags()}</div>
      <Input
        className="input"
        ref={inputRef}
        placeholder={t('models.entityTypesPlaceholder')}
        onPressEnter={addTag}
        value={inputValue}
        onChange={inputChange}
      />
    </div>
  )
}

export default EditableTagGroup

index.scss:

css 复制代码
.editable {
  height: 100px;
  border-radius: 2px;
  background-color: rgba(255, 255, 255, 1);
  border: 1px solid #d9d9d9;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  &:focus-within,
  &:hover {
    border-color: rgba(22, 119, 254, 1);
    box-shadow: 0 0 4px 0 rgba(10, 42, 97, 0.2);
  }
  .ant-input {
    border: none;
    height: 32px;
    &:hover,
    &:focus {
      box-shadow: none;
      border: none;
    }
  }
  .show {
    flex: 1;
    min-height: '47px';
    overflow: auto;
    padding: 5px 5px;
    .ant-tag {
      color: #5a5e66;
      padding: 2px 8px;
      margin: 0 4px 4px 0;
      font-size: 12px;
      border: none;
      border-radius: 3px;
      background-color: rgba(240, 242, 245, 1);
      .close-icon {
        color: rgba(192, 196, 204, 1);
        margin-left: 2px;
        font-size: 12px;
      }
    }
  }
}

参考链接:

https://blog.csdn.net/qq_49464155/article/details/123247090

相关推荐
YL有搞头1 小时前
webpack的构建流程以及loader和plugin
前端·webpack·node.js
2503_928411561 小时前
11.20 vue项目搭建-单页面应用
前端·javascript·vue.js
BUG创建者1 小时前
项目中使用script-ext-html-webpack-plugin
前端·webpack·html
极光代码工作室1 小时前
基于SpringBoot的校园招聘信息管理系统的设计与实现
java·前端·spring
打小就很皮...1 小时前
React VideoPlay 组件封装与使用指南
前端·react.js·video
Ace_31750887761 小时前
微店平台关键字搜索接口深度解析:从 Token 动态生成到多维度数据挖掘
java·前端·javascript
Billow_lamb1 小时前
React 创建 Context
javascript·react.js·ecmascript
苏小画2 小时前
Vue 组件库从创建到发布全流程
前端·javascript·vue.js
月小满2 小时前
DataV轮播时其他组件的内容也一起滚动 修复bug的方法
前端·vue.js·bug·大屏端