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的提交前事件”。

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

    敌人总是会在你最不想它出现的地方出现!
  • 相关阅读:
    PythonのTkinter基本原理
    使用 Word (VBA) 分割长图到多页
    如何使用 Shebang Line (Python 虚拟环境)
    将常用的 VBScript 脚本放到任务栏 (Pin VBScript to Taskbar)
    关于 VBScript 中的 CreateObject
    Windows Scripting Host (WSH) 是什么?
    Component Object Model (COM) 是什么?
    IOS 打开中文 html 文件,显示乱码的问题
    科技发展时间线(Technology Timeline)
    列置换密码
  • 原文地址:https://www.cnblogs.com/longhx/p/5445816.html
Copyright © 2011-2022 走看看