目录braft-editor的基本使用项目需求使用braft-editor踩坑记,引用 braft-utils有错误遇到的问题解决方式braft-editor的基本使用 项目需求 实
实现照片上传,富文本为空时的提示,官网详见Braft Editor
import React, { PureComponent, Fragment } from 'react';
import { connect } from 'dva';
import BraftEditor from 'braft-editor'
import 'braft-editor/dist/index.CSS'
import moment from 'moment';
import Link from 'umi/link';
import {
Row,
Col,
Card,
Button,
message,
Divider,
Table,
Modal,
FORM,
Select,
Input,
notification
} from 'antd';
import styles from './createNotice.less';
import { router } from 'umi';
const FormItem = Form.Item;
const { Option } = Select;
@connect(({ notice, loading }) => ({
notice,
loading: loading.models.notice,
}))
@Form.create()
class CreateNotice extends PureComponent {
constructor(props) {
super(props)
this.state = {
modalVisible: false,
title: '',
labelId: '',
labelName: '',
content: '',
editorValue: '',
editorState: BraftEditor.createEditorState(null)
}
}
componentDidMount() {
this.requLabel()
}
requLabel() {
const { dispatch } = this.props
dispatch({
type: 'notice/fetchLabel'
})
}
//消息提醒
openNotification = (type, msg) => {
notification[type]({
message: msg,
});
};
//返回
GoBack = () => {
Modal.confirm({
title: '提示',
content: '返回将不保存已编辑信息,确定离开吗?',
okText: '确定',
cancelText: '取消',
onOk: () => {
router.go(-1)
},
onCancel: () => { }
})
}
//富文本的值改变时触发
handleChange = (editorState) => {
const { form } = this.props
this.setState({ editorState })
form.setFieldsValue({
content: editorState
})
}
//label的select切换
onChange = (values) => {
this.setState({
labelId: values.key,
labelName: values.label
})
}
//预览
preView = () => {
this.props.form.validateFields((error, values) => {
// if (!error) {
this.setState({
modalVisible: true,
title: values.title,
content: values.content.tohtml()
})
// }
})
}
//关闭
handleOk = () => {
this.setState({
modalVisible: false
})
}
//发布
handleSubmit = (event) => {
const { dispatch, form } = this.props;
const { labelId, editorState } = this.state
event.preventDefault()
form.validateFields((error, values) => {
if (error) {
return
}
let edit = this.state.editorState.isEmpty() //用isEmpty判断是否为空
if (edit) {
this.openNotification('warn', '请输入内容')
return
}
if (!error) {
const submitData = {
title: values.title,
infoLabelId: labelId,
content: window.btoa(window.encodeURIComponent(values.content.toHTML())) // or values.content.toRAW()
}
Modal.confirm({
title: '提示',
content: '确认发布吗?',
okText: '确定',
cancelText: '取消',
onOk: () => {
dispatch({
type: 'notice/publish',
payload: submitData,
callback: res => {
if (res.success) {
this.openNotification('success', '发布成功')
router.go(-1)
} else {
this.openNotification('error', '发布失败')
}
}
})
},
onCancel: () => { }
})
}
})
}
//上传媒体
uploadPic = (param) => {
//也可以用fetch或者axiOS,用formData
const token = localStorage.getItem('meiyun-operation-token')
const serverURL = '/meiyun-resource/oss/endpoint/put-file'
const xhr = new XMLHttpRequest
const fd = new FormData()
const successFn = (response) => {
let url = JSON.parse(xhr.responseText).data.link
// 文件上传到服务端成功后获取地址
// 上传成功后调用param.success并传入上传后的文件地址
param.success({
url,
meta: {
id: 'xxx',
title: 'xxx',
alt: 'xxx',
loop: true, // 指定音视频是否循环播放
autoPlay: true, // 指定音视频是否自动播放
controls: true, // 指定音视频是否显示控制栏
poster: 'http://xxx/xx.png', // 指定视频播放器的封面
}
})
}
const progressFn = (event) => {
// 上传进度发生变化时调用param.progress
param.progress(event.loaded / event.total * 100)
}
const errorFn = (response) => {
// 上传发生错误时调用param.error
param.error({
msg: '上传失败'
})
}
xhr.upload.addEventListener("progress", progressFn, false)
xhr.addEventListener("load", successFn, false)
xhr.addEventListener("error", errorFn, false)
xhr.addEventListener("abort", errorFn, false)
fd.append('file', param.file)
xhr.open('POST', serverURL, true)
xhr.setRequestHeader('Blade-Auth', 'Bearer ' + token);
xhr.send(fd)
}
render() {
const {
form: { getFieldDecorator },
notice: { labelData },
loading,
} = this.props;
const { modalVisible, title, labelName, content } = this.state
const formItemLayout = {
labelCol: { span: 4 },
wrapperCol: { span: 18 }
}
const controls = [
'font-size',
'font-family',
'list-ol',
'list-ul',
'hr',
'text-align', 'bold', 'italic', 'underline', 'text-color', 'separator', 'superscript',
'subscript', 'separator', 'media', 'letter-spacing',
'line-height',
'clear',]
return (
<div className={styles.container}>
<div className={styles.title}>
<span onClick={this.goBack}>< 公告管理</span>
</div>
<div className={styles.formBox}>
<Form onSubmit={this.handleSubmit} layout="horizontal" {...formItemLayout}>
<FormItem label="公告标题" {...formItemLayout}>
{getFieldDecorator('title', {
rules: [{ required: true, message: '请输入公告标题' }, { message: '公告标题不能输入<或>', pattern: new RegExp('^[^<\|^>]+$', 'g') }, { message: '公告标题不能超过30个字符', max: 30 }]
})(<Input placeholder="请输入公告标题" style={{ width: 300 }} />)}
</FormItem>
<FormItem {...formItemLayout} label="标签">
{getFieldDecorator('labelId')(
<Select
showSearch
style={{ width: 300 }}
placeholder="请选择标签"
labelInValue={true}
optionFilterProp="children"
onChange={this.onChange}
onFocus={this.onFocus}
onBlur={this.onBlur}
filterOption={(input, option) =>
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
{labelData.length && labelData.map(item => {
return (
<Option value={item.id} key={item.id}>{item.labelTitle}</Option>
)
})}
</Select>
)}
</FormItem>
{}
<FormItem {...formItemLayout} label="内容">
{getFieldDecorator('content', {
rules: [{
required: true,
message: '请输入正文内容'
}],
})(<BraftEditor
ref={instance => this.editorInstance = instance}
className={styles.myEditor}
controls={controls}
onChange={this.handleChange}
forceNewLine={true}
placeholder="请输入正文内容"
media={{ uploadFn: this.uploadPic }}
/>)}
</FormItem>
<FormItem>
<Row gutter={{ md: 24, lg: 48, xl: 48 }}>
<Col md={18} sm={24}></Col>
<Col md={6} sm={24}>
<Button style={{ marginRight: 20 }} onClick={this.preView}>预览</Button>
<Button type="primary" htmlType="submit">发布</Button>
</Col>
</Row>
</FormItem>
</Form>
</div>
{modalVisible && <Modal
title="预览"
visible={modalVisible}
maskClosable={false}
width={1000}
footer={[
<Button key="submit" type="primary" loading={loading} onClick={this.handleOk}>
关闭
</Button>
]}
onOk={this.handleOk}
onCancel={this.handleOk}>
<div>
<h2 style={{ textAlign: 'center' }}>{title}</h2>
<p>{labelName}</p>
<div dangerouslySetInnerHTML={{ __html: content }}></div>
</div>
</Modal>}
</div>
)
}
}
export default CreateNotice
最近接到一个需求,需要支持在文本输入框支持图片粘贴上传,但是在我们这边管理页面,对于用户提的一些问题显示又不支持 Matkdown。
所以选择 braft-editor 来实现,发现提供一些配置项,因为我这边不需要那些加粗,下划线等等按钮,只需要上传图片,粘贴然后配合 COS 存链接就好了。
首先我这个是 React 项目,其它项目不太清楚,然后使用 yarn。
在 utils 官方仓库中,有相关 issues,链接在下方:
引用 braft-utils 有错误 #500
其中也有人提及了一些解决方案,但是并没有解决问题,一直报错:
TS7016: Could not find a declaration file for module ‘braft-utils’. ‘xxx/node_modules/braft-utils/dist/index.js’ implicitly has an ‘any’ type.
Try npm i --save-dev @types/braft-utils if it exists or add a new declaration (.d.ts) file containing declare module 'braft-utils';
看这个报错信息,有提示,用 npm 安装那个依赖,我已经试过了,并没有效果,不存在那个依赖包。
直接少废话,以下是解决方式:
yarn add braft-finder
yarn add braft-utils
yarn add draft-js-multidecorators
yarn add draftjs-utils
然后在你当前需要引入的文件那,同级目录底下创建一个名为 xxx.d.ts 文件,放入以下定义:
declare module 'braft-utils';
declare module 'braft-finder';
弄完之后记得重新 yarn dev ,之后就会出现如下页面,完美解决。
弄完这个问题,还就那个焦头烂额的,不过总算没有 bug 了,在这里记录一下,以免大家踩坑。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。
--结束END--
本文标题: react中braft-editor的基本使用方式
本文链接: https://lsjlt.com/news/167527.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-01-12
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
2023-05-20
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0