react实现一个表格内容添加到文本的编辑器
技术攻克难点
一.输入框的值修改(onChange)
二.dangerouslySetInnerHTML的使用
1.dangerouslySetInnerHTMl 是React标签的一个属性,类似于angular的ng-bind;
2.有2个{{}},第一{}代表jsx语法开始,第二个是代表dangerouslySetInnerHTML接收的是一个对象键值对;
3.既可以插入DOM,又可以插入字符串;
4.不合时宜的使用 innerHTML 可能会导致 cross-site scripting (XSS) 攻击。 净化用户的输入来显示的时候,经常会出现错误,不合适的净化也是导致网页攻击的原因之一。dangerouslySetInnerHTML 这个 prop 的命名是故意这么设计的,以此来警告,它的 prop 值( 一个对象而不是字符串 )应该被用来表明净化后的数据。
代码实现
/*
@返回文本的实例
{
"key": 0,
"result": "<div><span style=\"color:red\">你好</span><span style=\"color:red\">你好</span></div>",
"text": "你好你好你好你好你好你好你好你好"
},
*/
import 'moment/locale/zh-cn';
import locale from 'antd/es/date-picker/locale/zh_CN';
import React, { Component } from 'react';
import axios from 'axios';
import utils from "../../utils"
import { Input, Button, DatePicker, Space, Table, Row ,Col} from 'antd';
import './index.less'
const { TextArea } = Input;
let path = window.location.pathname.split('/')[1], search, url
if (window.location.search) {
search = window.location.search
const s = search.substr(1, search.length).split('&')
const m = s[0].split('=')
url = `http://nlpai.woa.com/${m[1]}/`
} else {
url = `http://nlpai.woa.com/${path}/end/`
}
export default class TopicCards extends Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
this.state = {
data: [
],
list:[],
isLoaded: false,
value:''
}
}
// 向后台发送请求
async getRequest (value) {
console.log(this.state.timeInterval)
if (value) {
const _this = this;
utils.post({
url:`http://*****(项目路径保密)`,
data:{
"query":value
}
}).then(res => {
console.log(res)
this.setState({
data:res
})
})
} else {
alert('请正确填写openid或微信号')
}
}
// 展示表格
showTable () {
const columns = [
{
title: 'right',
dataIndex: 'result',
key: '0',
render:(result)=>{
return <div dangerouslySetInnerHTML={{ __html: result.replace('script','') }}></div>
}
}
];
return (
<Table columns={columns} dataSource={this.state.data} scroll={{ y: 900 }} pagination={false}
onRow={record => {
return {
onClick: event => {this.addList(record.text)}, // 点击行
};
}} />
)
}
// 添加的表格
addList(value){
console.log(value)
const v=this.state.value
this.setState({
value:v+value+'\n'
})
}
onChange = ({ target: { value } }) => {
this.setState({ value });
};
render () {
return (
<div className="rightToLeft">
<h1>弹幕检索 </h1>
{/*搜索*/}
<div className="search">
<Input size="large" style={{ width: 400 }} placeholder="请搜索" ref={this.textInput} onPressEnter={()=>{this.getRequest(this.textInput.current.state.value)}} /> 
<Button type="primary" size="large" onClick={() => {
this.getRequest(this.textInput.current.state.value)
}}>查询</Button> 
</div>
<div className="tables">
<div className="left">
<TextArea rows={4} allowClear value={this.state.value} onChange={this.onChange} autoSize={{ minRows: 24, maxRows: 44 } }/>
</div>
<div className="right">
{this.showTable()}
</div>
</div>
</div>
)
}
}
效果图如下:
另附antd表格编辑组件封装jsx
import React, { useContext, useState, useEffect, useRef } from 'react';
import { Table, Input, Button, Popconfirm, Form } from 'antd';
const EditableContext = React.createContext();
const EditableRow = ({ index, ...props }) => {
const [form] = Form.useForm();
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
const EditableCell = ({
title,
editable,
children,
dataIndex,
record,
handleSave,
...restProps
}) => {
const [editing, setEditing] = useState(false);
const inputRef = useRef();
const form = useContext(EditableContext);
useEffect(() => {
if (editing) {
inputRef.current.focus();
}
}, [editing]);
const toggleEdit = () => {
setEditing(!editing);
form.setFieldsValue({
[dataIndex]: record[dataIndex],
});
};
const save = async (e) => {
try {
const values = await form.validateFields();
toggleEdit();
handleSave({ ...record, ...values });
} catch (errInfo) {
console.log('Save failed:', errInfo);
}
};
let childNode = children;
if (editable) {
childNode = editing ? (
<Form.Item
style={{
margin: 0,
}}
name={dataIndex}
rules={[
{
required: true,
message: `${title} is required.`,
},
]}
>
<Input ref={inputRef} onPressEnter={save} onBlur={save} />
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{
paddingRight: 24,
}}
onClick={toggleEdit}
>
{children}
</div>
);
}
return <td {...restProps}>{childNode}</td>;
};
class EditableTable extends React.Component {
constructor(props) {
super(props);
this.columns = [
{
title: 'name',
dataIndex: 'name',
width: '30%',
editable: true,
},
];
this.state = {
dataSource: [
{
key: '0',
name: 'Edward King 0',
age: '32',
address: 'London, Park Lane no. 0',
},
{
key: '1',
name: 'Edward King 1',
age: '32',
address: 'London, Park Lane no. 1',
},
],
};
}
handleSave = (row) => {
const newData = [...this.state.dataSource];
const index = newData.findIndex((item) => row.key === item.key);
const item = newData[index];
newData.splice(index, 1, { ...item, ...row });
this.setState({
dataSource: newData,
});
};
render() {
console.log(this.props.lists)
const { dataSource } = this.state;
const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};
const columns = this.columns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record) => ({
record,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
handleSave: this.handleSave,
}),
};
});
return (
<div>
<Table
components={components}
rowClassName={() => 'editable-row'}
bordered
dataSource={dataSource}
columns={columns}
/>
</div>
);
}
}
export default EditableTable;