網站首頁 編程語言 正文
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;
/* eslint react/no-multi-comp:0 */
@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>
{/* </Col>
</Row> */}
<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
使用braft-editor踩坑記,引用 braft-utils有錯誤
最近接到一個需求,需要支持在文本輸入框支持圖片粘貼上傳,但是在我們這邊管理頁面,對于用戶提的一些問題顯示又不支持 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 了,在這里記錄一下,以免大家踩坑。
原文鏈接:https://blog.csdn.net/weixin_44779945/article/details/106575379
相關推薦
- 2022-06-21 python使用matplotlib繪制折線圖_python
- 2022-12-08 C語言程序如何求學生總成績和平均成績_C 語言
- 2023-10-25 更簡單的方法實現el-calendar日歷組件中點擊上個月、今天、下個月按鈕時的點擊事件
- 2022-06-04 解決Go語言time包數字與時間相乘的問題_Golang
- 2023-10-17 git更換遠端地址
- 2022-01-04 微信小程序內部A頁面向內嵌H5頁面跳轉,并且傳參
- 2022-04-06 python實現一個搖骰子小游戲_python
- 2022-05-29 Docker向數據卷Volume寫入數據_docker
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支