原生实现element动态添加tab -jsx封装

tab.jsx

// DynamicTabs.jsx
import React, { useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import 'bootstrap/dist/css/bootstrap.min.css';
import '@fortawesome/fontawesome-free/css/all.min.css';

const DynamicTabs = ({
  initialTabs = [],
  onTabAdd,
  onTabRemove,
  onTabChange,
  onDataChange
}) => {
  const [tabs, setTabs] = useState(initialTabs);
  const [activeTabId, setActiveTabId] = useState(null);
  const tabCounter = useRef(0);

  // 样式
  const styles = {
    tabClose: {
      marginLeft: '8px',
      cursor: 'pointer',
      padding: '2px 6px',
      borderRadius: '50%',
      position: 'absolute',
      right: '8px',
      top: '50%',
      transform: 'translateY(-50%)'
    },
    addTabButton: {
      cursor: 'pointer',
      padding: '8px 12px',
      border: 'none',
      background: 'none'
    },
    navLink: {
      paddingRight: '35px',
      position: 'relative'
    }
  };

  useEffect(() => {
    // 初始化时,如果有传入的 tabs,设置第一个为激活状态
    if (initialTabs.length > 0 && !activeTabId) {
      setActiveTabId(initialTabs[0].id);
    }
  }, []);

  const addNewTab = () => {
    const newTabId = `tab${++tabCounter.current}`;
    const newTab = {
      id: newTabId,
      productId: '',
      appName: ''
    };

    setTabs(prevTabs => [...prevTabs, newTab]);
    setActiveTabId(newTabId);
    onTabAdd?.(newTab);
  };

  const removeTab = (tabId) => {
    setTabs(prevTabs => {
      const newTabs = prevTabs.filter(tab => tab.id !== tabId);
      
      // 如果删除的是当前激活的标签,切换到其他标签
      if (activeTabId === tabId && newTabs.length > 0) {
        setActiveTabId(newTabs[0].id);
      }
      
      onTabRemove?.(tabId);
      return newTabs;
    });
  };

  const handleInputChange = (tabId, field, value) => {
    setTabs(prevTabs => {
      const newTabs = prevTabs.map(tab => {
        if (tab.id === tabId) {
          const updatedTab = { ...tab, [field]: value };
          onDataChange?.(updatedTab);
          return updatedTab;
        }
        return tab;
      });
      return newTabs;
    });
  };

  return (
    <div className="card">
      <div className="card-body">
        <div className="d-flex align-items-center">
          <ul className="nav nav-tabs flex-grow-1" role="tablist">
            {tabs.map(tab => (
              <li className="nav-item" key={tab.id}>
                <a
                  className={`nav-link ${activeTabId === tab.id ? 'active' : ''}`}
                  style={styles.navLink}
                  onClick={() => {
                    setActiveTabId(tab.id);
                    onTabChange?.(tab.id);
                  }}
                  role="tab"
                >
                  Tab {tab.id.replace('tab', '')}
                  <span
                    className="tab-close"
                    style={styles.tabClose}
                    onClick={(e) => {
                      e.stopPropagation();
                      removeTab(tab.id);
                    }}
                  >
                    <i className="fas fa-times"></i>
                  </span>
                </a>
              </li>
            ))}
          </ul>
          <button
            className="add-tab-button"
            style={styles.addTabButton}
            onClick={addNewTab}
          >
            <i className="fas fa-plus"></i> Add Tab
          </button>
        </div>

        <div className="tab-content mt-3">
          {tabs.map(tab => (
            <div
              key={tab.id}
              className={`tab-pane fade ${activeTabId === tab.id ? 'show active' : ''}`}
            >
              <form className="mt-3">
                <div className="mb-3">
                  <label htmlFor={`${tab.id}-product-id`} className="form-label">
                    Product ID
                  </label>
                  <input
                    type="text"
                    className="form-control"
                    id={`${tab.id}-product-id`}
                    value={tab.productId}
                    onChange={(e) => handleInputChange(tab.id, 'productId', e.target.value)}
                  />
                </div>
                <div className="mb-3">
                  <label htmlFor={`${tab.id}-app-name`} className="form-label">
                    App Name
                  </label>
                  <input
                    type="text"
                    className="form-control"
                    id={`${tab.id}-app-name`}
                    value={tab.appName}
                    onChange={(e) => handleInputChange(tab.id, 'appName', e.target.value)}
                  />
                </div>
              </form>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

DynamicTabs.propTypes = {
  initialTabs: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.string.isRequired,
      productId: PropTypes.string,
      appName: PropTypes.string
    })
  ),
  onTabAdd: PropTypes.func,
  onTabRemove: PropTypes.func,
  onTabChange: PropTypes.func,
  onDataChange: PropTypes.func
};

export default DynamicTabs;

使用案例:

// App.jsx 或其他组件中
import React, { useState } from 'react';
import DynamicTabs from './DynamicTabs';

const App = () => {
  const [tabsData, setTabsData] = useState([
    { id: 'tab1', productId: 'PROD-001', appName: 'App 1' }
  ]);

  const handleTabAdd = (newTab) => {
    console.log('New tab added:', newTab);
  };

  const handleTabRemove = (tabId) => {
    console.log('Tab removed:', tabId);
  };

  const handleTabChange = (tabId) => {
    console.log('Active tab changed to:', tabId);
  };

  const handleDataChange = (updatedTab) => {
    console.log('Tab data changed:', updatedTab);
    setTabsData(prevData => 
      prevData.map(tab => 
        tab.id === updatedTab.id ? updatedTab : tab
      )
    );
  };

  return (
    <div className="container mt-4">
      <DynamicTabs
        initialTabs={tabsData}
        onTabAdd={handleTabAdd}
        onTabRemove={handleTabRemove}
        onTabChange={handleTabChange}
        onDataChange={handleDataChange}
      />
    </div>
  );
};

export default App;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值