手写 editor web 富文本编辑器

手写富文本编辑器,需要使用 react 中自带的 FragmentcreateRef,以及 execCommand 方法,这两个到底有什么作用呢。那么,在演示代码前先了解下 FragmentcreateRefexecCommand 是什么,分别有什么作用?

Fragment

React 中一个常见模式是 一个组件返回多个元素。Fragment 相当于一个 React 组件,它可以聚合一个子元素列表,并且不在 DOM 中增加额外节点。在 react 中返回的元素必须有父元素进行包裹,但特殊情况下,我们不想使用多余的标签,此时可以使用 Fragment 包裹标签。Fragment 更像是一个空的 jsx 标签 <>

class FragmentDemo extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            list: [
                {
                    type: '姓名',
                    text: 'wqjiao'
                },
                {
                    type: '性别',
                    text: '女'
                }
            ]
        }
    }

    render () {
        let { list } = this.state;

        return (
            
                        { list && list.map(item => {
                            return (
                                
                                    
                            )
                        }) }
                    
{ item.type } { item.text }
) } }

其中,key 是唯一可以传递给 Fragment 的属性。

createRef

在 React 官网中是这么解释 Refs and the DOM

Refs are created using React.createRef() and attached to React elements via the ref attribute. 
Refs are commonly assigned to an instance property when a component is constructed so they can
be referenced throughout the component.

使用 React.createRef() 创建 refs,通过 ref 属性来获得 React 元素。当构造组件时,refs 通常被赋值给实例的一个属性,这样你可以在组件中任意一处使用它们。通过 current 属性取得 DOM 节点

execCommand

当一个 HTML 文档切换到设计模式时,document 暴露 execCommand 方法,该方法允许运行命令来操纵可编辑内容区域的元素。

大多数命令影响 document 的 selection(粗体,斜体等),当其他命令插入新元素(添加链接)或影响整行(缩进)。当使用 contentEditable 时,调用 execCommand() 将影响当前活动的可编辑元素。

但是 document.execCommand(xxxx) 是 IE 独家提供的,有些功能在 Chrome/FrieFox 中是不支持的,比如 粘贴功能 document.execCommand("paste", "false", null)

富文本编辑器

在了解以上两个 React 属性之后,附上手写 editor web 富文本编辑器的 js 代码

  • js 代码
import React, { Component, Fragment, createRef } from "react";
import { Select } from 'antd';
import './index.less';

const Option = Select.Option;

class WqjiaoEditor extends Component {
    
    constructor(props) {
        super(props);
        this.state = {
            editorIcons: [{
                id: 'choose-all',
                text: '全选',
                event: this.chooseAll
            }, {
                id: 'copy',
                text: '复制',
                event: this.copy
            }, {
                id: 'cut',
                text: '剪切',
                event: this.cut
            }, {
                id: 'bold',
                text: '加粗',
                event: this.bold
            }, {
                id: 'italic',
                text: '斜体',
                event: this.italic
            }, {
                id: 'font-size',
                text: '字体大小',
                event: this.fontSize
            }, {
                id: 'underline',
                text: '下划线',
                event: this.underline
            }, {
                id: 'background-color',
                text: '背景色',
                event: this.backgroundColor
            }],
            fontSizeOption: [],
            isShow: false,
            fontSize: '7'
        }
    }

    document = createRef(null);

    componentDidMount() {
        this.editor = this.document.current.contentDocument;
        this.editor.designMode = 'On';
        this.editor.contentEditable = true;

        let fontSizeOption = [];
        // 字体大小数组
        for (let i = 1; i <= 7; i ++) {
            fontSizeOption.push(i);                                                
        }

        this.setState({
            fontSizeOption
        });
    }

    // 全选
    chooseAll = () => {
        this.editor.execCommand('selectAll');
    }

    // 复制
    copy = () => {
        this.editor.execCommand('copy');
    }

    // 剪切
    cut = () => {
        this.editor.execCommand('cut');
    }

    // 加粗
    bold = () => {
        this.editor.execCommand('bold');
    }

    // 斜体
    italic = () => {
        this.editor.execCommand('italic');
    }

    // 字体大小
    fontSize = () => {
        let me = this;     
    }

    onClick(id) {
        if (id === 'font-size') {
            this.setState({
                isShow: true
            });
        }
    }

    onChange(value) {
        this.setState({
            fontSize: value,
            isShow: false
        })
        this.editor.execCommand('fontSize', true, value);
    }

    // 下划线
    underline = () => {
        this.editor.execCommand('underline');
    }

    // 背景色
    backgroundColor = () => {
        this.editor.execCommand('backColor', true, '#e5e5e5');
    }

    render() {
        let me = this;
        let { editorIcons, isShow, fontSize, fontSizeOption } = me.state;

        return (
            
                
    { editorIcons && editorIcons.map((item, index) => { return (
  • { (item.id === 'font-size' && isShow) &&
    }
  • ); }) }
) } } export default WqjiaoEditor;
  • css 样式,图片本地添加
// wqjiao editor web 富文本编辑器
::-webkit-scrollbar {
    display: none;
}

.wqjiao-editor {
    // width: 100%;
    width: 300px;
    
    // 样式重置
    * {
        margin: 0;
        padding: 0;
        list-style: none;
        font-style: normal;
    }

    // editor 图标
    .wqjiao-editor-icon {
        width: 100%;
        border: 1px solid #e5e5e5;
        border-top-left-radius: 4px;
        border-top-right-radius: 4px;
        box-sizing: border-box;
        .wqjiao-icon-list {
            padding: 0 5px;
        }
        .wqjiao-icon-item {
            float: left;
            font-size: 10px;
            padding: 5px 10px;
            position: relative;
        }
        .wqjiao-editor-select {
            position: absolute;
            top: 20px;
            left: -3px;
            width: 40px;
        }
        .ant-select {
            width: 100%;
        }
        .ant-select-selection__rendered,
        .ant-select-selection--single {
            height: 20px;
            line-height: 20px;
        }
        .ant-select-arrow {
            top: 4px;
            right: 4px;
        }
        .ant-select-selection-selected-value {
            padding: 0;
        }
        .ant-select-selection__rendered {
            margin: 0;
            margin-left: 4px;
        }
    }

    // editor 文本区域
    .wqjiao-editor-textarea {
        width: 100%;
        min-height: 200px;
        font-size: 14px;
        padding: 10px;
        border: 1px solid #e5e5e5;
        border-top: none;
        border-bottom-left-radius: 4px;
        border-bottom-right-radius: 4px;
        box-sizing: border-box;
        &:hover,
        &:focus {
            outline: none;
            box-shadow: none;
        }
    }

    // 清除浮动元素带来的影响
    .clearfix {
        zoom: 1;
    }
    .clearfix:after {
        content: "";
        clear: both;
        height: 0;
        visibility: hidden;
        display: block;
    }

    // 图标背景
    .wqjiao-i {
        display: block;
        width: 14px;
        height: 14px;
        cursor: pointer;
        &.i-choose-all {
           background: url('./img/i-choose-all.png');
        }
        &.i-copy {
           background: url('./img/i-copy.png'); 
        }
        &.i-cut {
           background: url('./img/i-cut.png'); 
        }
        &.i-bold {
            background: url('./img/i-bold.png'); 
        }
        &.i-italic {
            background: url('./img/i-italic.png'); 
        }
        &.i-font-size {
            background: url('./img/i-font-size.png'); 
        }
        &.i-underline {
            background: url('./img/i-underline.png'); 
        }
        &.i-background-color {
            background: url('./img/i-background-color.png'); 
        }
        &:hover,
        &.active {
            &.i-choose-all {
                background: url('./img/i-choose-all-active.png');
            }
            &.i-copy {
                background: url('./img/i-copy-active.png'); 
            }
            &.i-cut {
                background: url('./img/i-cut-active.png'); 
            }
            &.i-bold {
                background: url('./img/i-bold-active.png'); 
            }
            &.i-italic {
                background: url('./img/i-italic-active.png'); 
            }
            &.i-font-size {
                background: url('./img/i-font-size-active.png'); 
            }
            &.i-underline {
                background: url('./img/i-underline-active.png'); 
            }
            &.i-background-color {
                background: url('./img/i-background-color-active.png'); 
            }
        }
    }
}
  • 效果演示
  • execCommand 兼容性

你可能感兴趣的:(react.js,javascript)