• 【留言板】可编辑输入框操作总结


    闲暇之余,用于加深自己对基础的了解,徒手撸了一个留言板:输入框。废话少说,进入正题。简陋的效果如下(下载代码):

    一、定义需求

    1. 可输入文本,以及插入表情。
    2. 兼容性:IE与标准浏览器

    二、详细设计

    根据需求,我们大致可以想到如下问题:

    1. 兼容性的处理
      1. 事件绑定的兼容性
      2. 可编辑输入框的表情插入兼容性
      3. 获取数据的兼容性
    2. 三个模块
      1. 留言板与ui交互的模块
      2. 表情展示模块
      3. 可编辑输入框的操作模块 因此我规划了如下的类结构:

    • LeaveMsg:实现UI与留言板的交互
    • FaceWrap:实现表情殂的管理,以及相应事件的响应,如显示/隐藏,获取表情,初始化表情列表等。
    • SelectionUitls:实现可编辑输入框的操作,如:插入一个表情、获取数据等。 各模块的兼容性在以下细节中进行介绍。

    三、代码实现

    1. FaceWrap类(表情列表管理类)

    var FaceWrap = function(head, cont, opts){
        this.$head = head;
        this.$cont = cont;
        this.data = ['one', 'two', 'thr'];
        var self = this;
        var toggle = false;
        this.onClickHandHandle = function(evt){
            if(!toggle){
                self.$cont.style.display = 'block';
                toggle = true;
            }else{
                self.$cont.style.display = 'none';
                toggle = false;
            }
            if(opts.onClickHandHandle){
                opts.onClickHandHandle(toggle);
            }
        }
        this.onChooseImg = opts. onChooseImg || function(){}
        this.generalFaceImg();
        this.bind();
    }
    var facePt = FaceWrap.prototype;
    facePt.generalFaceImg = function(){
        var fragment = document.createDocumentFragment();
        for( var index =0; index < this.data.length; ++index){
            var data = this.data[index];
            var img = document.createElement('img');
            img.setAttribute('src', '../img/face/' + data + '.jpg');
            img.setAttribute('data-id', data);
            img.setAttribute('class','face-img');
            fragment.appendChild(img);
        }
        this.$cont.appendChild(fragment);
    }
    facePt.bind = function(){  
        if(document.attachEvent){
            this.$head.attachEvent('onclick',this.onClickHandHandle);
            this.$cont.attachEvent('onclick',this.onChooseImg);
        }else{       
            this.$head.addEventListener('click',this.onClickHandHandle);
            this.$cont.addEventListener('click',this.onChooseImg);
        }
    }
    facePt.hide = function(){
        this.onClickHandHandle();
    }

    需要注意的点:

         1. 在初始化表情列表(generalFaceImg)的时候,用到了Fragment(文档碎片)来提高性能;

         2. 在class中设元素的display为none后,用js是获取不到此元素的display值的。

    兼容性有以下几个点:

    1. 事件的绑定:attacheEvent和addEventListener。
    2. classList在ie8-不支持的问题,暂时选择的用setAttribute代替
    3. appendChild全都支持,append在chrome中支持,但ie不支持

    2. SelectionUitls类(可编辑输入框管理类)

    var SelectionUitls = function(dom){
        this.dom = dom;
        this.cursorIndex;
    }
    var pt = SelectionUitls.prototype;
    pt.insertDomForStandard = function(dom){
        var sel = window.getSelection(); //获取选区集合
        var range = sel.getRangeAt(0); //获取第一个选择
        range.deleteContents(); //删除选区选重的元素
        range.insertNode(dom); //插入元素在选区的首位置
        range = range.cloneRange(); //克隆一个选区
        range.setStartAfter(dom); //设置选区起点光标位置在指定元素的后面
        range.collapse(true);//合并起点、终点光标
        sel.removeAllRanges();//移除所有选区
        sel.addRange(range); //添加一个选区
    }
    pt.insertDomForIe = function(dom){
        this.dom.focus();
        var wrap = document.createElement('div');
        wrap.appendChild(dom);
    
        document.selection.createRange().pasteHTML(wrap.innerHTML);
    }
    pt.insertDom = function(dom){
        //光标处插入非元素
        if(window.getSelection){
            this.insertDomForStandard(dom);
        }else{
            this.insertDomForIe(dom);
        }
    }
    pt.getContent = function(){
        //获取数据
        var nodes = this.dom.childNodes;
        var datas = [];
        for(var index = 0; index < nodes.length; index ++){
            var node = nodes[index];
            if(node.nodeType == 3){
                datas.push(node.textContent || node.nodeValue || node.data);
            }else{
                datas.push(node.getAttribute('data-id'));
            }
        }
        return datas.join('##');
    }

    主要内容:

    1. range(选区):IE与标准浏览器的兼容性,值得注意的IE操控选区时,需要让被操控元素(也就是选区所在的元素)获取焦点,否则会失败。
    2. 标准浏览器range的APi可参考此地址:http://www.w3school.com.cn/xmldom/dom_range.asp
    3. 获取数(getContent):将html结构的数据转换为标准的数据,防止脚本攻击。

    3. LeaveMsg类(留言板管理类)

    var LeaveMsg = function(opts){
        this.opts = opts;
        this.createFaceWrap();
        this.createUitls();
        this.curLocation;
    }
    var leaveMsgPt = LeaveMsg.prototype;
    leaveMsgPt._insertFace = function(id){
        var img = document.createElement('img');
        img.setAttribute('class','face-img');
        img.setAttribute('data-id', id);
        img.src= '../img/face/' + id + '.jpg';
        this.selectionUitls.insertDom(img);
        this.faceWrap.hide();
    }
    leaveMsgPt.createFaceWrap = function(){
        var self = this;
        var faceOpt = {
            onChooseImg:function(evt){
                //插入表情,获取位置,获取表情,插入表情
                var id = (evt.target||evt.srcElement).getAttribute('data-id');
                self._insertFace(id);
            }
        }
        this.faceWrap = new FaceWrap(this.opts.faceHead, this.opts.faceCont, faceOpt);
    }
    leaveMsgPt.createUitls = function(){
        this.selectionUitls = new SelectionUitls(this.opts.area);
    }
    leaveMsgPt.getContent = function(evt){
        this.selectionUitls.getContent();
    }

    实现FaceWrap、SelectionUitls类与LeaveMsg类的组合,并对UI提供相就的API。

    四、使用他们

    js部分代码

    var leaveMsgArea = document.getElementById('leaveMsgArea');
    var faceHead = document.getElementById('head');
    var faceCont = document.getElementById('cont');
    
    
    var leaveMsg = new LeaveMsg({
        area: leaveMsgArea,
        faceHead: faceHead,
        faceCont: faceCont
    });

    HTML部分代码

    <div class="leaveMsgArea" contenteditable="true" id="leaveMsgArea">
    </div>
    <div class="face-wrap">
        <a class="face-head" id="head" href="javascript:void(0)">表情</a>
        <div class="face-cont" id="cont">
    
        </div>
    </div>
    <div class="button-group">
        <button type="button" onclick="leaveMsg.getContent(event)" >获取内容</button>
    </div>
  • 相关阅读:
    docker镜像管理基础
    docker的基础应用
    mysql基础
    策略模式
    简单工厂模式
    hystrix-go简介
    手把手带你使用 go-kit(option)
    手把手带你使用 go-kit(组件扩充,服务发现)
    手把手带你使用 go-kit(客户端直连)
    手把手带你使用 go-kit(基础篇)
  • 原文地址:https://www.cnblogs.com/cqhaibin/p/6753211.html
Copyright © 2020-2023  润新知