最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

react中braft-editor的基本使用方式

 更新時(shí)間:2022年09月14日 14:40:53   作者:wwww....  
這篇文章主要介紹了react中braft-editor的基本使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

braft-editor的基本使用

項(xiàng)目需求

實(shí)現(xiàn)照片上傳,富文本為空時(shí)的提示,官網(wǎng)詳見(jiàn)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: '返回將不保存已編輯信息,確定離開(kāi)嗎?',
            okText: '確定',
            cancelText: '取消',
            onOk: () => {
                router.go(-1)
            },
            onCancel: () => { }
        })
    }
    //富文本的值改變時(shí)觸發(fā)
    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
        })
    }
    //預(yù)覽
    preView = () => {
        this.props.form.validateFields((error, values) => {
            // if (!error) {
            this.setState({
                modalVisible: true,
                title: values.title,
                content: values.content.toHTML()
            })
            // }
        })

    }
    //關(guān)閉
    handleOk = () => {
        this.setState({
            modalVisible: false
        })
    }
    //發(fā)布
    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', '請(qǐng)輸入內(nèi)容')
                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: '確認(rèn)發(fā)布嗎?',
                    okText: '確定',
                    cancelText: '取消',
                    onOk: () => {
                        dispatch({
                            type: 'notice/publish',
                            payload: submitData,
                            callback: res => {
                                if (res.success) {
                                    this.openNotification('success', '發(fā)布成功')
                                    router.go(-1)
                                } else {
                                    this.openNotification('error', '發(fā)布失敗')

                                }
                            }
                        })
                    },
                    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
            // 文件上傳到服務(wù)端成功后獲取地址
            // 上傳成功后調(diào)用param.success并傳入上傳后的文件地址
            param.success({
                url,
                meta: {
                    id: 'xxx',
                    title: 'xxx',
                    alt: 'xxx',
                    loop: true, // 指定音視頻是否循環(huán)播放
                    autoPlay: true, // 指定音視頻是否自動(dòng)播放
                    controls: true, // 指定音視頻是否顯示控制欄
                    poster: 'http://xxx/xx.png', // 指定視頻播放器的封面
                }
            })
        }

        const progressFn = (event) => {
            // 上傳進(jìn)度發(fā)生變化時(shí)調(diào)用param.progress
            param.progress(event.loaded / event.total * 100)
        }

        const errorFn = (response) => {
            // 上傳發(fā)生錯(cuò)誤時(shí)調(diào)用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}>&lt; 公告管理</span>
                </div>
                <div className={styles.formBox}>
                    <Form onSubmit={this.handleSubmit} layout="horizontal" {...formItemLayout}>
                        <FormItem label="公告標(biāo)題" {...formItemLayout}>
                            {getFieldDecorator('title', {
                                rules: [{ required: true, message: '請(qǐng)輸入公告標(biāo)題' }, { message: '公告標(biāo)題不能輸入<或>', pattern: new RegExp('^[^<\|^>]+$', 'g') }, { message: '公告標(biāo)題不能超過(guò)30個(gè)字符', max: 30 }]
                            })(<Input placeholder="請(qǐng)輸入公告標(biāo)題" style={{ width: 300 }} />)}
                        </FormItem>
                        <FormItem {...formItemLayout} label="標(biāo)簽">
                            {getFieldDecorator('labelId')(
                                <Select
                                    showSearch
                                    style={{ width: 300 }}
                                    placeholder="請(qǐng)選擇標(biāo)簽"
                                    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="內(nèi)容">
                            {getFieldDecorator('content', {
                                rules: [{
                                    required: true,
                                    message: '請(qǐng)輸入正文內(nèi)容'
                                }],
                            })(<BraftEditor
                                ref={instance => this.editorInstance = instance}
                                className={styles.myEditor}
                                controls={controls}
                                onChange={this.handleChange}
                                forceNewLine={true}
                                placeholder="請(qǐng)輸入正文內(nèi)容"
                                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}>預(yù)覽</Button>
                                    <Button type="primary" htmlType="submit">發(fā)布</Button>
                                </Col>
                            </Row>
                        </FormItem>
                    </Form>
                </div>
                {modalVisible && <Modal
                    title="預(yù)覽"
                    visible={modalVisible}
                    maskClosable={false}
                    width={1000}
                    footer={[
                        <Button key="submit" type="primary" loading={loading} onClick={this.handleOk}>
                            關(guān)閉
            </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有錯(cuò)誤

最近接到一個(gè)需求,需要支持在文本輸入框支持圖片粘貼上傳,但是在我們這邊管理頁(yè)面,對(duì)于用戶提的一些問(wèn)題顯示又不支持 Matkdown。

所以選擇 braft-editor 來(lái)實(shí)現(xiàn),發(fā)現(xiàn)提供一些配置項(xiàng),因?yàn)槲疫@邊不需要那些加粗,下劃線等等按鈕,只需要上傳圖片,粘貼然后配合 COS 存鏈接就好了。

遇到的問(wèn)題

首先我這個(gè)是 React 項(xiàng)目,其它項(xiàng)目不太清楚,然后使用 yarn。

在 utils 官方倉(cāng)庫(kù)中,有相關(guān) issues,鏈接在下方:

引用 braft-utils 有錯(cuò)誤 #500

其中也有人提及了一些解決方案,但是并沒(méi)有解決問(wèn)題,一直報(bào)錯(cuò):

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';

看這個(gè)報(bào)錯(cuò)信息,有提示,用 npm 安裝那個(gè)依賴,我已經(jīng)試過(guò)了,并沒(méi)有效果,不存在那個(gè)依賴包。

解決方式

直接少?gòu)U話,以下是解決方式:

yarn add braft-finder
yarn add braft-utils
yarn add draft-js-multidecorators
yarn add draftjs-utils

然后在你當(dāng)前需要引入的文件那,同級(jí)目錄底下創(chuàng)建一個(gè)名為 xxx.d.ts 文件,放入以下定義:

declare module 'braft-utils';
declare module 'braft-finder';

弄完之后記得重新 yarn dev ,之后就會(huì)出現(xiàn)如下頁(yè)面,完美解決。

弄完這個(gè)問(wèn)題,還就那個(gè)焦頭爛額的,不過(guò)總算沒(méi)有 bug 了,在這里記錄一下,以免大家踩坑。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 深入學(xué)習(xí)TypeScript 、React、 Redux和Ant-Design的最佳實(shí)踐

    深入學(xué)習(xí)TypeScript 、React、 Redux和Ant-Design的最佳實(shí)踐

    這篇文章主要介紹了深入學(xué)習(xí)TypeScript 、React、 Redux和Ant-Design的最佳實(shí)踐,TypeScript 增加了代碼的可讀性和可維護(hù)性,擁有活躍的社區(qū),,需要的朋友可以參考下
    2019-06-06
  • useEffect?返回函數(shù)執(zhí)行過(guò)程源碼解析

    useEffect?返回函數(shù)執(zhí)行過(guò)程源碼解析

    這篇文章主要為大家介紹了useEffect?返回函數(shù)執(zhí)行過(guò)程源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • React和Vue的props驗(yàn)證示例詳解

    React和Vue的props驗(yàn)證示例詳解

    這篇文章主要介紹了React和Vue的props驗(yàn)證,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-08-08
  • React實(shí)現(xiàn)簡(jiǎn)單登錄的項(xiàng)目實(shí)踐

    React實(shí)現(xiàn)簡(jiǎn)單登錄的項(xiàng)目實(shí)踐

    登錄、注冊(cè)、找回密碼是前端項(xiàng)目經(jīng)常遇到的需求,本文主要介紹了React實(shí)現(xiàn)簡(jiǎn)單登錄的項(xiàng)目實(shí)踐,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • 詳解React 16 中的異常處理

    詳解React 16 中的異常處理

    這篇文章主要介紹了詳解React 16 中的異常處理的相關(guān)資料,React 16.x 版本中,引入了所謂 Error Boundary 的概念,從而保證了發(fā)生在 UI 層的錯(cuò)誤不會(huì)連鎖導(dǎo)致整個(gè)應(yīng)用程序崩潰;未被任何異常邊界捕獲的異??赡軙?huì)導(dǎo)致整個(gè) React 組件樹(shù)被卸載,需要的朋友可以參考下
    2017-07-07
  • react組件的創(chuàng)建與更新實(shí)現(xiàn)流程詳解

    react組件的創(chuàng)建與更新實(shí)現(xiàn)流程詳解

    React組件分為函數(shù)組件與class組件;函數(shù)組件是無(wú)狀態(tài)組件,class稱為類組件;函數(shù)組件只有props,沒(méi)有自己的私有數(shù)據(jù)和生命周期函數(shù);class組件有自己私有數(shù)據(jù)(this.state)和生命周期函數(shù)
    2022-10-10
  • React的Props、生命周期詳解

    React的Props、生命周期詳解

    “Props” 是 React 中用于傳遞數(shù)據(jù)給組件的一種機(jī)制,通常作為組件的參數(shù)進(jìn)行傳遞,在 React 中,props 是只讀的,意味著一旦將數(shù)據(jù)傳遞給組件的 props,組件就不能直接修改這些 props 的值,這篇文章主要介紹了React的Props、生命周期,需要的朋友可以參考下
    2024-06-06
  • React中mobx和redux的區(qū)別及說(shuō)明

    React中mobx和redux的區(qū)別及說(shuō)明

    這篇文章主要介紹了React中mobx和redux的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • react如何獲取URL中參數(shù)

    react如何獲取URL中參數(shù)

    這篇文章主要介紹了react如何獲取URL中參數(shù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 使用React Profiler進(jìn)行性能優(yōu)化方案詳解

    使用React Profiler進(jìn)行性能優(yōu)化方案詳解

    在現(xiàn)代前端開(kāi)發(fā)中,性能優(yōu)化是一個(gè)不可忽視的重要環(huán)節(jié),在 React 生態(tài)系統(tǒng)中,React Profiler 是一個(gè)強(qiáng)大的工具,下面我們來(lái)看看如何使用它來(lái)提升我們的 React 應(yīng)用吧
    2025-03-03

最新評(píng)論

朝阳区| 内江市| 垦利县| 华坪县| 瓦房店市| 信阳市| 南部县| 类乌齐县| 客服| 京山县| 古丈县| 瓦房店市| 德惠市| 朔州市| 盘锦市| 汕尾市| 赫章县| 余庆县| 宜州市| 冷水江市| 开鲁县| 威海市| 东宁县| 溧水县| 杭锦旗| 潼南县| 汶上县| 西乌珠穆沁旗| 海丰县| 维西| 嘉义市| 马关县| 孝昌县| 巴马| 浪卡子县| 湖口县| 遵化市| 嘉义市| 虎林市| 甘洛县| 莆田市|