閒暇之餘,用於加深自己對基礎的瞭解,徒手擼了一個留言板:輸入框。廢話少說,進入正題。簡陋的效果如下(下載程式碼):
一、定義需求
- 可輸入文字,以及插入表情。
- 相容性:IE與標準瀏覽器
二、詳細設計
根據需求,我們大致可以想到如下問題:
- 相容性的處理
- 事件繫結的相容性
- 可編輯輸入框的表情插入相容性
- 獲取資料的相容性
- 三個模組
- 留言板與ui互動的模組
- 表情展示模組
- 可編輯輸入框的操作模組 因此我規劃瞭如下的類結構:
- 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值的。
相容性有以下幾個點:
- 事件的繫結:attacheEvent和addEventListener。
- classList在ie8-不支援的問題,暫時選擇的用setAttribute代替
- 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('##'); }
主要內容:
- range(選區):IE與標準瀏覽器的相容性,值得注意的IE操控選區時,需要讓被操控元素(也就是選區所在的元素)獲取焦點,否則會失敗。
- 標準瀏覽器range的APi可參考此地址:http://www.w3school.com.cn/xmldom/dom_range.asp
- 獲取數(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>