js 带表情的评论输入框问题

js 带表情的评论输入框问题

复制代码

<div class="comment_con clearfix">
    <div class="comment_input_box">
        <!-- div 模拟input输入框  -->
        <div type="text"  class="comment_input" contenteditable="true"  v-on:input="inputChange($event)" v-on:paste="inputPaste($event)" v-on:focus.stop="inputFocus($event)"></div>
        <!--表情按钮  -->
        <input type="button" class="emoji-wrap"  @click.stop="showEmijiBtn($event,1)" />
    </div>
    <span class="comment_btn" @click="sendComment($event)">评论</span>
    <!--表情弹窗  -->
    <div class="dynamic-emoji" v-show="isEmojiShow">
        <div id="emoji-box" class="emoji-box open">
            <span class="td-div"  v-for="(value,key) in arrEmojiList"  @click="selectEmoji($event,value,key)">
                <img class="emoji" :src="emoji_path+value" :title="key"/>
            </span> 
        </div>
    </div> 
</div>

 1.输入框粘贴处理

inputPaste: function(e) {
    var e = e || window.event;
    var clipboar = e.clipboardData || e.originalEvent.clipboardData;
    if (clipboar) {
        var text = clipboar.getData('Text');
        if (text.length > 140) {
            text = text.substr(0, 140);
            this.dialogShowFn(2, '粘贴内容过长,已截取前140字!');
        }
        String.insertAtCaret(this.curElementInput, text);
        e.preventDefault();
    }
},

2.控制字数 内部文字和表情个数

if (this.curElementInput.innerText.length + this.curElementInput.childElementCount > 140) {
    this.dialogShowFn(2, "评论内容不能超过140字");
    return false;
}

3.转换表情

readEmoji: function(message) {
    //替换信息中的 < & 空格
    var message = this.convertHtml(message, true);
    //如果有at信息,特殊显示
    //提取消息中的图片信息
    message = message.replace(/\[[^\[\]]+\]/g, function (v, i, s) { return this.arrEmojiList[v] ? ('<img class="emoji" src="' + this.emoji_path + this.arrEmojiList[v] + '">') : v }.bind(this));//新表情的解析
    return message;
}, 

4.特殊字符转换

convertHtml: function(msg, flag) {
    msg = msg + ""; //如果是数字,转为字符串
    if (flag) {
        msg = msg.replace(/&/g, '&amp;').replace(/\s/g, '&nbsp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
    } else {
        msg = msg.replace(/&gt;/g, '>').replace(/&lt;/g, '<').replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&');
    }
    return msg;
},

5.设置光标位置

setFocus: function(el) {
    var range = document.createRange();
  

},

6.插入字符串

// 字符串解析为DOM对象
function loadXMLString(str) {
    var div = document.createElement("div");
    if(typeof str == "string") div.innerHTML = str;
    return div.childNodes;
};

// 插入字符串DOM
function insertAtCaret(id, val) {
    //光标位置  光标在表情前面--上一个文本的结尾   光标在表情后面--输入框子节点的序号
    var selection = window.getSelection && window.getSelection();
    var anchorNode = selection.anchorNode;
    var anchorOffset = selection.anchorOffset;
    //输入框
    // var pn = document.getElementById(id);
    var pn = id;
    //选区
    var ran = selection.getRangeAt(0);
    //插入的表情
    var imgNode = loadXMLString(val)[0];
    if (anchorNode.nodeType == 3) {
        //文本中插入
        // if (selection.anchorOffset == anchorNode.nodeValue.length){
        //     //在文本结尾
        //     pn.insertBefore(imgNode ,anchorNode.nextElementSibling);
        // } else 
        if (selection.anchorOffset == 0){
            //在文本开头
            pn.insertBefore(imgNode ,anchorNode);
        } else {
            //在文本中
            //拆分后半部分文本并插入
            var n2 = document.createTextNode(anchorNode.nodeValue.substring(selection.anchorOffset));
            pn.replaceChild(n2, anchorNode);
            //在后半部分文本前插入表情
            imgNode = pn.insertBefore(imgNode, n2);
            //插入前半部分文本
            if(anchorOffset){
                var n1 = document.createTextNode(anchorNode.nodeValue.substring(0, anchorOffset));
                pn.insertBefore(n1, imgNode);
            }
        }
    }else if(anchorNode.nodeType == 1){
        //输入框子节点插入
        //在选中节点的后面一个节点,在它之前插入
        pn.insertBefore(imgNode, pn.childNodes[anchorOffset]);
    }
    //结尾表情被隐藏处理176
    if (imgNode.offsetLeft - pn.scrollLeft > 176){
        pn.scrollLeft = imgNode.offsetLeft - 176;
    }
    //设置焦点
    ran = ran.cloneRange();
    ran.setStartAfter(imgNode);
    selection.removeAllRanges();
    selection.addRange(ran);
    pn.focus();
};

转自https://www.cnblogs.com/yuesu/p/9408582.html

div 模拟输入框

div 模拟输入框

1.默认分享文案:发现一个好玩的歌房,快来一起玩吧~   ,获取鼠标时,默认文案消失

  利用 empty,focus,before 伪元素解决,模拟placeholder

<div class="editBox" contenteditable="true" placeholder="发现一个好玩的歌房,快来一起玩吧~"></div>
.editBox:empty:before{
      content: attr(placeholder);
      color:#999;
}
.editBox:focus:before{
     content:none;
}

2.最多输入140个汉字 ,已输入文字数量随输入实时变化。超出140汉字时,不能输入进去 

问题:

1.输入框粘贴,去掉格式,截取字数

2.超过140字时,再次输入,光标总是默认在最前面,需要记录光标的位置

        // 获取输入框内容,先记录光标的位置,截取140字后,重新设置光标位置
        inputChange(e) {
            this.cursorPos=this.getCursorPosition(e.currentTarget);
            if(e.currentTarget.innerText.length > 140){
                this.shareTipFn(1,"内容不能超过140字");
                e.currentTarget.innerText=e.currentTarget.innerText.substr(0,140);
                this.setCursorPosition(e.currentTarget,Math.min(this.cursorPos,140));
            }
            this.content=e.currentTarget.innerText;
            this.curTextLen=this.content.length;
        },
        // 输入框粘贴处理
        inputPaste(e) {
            e.preventDefault();
            var clipboar = e.clipboardData || e.originalEvent.clipboardData;
            if (clipboar) {
                var text = clipboar.getData('Text');
                String.insertAtCaret(e.currentTarget, text);
                this.inputChange(e);
            }
        },
        //获取当前光标位置
        getCursorPosition (element) {
            var caretOffset = 0;
            var doc = element.ownerDocument || element.document;
            var win = doc.defaultView || doc.parentWindow;
            var sel = win.getSelection();
            if (sel.rangeCount > 0) {//选中的区域
                var range = win.getSelection().getRangeAt(0);//获取指定的选中区域
                var preCaretRange = range.cloneRange();//克隆一个选中区域
                preCaretRange.selectNodeContents(element);//设置选中区域的节点内容为当前节点
                preCaretRange.setEnd(range.endContainer, range.endOffset);  //重置选中区域的结束位置
                caretOffset = preCaretRange.toString().length;
            }
            console.log(caretOffset,sel.focusOffset);
            return caretOffset;
        },
        // 设置光标位置
        setCursorPosition(element, pos){
            var range = document.createRange();//创建一个选中区域
            range.selectNodeContents(element);//选中节点的内容
            if(element.innerHTML.length > 0) {
                range.setStart(element.childNodes[0], pos); //设置光标起始为指定位置
            }
            range.collapse(true);       //设置选中区域为一个点
            var selection = window.getSelection();//获取当前选中区域
            selection.removeAllRanges();//移出所有的选中范围
            selection.addRange(range);//添加新建的范围
           
        },

3.点击分享,

1.设置flag标记,防止频繁点击

2.判断有无网

div 模拟输入框,支持输入表情

1.html结构

    <div id="app" v-clock @click="emojiClose">
        <div class="editBox" >
            <div class="edit" contenteditable="true" placeholder="发现一个好玩的歌房,快来一起玩吧~"  v-on:input="inputChange($event)" v-on:keydown="inputkeydown($event)" v-on:paste="inputPaste($event)" ></div>
            <div class="editBottom">
                <img class="emojiImg" src="../images/emoji-icon.png" @click.stop="emojiBtn"/>
                <div class="textLen"><span class="curLen">{{curTextLen}}</span>/140</div>
            </div>
            <!--表情框  -->
            <div class="emojiBox" v-show="isEmojiShow">
                <div class="emojiList">
                    <span class="emojiImg" v-for="(value,key) in arrEmojiList" :title="key" @click.stop="selectEmoji($event,value,key)">
                        <img :src="emoji_path+value">
                    </span>
                </div>
            </div> 
        </div>
        <div class="shareBtn" :class="flag?'shareBtnRed':'shareBtnGray'" @click="shareFn">分享</div> 
        <!--分享提示 弹层  -->
        <div class="tipBox" v-show="shareTip.isShow">
            <div class="tipImg" :class="shareTip.type==0?'success':'warn'"></div>
            <span>{{shareTip.text}}</span>
        </div>
    </div>

2.默认分享文案:发现一个好玩的歌房,快来一起玩吧~ , 获取鼠标时,默认文案消失

  

.edit:empty:before{
    content: attr(placeholder);
    color:#999;
}
.edit:focus:before{
    content:none;
}

2.最多输入140个汉字,支持输入表情

  屏蔽回车,粘贴处理,表情处理

        // 屏蔽回车
        inputkeydown(event){
            if (window.event && window.event.keyCode == 13) {
                event.cancelBubble=true;
                event.preventDefault();
                event.stopPropagation();
                // this.shareFn();
            }
        },
        // 获取输入框内容
        inputChange(e) {
            let curTarget=document.getElementsByClassName('edit')[0];
            this.getCursorPosition();
            if(curTarget.innerText.length + curTarget.childElementCount > 140){
                this.shareTipFn(1,"内容不能超过140字");
                // 图片:移除最后一个元素   文字
                if((/<[a-z|/]+>$/).test(curTarget.innerHTML)){
                    curTarget.removeChild(curTarget.lastElementChild);
                }else{
                    let imgArr=curTarget.innerHTML.match(/<img.*?data-id="(.*?)"\/?>/ig)||[];
                    let imgLen = imgArr.join('').length-imgArr.length;
                    // curTarget.innerHTML=curTarget.innerHTML.substr(0,140+imgLen);
                    curTarget.innerHTML=curTarget.innerHTML.substr(0,curTarget.innerHTML.length-(curTarget.innerText.length + curTarget.childElementCount-140));
                    
                }
                this.setCursorPosition(curTarget);
                
            }
            
            this.curTextLen=curTarget.innerText.length + curTarget.childElementCount;
            this.content=curTarget.innerHTML;
        },
        // 输入框处理
        inputPaste(e) {
            e.preventDefault();
            var clipboar = e.clipboardData || e.originalEvent.clipboardData;
            if (clipboar) {
                var text = clipboar.getData('Text');
                String.insertAtCaret(e.currentTarget, text.replace(/\s/g,''));
                this.inputChange(e);
            }
        },
        //获取当前光标位置
        getCursorPosition () {
            var section = window.getSelection();
            this.sectionObj.anchorNode = section.anchorNode;
            this.sectionObj.anchorOffset =section.anchorOffset;
            
        },
        // 设置光标位置
        setCursorPosition(element){
            var range = document.createRange();
            if(this.sectionObj.anchorNode.nodeType == 1){
                //焦点在图片
                range.setStart(element,Math.min(this.sectionObj.anchorOffset,element.childNodes.length));
            }else{
                //焦点在文本
                let node=this.sectionObj.anchorNode;
                // for(let i=0;i<element.childNodes.length;i++){
                //     if((element.childNodes[i].data&&node.data==element.childNodes[i].data)||i==element.childNodes.length-1){
                //          range.setStart(element.childNodes[i],Math.min(this.sectionObj.anchorOffset,element.childNodes[i].length));
                //          break;
                //     }
                // }
                range.setStart(node,Math.min(this.sectionObj.anchorOffset,node.length));
            }
            range.collapse(true); //设置选中区域为一个点
            var selection = window.getSelection();//获取当前选中区域
            selection.removeAllRanges();//移出所有的选中范围
            selection.addRange(range);//添加新建的范围
         
           
        },
       // 选择表情
        selectEmoji(e,value,key) {
            let curElement=document.getElementsByClassName('edit')[0];
            curElement.focus();
            let str = '<img class="emojiImg" src="' +this.emoji_path+value + '" data-id="' + key + '"\/>';
            if(e.target.nodeName == 'IMG') {
                String.insertAtCaret(curElement,str);
                this.inputChange(e);
            }
            this.isEmojiShow=false;
        },
        // 表情按钮 显示 隐藏
        emojiBtn(){
          this.isEmojiShow=!this.isEmojiShow;  
        },

复制代码

4.分享操作

分享内容:对表情,特殊字符处理

点击分享:防止频繁点击操作,判断有无网

// 分享
shareFn(){
    if(!this.flag) return;
    this.flag=false;
    // 处理表情图片
    this.content=this.content.replace(/<img.*?data-id="(.*?)"\/?>/ig, '$1');
    this.content=this.convertHtml(this.content,false);
    var params={
        userID: this.userID,
        toUserID:this.toUserID,
        objectID:this.objectID,
        content:this.content||this.shareDefaultText,
        type: this.type
    }
    params=encodeURIComponent(JSON.stringify(params));
    axios.get('https://music.51vv.com/sod?parameter='+params)
    .then(res=>{
        if(res.data.retCode==1000){
            this.shareTipFn(0,'分享成功!');
        }else{
            this.flag=true;
            this.shareTipFn(1,'分享失败!请稍后重试');
        }
    })
    .catch(error=>{
        console.log(error);
        this.flag=true;
        this.shareTipFn(1,'分享失败!请稍后重试');
    });
},
// 特殊字符转换
convertHtml:function(msg,flag) {
    msg = msg+""; //如果是数字,转为字符串
    if (flag) {
        msg = msg.replace(/&/g,'&amp;').replace(/\s/g,'&nbsp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
    } else {
        msg = msg.replace(/&gt;/g,'>').replace(/&lt;/g,'<').replace(/&nbsp;/g,' ').replace(/&amp;/g,'&');
    }
    return msg;
},

 转自https://www.cnblogs.com/yuesu/p/9796724.html

发布了39 篇原创文章 · 获赞 63 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/qq_31967569/article/details/103984856