This week, I made a PC service background requirement, requiring a rich text editor, inserting pictures, tables, font size background color, etc.,
Finally introduced the rich text editor TinyMCE
For the introduction of TinyMCE:
TinyMCE is an easy-to-use and powerful WYSIWYG rich text editor. Similar programs include: UEditor, Kinditor, Simditor, CKEditor, wangEditor, Suneditor, froala, etc.
The advantages of TinyMCE:
- Open source and commercially available, based on LGPL2.1
- Rich plug-ins, the built-in plug-ins basically cover the functions required daily
- Rich interfaces, strong scalability, and the ability to expand functions indefinitely
- The interface looks good, in line with modern aesthetics
- Provide three modes: classic, inline, and immersive without interference
- Excellent support for standards (since v5)
- Multi-language support, the official website can download dozens of languages.
The picture above is the content of the rich text editor configured in the demand. My demand TinyMCE can be fully satisfied.
TinyMCE official website: www.tiny.cloud
TinyMCE supports vue, react, angular
This modified project uses react,
Encapsulated a rich text editing component suitable for us in the demand:
The contents of the editor component:
import React from 'react'; import './Editor.scss'; import {isDev, nginxPrefix} from '@/config'; import {Upload, Button, Icon, Popconfirm, Spin, message} from 'antd'; import _get from 'lodash/get'; import _uniqueId from 'lodash/uniqueId'; import PropTypes from 'prop-types'; * @ props object uploadConfig? Custom upload configuration * @props function onAdd? add event * @props function onDelete? delete event * @props boolen disabled? disabled * @props string defaultContent? initial content * @props number height? height * @props string id? identifier/ * * @event function getEditorContent Get edit content * @event function setEditorContent Set edit content * @event function insertContent Insert edit content * / class Editor extends React.Component { constructor (props) { super (props); const tinymceId = `editor-tinymce -$ { this .props.id}-$ {_ uniqueId ()}-$ { new Date (). getTime ()} `; this .state = { // Editor ID tinymceId, // Editor instance editor: null }; } componentDidMount () { const {height= 300, defaultContent = ''} = this.props; window.tinymce.init({ selector: `#${this.state.tinymceId}`, language: 'zh_CN', height: height, min_height: 200, width: '100%', resize: true, default_link_target: '_blank', init_instance_callback: editor => { if (defaultContent) { editor.setContent(defaultContent); } }, paste_enable_default_filters: true, // paste_word_valid_elements: () => { // // }, // 插件配置 plugins: 'table image lists link paste', // 菜单配置 menubar: 'file edit view insert format', // 工具栏配置 /* eslint-disable */ toolbar: 'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | outdent indent | blockquote | table | image link | forecolor backcolor | bullist numlist | removeformat' /*eslint-enable* / }). then (([editor]) => this .setState ({editor})); } componentWillUnmount () { // In some life cycles, the instance is not generated and there is no unmount method. (Component mounting phase) // if (this.state.editor! == null) { // this.state.editor.destroy (); // } window.tinymce.get ( this .state.tinymceId) .destroy (); } getEditorContent = () => { return this .state.editor.getContent (); } setEditorContent = (content) => { window.tinymce.get ( this.state.tinymceId).setContent(content); } insertContent = (content) => { try { this.state.editor.insertContent(content); } catch(e) { window.tinymce.get(this.state.tinymceId).insertContent(content); } } // 默认上传配置 uploadConfig = { name: 'file', action: (isDev ? '' : nginxPrefix) + '/admin/common/uploadFile', headers: { authorization: 'authorization-text', }, onChange: (info) => { if (info.file.status === 'done' ) { message.success ( 'Image upload successful' ); this .state.editor.insertContent ( ` <img src =" $ {_ get (info, 'file.response.data.result')} "> ` ); } else if (info.file.status === 'error' ) { message.error ( 'Image upload failed' ); } }, accept: '.jpg, .jpeg, .jpe, .png, .bmp' } render() { const {uploadConfig} = this.props; return ( <Spin spinning={this.props.disabled} indicator={<Icon type="stop" style={{color: '#555'}} />}> <div className="editor-container"> <textarea id={this.state.tinymceId} /> <div className="btn-bar"> <Upload {...(uploadConfig ? uploadConfig : this.uploadConfig)}> <Button><Icon type="upload" />添加本地图片</Button> </Upload> <span> { this.props.onAdd && <Button icon="plus" shape="circle" onClick={this.props.onAdd} /> } { this.props.onDelete && <Popconfirm title="无法撤回,确认删除?" onConfirm={this.props.onDelete} okText="确认" cancelText="cancel" placement = "leftBottom" > < Button type = "danger" icon = "delete" shape = "circle" style = {{marginLeft: '4px' }} onClick = {() => { // When rich text editor When there is no content, the delete button does not pop up,Directly call the delete method const content = this.getEditorContent(); if (!content) { this.props.onDelete(); } }} /> </Popconfirm> } </span> </div> </div> </Spin> ); } } Editor.defaultProps = { id: 'no-props-id', height: 300, defaultContent: '', onDelete: null, onAdd: null, disabled: false, uploadConfig: null }; Editor.propTypes = { id: PropTypes.string, height: PropTypes.number, defaultContent: PropTypes.string, onDelete: PropTypes.func, onAdd: PropTypes.func, disabled: PropTypes.bool }; export default Editor;
The component finally submits a piece of HTML, the picture is just a URL, the size is very small, very practical
In this demand, the rich text edit box is a case entry,
Of course, there is a display when you enter it, and it is also very simple for the display. A picture enlargement function is added to the display place
There is a problem when displaying, that is, the size of the picture we want to control is very small, so that the entire content can be seen, and the specific content of the picture can be clicked to enlarge
Come and show me the handsome picture after clicking the picture of my male god: