本身寫的一個簡單的編輯器 尚在簡潔 具體功能 加粗 斜體 下劃線 連接地址 顏色字體大小 粘貼圖片 excel 截屏 拖拽 上傳 功能都有 默認值 是否顯示工具欄 是否可編輯 測試經過能實現軟件開發大部分需求 可本身繼續添加其餘需求 html
樣子:react
部分代碼:antd
/** * Created by zhanglei on 2017/5/23. */import React, { Component } from 'react';import { Modal,message } from 'antd';import PropTypes from 'prop-types';import './edit.less'import ToolBar from './toolBar'export default class Editor extends Component { static propTypes = { className: PropTypes.string, value:PropTypes.string, editColor:PropTypes.string, }; constructor(props){ super(props); this.state={ value:null, tableData:[], linkModel:false, visible:false, isColor:false, editValue:'', myDisabled:false, isEdit:true, isFace:false, isBackground:false, linkValue:null, isSent:true, } }; componentDidMount(){ document.addEventListener('click',this.documentClick); }; moveToEnd = () =>{ const range = window.getSelection(); range.selectAllChildren(this.refs['inputText']); range.collapseToEnd(); }; documentClick=(e)=>{ const { isColor, isBackground } = this.state; if(isColor||isBackground){ let en = e.srcElement||e.target; const name = '.color-content'; while(en){ if(en.className&&en.className === name.replace('.','')){ return; } en = en.parentNode; } this.setState({ isColor:false, isBackground:false }); } }; componentWillUnmount(){ document.removeEventListener('click',this.documentClick) } onPaste=(e)=>{ let cbd = e.clipboardData; if ( !(e.clipboardData && e.clipboardData.items) ) { return ; } this.onParseOrDrop(cbd,e); }; onDrop=(e)=>{ e.preventDefault(); let cbd = e.dataTransfer; if ( !(e.dataTransfer && e.dataTransfer.items) ) { return ; } this.onParseOrDrop(cbd,e); }; onParseOrDrop = (cbd,e) =>{ let ua = window.navigator.userAgent; if(cbd.items && cbd.items.length === 2 && cbd.items[0].kind === "string" && cbd.items[1].kind === "file" && cbd.types && cbd.types.length === 2 && cbd.types[0] === "text/plain" && cbd.types[1] === "Files" && ua.match(/Macintosh/i) && Number(ua.match(/Chrome\/(\d{2})/i)[1]) < 49){ return; } if(cbd.items&&cbd.items.length === 4){ document.createElement('table'); return false; } const myArray = Object.keys(cbd.items).map(item=>{ return cbd.items[item]; }); const arr = myArray.some((u)=>{ if(u.kind === 'file'&&u.type!=='image/jpeg'&&u.type!=='image/png'){ message.error('僅支持PNG或者JPG的圖片格式上傳'); return !1 } return u.kind === 'file'&&(u.type==='image/jpeg'||u.type==='image/png') }); if(!arr) return !1; myArray.forEach(item=>{ if(item.kind === 'string'){ e.preventDefault(); return; } if(item.kind === "file"){ e.preventDefault(); const blob = item.getAsFile(); if (blob.size === 0) return; this.bind_parse(blob); } }) }; bind_parse = (file) =>{ const reader = new FileReader(); reader.onload = ((e)=>{ const newImg = `<img class="edit-img" title='點擊放大' src="${ e.target.result}"/>`; const {onChange} = this.props; if(onChange){ onChange( this.inputText.innerHTML+newImg ); } }); reader.readAsDataURL(file); }; textHtml=(e)=>{ e.preventDefault(); const {isEdit} = this.state; let html =null; if(isEdit){ html = this.refs['inputText'].innerHTML; this.refs['inputText2'].value = html; this.setState({ isEdit:false, myDisabled:true }); }else{ html = this.refs['inputText2'].value; this.refs['inputText'].innerHTML = html; this.setState({ isEdit:true, myDisabled:false }); } }; emitChange = (e) => { const { onChange } = this.props; const html = e.target.innerHTML; if (onChange && html !== this.lastHtml) { onChange(html) } this.lastHtml = html; }; shouldComponentUpdate(nextProps,nextState){ return nextProps.value !== this.props.value|| this.state.editValue !== nextState.editValue|| this.state.visible !== nextState.visible|| this.state.myDisabled !== nextState.myDisabled; } render() { const { isEdit, visible, myDisabled } = this.state; const { disabled, editColor } = this.props; const isDisabled = !('disabled' in this.props) || !disabled; return ( <div className="editor-full"> { isDisabled && <ToolBar id={ this.props.id } myDisabled={ myDisabled } bind_parse={(this.bind_parse)} textHtml={(this.textHtml)} /> } <div className="inputText" style={{ borderColor:editColor }}> <div className="input-content-edit" onPaste={ this.onPaste } onDrop={ this.onDrop } onInput={this.emitChange} contentEditable={ isDisabled } onBlur={ this.emitChange } dangerouslySetInnerHTML={{ __html:this.props.value }} onClick={e =>{ if(e.target.title === '點擊放大'){ this.setState({ url:e.target.src, visible:true }) } }} ref={ref =>this.inputText = ref} style={{ display:isEdit ? 'block' : 'none', height:isDisabled ? '200px' : 'auto' }}> </div> <textarea style={{ display:isEdit ? 'none' : 'block' }} ref="inputText2" id="editor-con"/> </div> <Modal className="chat-model" style={{ width:'70%' }} visible={ visible } footer={ null } onCancel={() =>this.setState({ visible:false })} > <img src={this.state.url} alt="img"/> </Modal> </div> ); }}