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

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

一、定义需求

  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>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏极客猴

分享一个爬取网站的小技巧

有时候,我们很想爬取一个网站的数据。如果 PC 端的网页的反爬机制太强,我们可以换个思路。现在很多网站为了满足手机浏览器能正常访问的需求,都会推出手机版的网页。...

84120
来自专栏大前端开发

5个最优秀的微信小程序UI组件库

开发微信小程序的过程中,选择一款好用的组件库,可以达到事半功倍的效果。自从微信小程序面世以来,不断有一些开源组件库出来,下面5款就是排名比较靠前,用户使用量与关...

3.7K50
来自专栏司想君

手拉手,用Vue开发动态刷新Echarts组件

92380
来自专栏DeveWork

解决iOS 版Safari 中浮动(float)导致页面右侧偏移的bug

长时间没写CSS代码就是生疏了啊!昨天在用ipad 调试最新的主题的时候遇到了一个坑,现在写在这里记录下——iOS 版Safari 中浮动(float)导致页面...

22460
来自专栏web编程技术分享

【php增删改查实例】第二十六节 - 个人详情页制作

22370
来自专栏phodal

单页面应用后台渲染的三次实践

或许这是一个好的主题,又或许这不是一个好的主题。但是至少我可以Share一下我的经验: 基于Mustache模板引擎的前后台渲染。 基于PreRender方式的...

31990
来自专栏沈唁志

WordPress网站的SEO基础

30320
来自专栏Jerry的SAP技术分享

推荐一个yaml文件转json文件的在线工具

YAML的全称是YAML Ain’t Markup Language,是一种简洁的非标记语言,以数据为中心,使用空白,缩进,和分行组织数据,从而使得表示更加简洁...

21210
来自专栏一“技”之长

iOS开发之BusinessChat框架使用 原

      BusinessChat是iOS11.3后引入的新框架,这个框架配合iMessage应用将商家与用户更加紧密的结合起来,并且为商家提供了另外一种非常...

23520
来自专栏移动开发之家

移动端跨平台开发的深度解析

 跨平台一直是老生常谈的话题,cordova、ionic、react-native、weex、kotlin-native、flutter等跨平台框架的百花齐放,...

15640

扫码关注云+社区

领取腾讯云代金券