用前端开发写一个1、空白页面里面有一个新增按钮,点击新增行,手动输入行属性,然后生成一个新区域和行 2、每行里面都包含新增和删除按钮,点击新增手动输入行属性,可以在此行后面新增一行;如果新增行与当前行属性一样,则2行合并为一个区域,里面包含2行;如果新增行与当前行属性不一样,则生成一个新的区域和行; 如果在同一区域中,包含多行,在非本区域最后一行上点击新增,新增的行属性与本行的不一致,则会对原来的区域进行一个切割操作 举例(如视屏):目前页面已有A区域,里面包含3行(行属性是A),在第2行上点击新增,新增的行属性是C,那么原来的A区域就会分为2半:上面A区域包含2行,中间是新的C区域包含1行,下面A区域包含1行 3、点击行里面的删除按钮,则删除本行,如果区域中的最后一行被删除,则同时删除此区域提示: 注意需求中的描述,既有区域,区域中又包含行,所以有2层结构,那么数据结构也要与之对应才能实现!!!
时间: 2023-10-08 19:12:48 浏览: 76
这个需求可以使用 React 框架来实现,需要设计两个组件,一个是区域组件,一个是行组件。同时,需要考虑数据结构的设计,可以使用数组来存储所有的区域和行的信息。
首先,我们来设计区域组件,代码如下:
```jsx
import React from 'react';
import Row from './Row';
class Area extends React.Component {
constructor(props) {
super(props);
this.state = {
rows: props.rows || []
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.rows !== this.props.rows) {
this.setState({ rows: nextProps.rows });
}
}
handleAddRow = () => {
const newRow = {
id: Date.now(),
name: '',
desc: ''
};
this.setState(state => ({ rows: [...state.rows, newRow] }));
};
handleDeleteRow = (id) => {
this.setState(state => ({
rows: state.rows.filter(row => row.id !== id)
}), () => {
if (this.state.rows.length === 0) {
this.props.onDeleteArea(this.props.id);
}
});
};
render() {
const { rows } = this.state;
return (
<div className="area">
<button onClick={this.handleAddRow}>新增行</button>
{rows.map(row => (
<Row
key={row.id}
id={row.id}
name={row.name}
desc={row.desc}
onDeleteRow={this.handleDeleteRow}
/>
))}
</div>
);
}
}
export default Area;
```
在上面的代码中,我们定义了一个 Area 组件,它接收一个 rows 属性,表示当前区域中包含的所有行。在组件的构造函数中,我们将这个属性保存到组件的 state 中。在 componentWillReceiveProps 生命周期方法中,如果 rows 属性发生了变化,我们会更新组件的 state。
在 render 方法中,我们首先渲染一个新增行的按钮。然后,我们遍历所有的行,渲染 Row 组件,并将行的属性传递给它。同时,我们还将 handleDeleteRow 方法传递给 Row 组件,以便在行被删除时能够从 state 中删除对应的行信息,并更新区域组件的 state。
接下来,我们来设计行组件,代码如下:
```jsx
import React from 'react';
class Row extends React.Component {
constructor(props) {
super(props);
this.state = {
name: props.name || '',
desc: props.desc || ''
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.name !== this.props.name || nextProps.desc !== this.props.desc) {
this.setState({
name: nextProps.name,
desc: nextProps.desc
});
}
}
handleAddRow = () => {
const newRow = {
id: Date.now(),
name: '',
desc: ''
};
this.props.onAddRow(this.props.id, newRow);
};
handleDeleteRow = () => {
this.props.onDeleteRow(this.props.id);
};
handleNameChange = (event) => {
this.setState({ name: event.target.value });
};
handleDescChange = (event) => {
this.setState({ desc: event.target.value });
};
handleBlur = () => {
const { name, desc } = this.state;
this.props.onChange(this.props.id, { name, desc });
};
render() {
const { name, desc } = this.state;
return (
<div className="row">
<input type="text" value={name} onChange={this.handleNameChange} onBlur={this.handleBlur} />
<input type="text" value={desc} onChange={this.handleDescChange} onBlur={this.handleBlur} />
<button onClick={this.handleAddRow}>新增行</button>
<button onClick={this.handleDeleteRow}>删除行</button>
</div>
);
}
}
export default Row;
```
在上面的代码中,我们定义了一个 Row 组件,它接收三个属性:id、name 和 desc,分别表示行的唯一标识、名称和描述。在组件的构造函数中,我们将这些属性保存到组件的 state 中。在 componentWillReceiveProps 生命周期方法中,如果 name 或 desc 属性发生了变化,我们会更新组件的 state。
在 render 方法中,我们首先渲染两个输入框,分别用于编辑行的名称和描述。然后,我们渲染新增行和删除行的按钮,并将对应的事件方法传递给它们。在输入框失去焦点时,我们会调用 handleBlur 方法,将当前行的名称和描述信息传递给父组件,以便更新 state。
最后,我们需要设计整个页面的数据结构和事件处理方法,代码如下:
```jsx
import React from 'react';
import Area from './Area';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
areas: []
};
}
handleAddRow = (areaId, newRow) => {
this.setState(state => {
const areaIndex = state.areas.findIndex(area => area.id === areaId);
const area = state.areas[areaIndex];
const rows = area.rows;
const rowIndex = rows.findIndex(row => row.id === newRow.id);
if (rowIndex >= 0 && rows[rowIndex].name === newRow.name && rows[rowIndex].desc === newRow.desc) {
const newRows = rows.slice(0, rowIndex).concat([{ ...newRow, id: Date.now() }], rows.slice(rowIndex + 1));
return {
areas: [
...state.areas.slice(0, areaIndex),
{ ...area, rows: newRows },
...state.areas.slice(areaIndex + 1)
]
};
} else {
const newArea = {
id: Date.now(),
rows: [newRow]
};
return {
areas: [
...state.areas.slice(0, areaIndex),
{ ...area, rows: rows.slice(0, rowIndex + 1) },
newArea,
{ ...area, rows: rows.slice(rowIndex + 1) },
...state.areas.slice(areaIndex + 1)
]
};
}
});
};
handleChangeRow = (rowId, newRow) => {
this.setState(state => {
const areas = state.areas.map(area => {
const rows = area.rows.map(row => {
if (row.id === rowId) {
return { ...row, ...newRow };
} else {
return row;
}
});
return { ...area, rows };
});
return { areas };
});
};
handleDeleteArea = (areaId) => {
this.setState(state => ({
areas: state.areas.filter(area => area.id !== areaId)
}));
};
handleDeleteRow = (rowId) => {
this.setState(state => {
const areas = state.areas.map(area => {
const rows = area.rows.filter(row => row.id !== rowId);
return { ...area, rows };
});
return { areas };
});
};
handleAddArea = () => {
const newArea = {
id: Date.now(),
rows: []
};
this.setState(state => ({ areas: [...state.areas, newArea] }));
};
render() {
const { areas } = this.state;
return (
<div className="app">
<button onClick={this.handleAddArea}>新增区域</button>
{areas.map(area => (
<Area
key={area.id}
id={area.id}
rows={area.rows}
onDeleteArea={this.handleDeleteArea}
onAddRow={this.handleAddRow}
onDeleteRow={this.handleDeleteRow}
/>
))}
</div>
);
}
}
export default App;
```
在上面的代码中,我们定义了一个 App 组件,它包含一个新增区域的按钮和所有的区域组件。在组件的构造函数中,我们初始化 state 中的 areas 属性为空数组。
在 handleAddRow 方法中,我们首先找到对应的区域和行,判断新增的行是否与当前行属性一致。如果一致,我们将新行加入到当前行后面,同时生成一个新的行。如果不一致,我们将当前区域分为三部分:上面的所有行、中间的新区域和下面的所有行,然后将它们合并起来。最后,我们更新整个页面的 state。
在 handleChangeRow 方法中,我们遍历所有的区域和行,找到对应的行,并将它的名称和描述信息更新为新的值。然后,我们更新整个页面的 state。
在 handleDeleteArea 方法中,我们找到对应的区域,并删除它。然后,我们更新整个页面的 state。
在 handleDeleteRow 方法中,我们遍历所有的区域和行,找到对应的行,并删除它。如果区域中已经没有行了,我们也会将对应的区域删除。然后,我们更新整个页面的 state。
最后,在 render 方法中,我们首先渲染新增区域的按钮。然后,我们遍历所有的区域,渲染 Area 组件,并将区域的属性传递给它。同时,我们还将 handleDeleteArea、handleAddRow 和 handleDeleteRow 方法传递给 Area 组件,以便在区域和行被删除或新增时能够更新整个页面的 state。
这样,我们就完成了整个页面的设计和实现。用户可以通过点击新增按钮和删除按钮来添加和删除区域和行,通过编辑输入框来修改行的属性。同时,系统也能自动地将相同属性的行合并为一个区域,并在新增行与当前行属性不一致时进行区域切割操作。
阅读全文