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;