zoukankan      html  css  js  c++  java
  • 实现一个简易的富文本编辑器(二):给富文本添加自定义事件

      为富文本添加一个提交按钮,点击按钮可以获取富文本内容。但是在提交前或者提交后我想做一些操作,比如内容校验内容清空等等。

      我们直接在该按钮上绑定点击事件同样可以达到目的,但是为了组件化,所以本例打算为提交按钮自定义beforeSubmit、afterSubmit两个事件。

    1.创建发布订阅者对象

      前文说到,事件系统是发布-订阅模式的一个实现,模式给事件发布函数与事件处理函数进行解耦,使得两者无直接调用关系。

      简易发布订阅者对象实现如下:

    var Event = {
    //    _cachePool : {}, 处理函数缓存池不要写在该对象内,因为原型链继承会让子类共享引用类型数据。
        fire : function(type, msg) {
            var fns;
            if(!(fns = this._cachePool[type])) {
                return;
            }
            var len = fns.length;
            for(var i = 0, fn; i < len; i++) {
                fn = fns[i];
                fn.call(this, msg);
            }
        },
        on : function(type, callback) {
            if(!this._cachePool[type]) {
                this._cachePool[type] = [];
            }
            this._cachePool[type].push(callback);
        },
        un : function(type, callback) {
            var fns = this._cachePool[type];
            if(fns) {
                this._cachePool[type] = fns.filter(function(item){//注意兼容,一些低版本Array没有过滤函数
                    return item !== callback;
                });
            }
        }
    };

      这里要去掉缓存池,因为这个对象将是编辑器原型中的一份子,我们希望每个编辑器都有自己一个私有的缓存池,以避免不同编辑器实例监听到相同的事件。

    2.编辑器样式

      本例编辑器给命令按钮设置图片样式,并且仅实现字体加粗功能:

    .editorOut {
        border:1px solid #ccc;
        width:200px;
        height:200px;
        position:relative;
    }
    .editorTool {
        margin:2px;
        width:100%;
    }
    .editorFoot {
        margin:2px;
        width:100%;
        position:absolute;
        bottom:0;
    }
    
    .editorOut button {
        height:20px;
        width:20px;
        margin:1px;
        border:0px solid #fff;
        cursor:pointer;
        overflow:hidden;
    }
    .editorOut button.bold{
        background:url(./imgs.svg) 0px 0px;
        background-size:140px 40px;
    }
    .editorOut button.bold:hover {
        background:url(./imgs.svg) 0px -20px;
        background-size:140px 40px;
    }

      注:SVG是绘制矢量图的标签(XML)语言,它的特点是不受像素影响。

    3.实现简易编辑器

      利用js脚本,动态创建编辑器。

      _create函数创建编辑器,它封装了创建编辑器命令块、底部块、输入域等创建的过程。

      _createEditor为创建编辑器输入域函数。

      _createTool为创建命令块函数。

      _createCommandBtn为创建调用编辑器命令的按钮的函数,本例只实现一个按钮。

      _createFoot创建底部块函数。

      _onbeforeSubmit为启动自定义事件beforesubmit的函数。

      _onaftersubmit为启动自定义事件aftersubmit的函数。

      _createPrintBtn为创建输出按钮的函数。本例两个自定义事件都在这里启动。

    EditorProto = {
        _create : function(id) {
            var editor = this._createEditor(id);
            var tool = this._createTool();
            var button = this._createCommandBtn();
            var foot = this._createFoot();
            var printBtn = this._createPrintBtn();
            this.printBtn = printBtn;
            tool.appendChild(button);
            foot.appendChild(printBtn);
            editor.insertBefore(tool, editor.firstChild);
            editor.appendChild(foot);
            return editor;
        },
        _createEditor : function(id) {
            var editor = document.getElementById(id);
            editor.className = "editorOut";
            editor.contentEditable = true;
            return editor;
        },
        _createTool : function() {
            var tool = document.createElement("div");
            tool.contentEditable = false;
            tool.className = "editorTool";
            return tool;
        },
        _createCommandBtn : function() {
            var button = document.createElement("button");
            button.className = "bold";
            button.title = "加粗";
            button.onclick = function(e) {
                document.execCommand("bold", false, null);
            };
            return button;
        },
        _createFoot : function() {
            var tool = document.createElement("div");
            tool.contentEditable = false;
            tool.className = "editorFoot";
            return tool;
        },
        _onbeforeSubmit : function(e, scope, callback) {
            scope.fire('beforesubmit', e);
        },
        _onaftersubmit : function(e, scope, callback) {
            scope.fire('aftersubmit', e);
        },
        _createPrintBtn : function() {
            var button = document.createElement("input"),
                that = this;
            button.type="button"
            button.value = "点击写出";
            button.onmousedown = function(e) {
                that._onbeforeSubmit(e, that);
            };
            button.onmouseup = function(e) {
                that._onaftersubmit(e, that);
            };
            return button;
        }
    };

    4.实现简易拷贝函数

      拷贝函数的作用是将Event对象与EditorProto对象糅合到一起。

    var copyIf = function(sub, sup, config) {
        for(var p in sup) {
            if(!sub[p]) {
                sub[p] = sup[p];//拷贝
            }
        }
    }

    5.编辑器组件化

      为了达到最终new一次创建一个实例的目的,我们需要将编辑器对象加工成构造函数。像ExtJS、JQuery、Mini UI等都有实现自己的extend函数,本例就不单独实现继承函数了。

    copyIf(EditorProto, Event);//将Event对象拷贝给EditorProto
    
    function Editor(id) {
        this._cachePool = {};//事件处理函数的缓存池不能放到原型里
        this._create(id);//new 操作构造器的时候,创建编辑器实例
    };
    Editor.prototype = EditorProto;//原型链继承

    6.验证beforesubmit与aftersubmit事件效果

      HTML里定义两个div,做为两个编辑器的容器。

    <div id="editor">print...</div>
    <div id="s"></div>

      JS里分别在HTML两个div内创建编辑器,并且第一个编辑器绑定两个自定义事件,第二个只绑定一个,测试效果。

    var editor = new Editor("editor");
    editor.on("beforesubmit", function() {console.log("beforesubmit");});
    editor.on("aftersubmit", function() {console.log("aftersubmit");});
    
    var s = new Editor("s");
    s.on("beforesubmit", function() {console.log("s的提交前事件");});

      点击第一个编辑器会打印出“beforesubmit”与“aftersubmit”;点击第二个编辑器打印出“s的提交前事件”。

      为编辑器创建自定义事件目的达成!

    敌人总是会在你最不想它出现的地方出现!
  • 相关阅读:
    Python3学习笔记22-文件读写
    Python3学习笔记21-实例属性和类属性
    Python3学习笔记20-获取对象信息
    Python3学习笔记19-继承和多态
    Python3学习笔记18-访问限制
    Python3学习笔记17-类与实例
    Python3学习笔记16-错误和异常
    Python3学习笔记15-迭代器与生成器
    Python3学习笔记14-迭代与列表生成式
    Python3学习笔记13-函数的参数
  • 原文地址:https://www.cnblogs.com/longhx/p/5445816.html
Copyright © 2011-2022 走看看