【问题标题】:Jquery focus cursor after adding emoji添加表情符号后的Jquery焦点光标
【发布时间】:2019-03-18 06:31:23
【问题描述】:

我正在尝试在 contenteditable div 中添加一个简单的表情符号。但是添加表情符号光标后我遇到了问题。我从 codepen.io 创建了这个 DEMO 。在此演示中,您可以看到有一个树示例表情符号。当您单击第一个表情符号时,表情符号将添加到 #text contenteditable div。到目前为止一切正常,但在添加表情符号后,它仍保留在光标表情符号后面。

添加表情符号后,我希望你在光标前面的表情符号。我怎样才能做到这一点 ?任何人都可以在这里帮助我吗?

$(document).ready(function() {
  $("body").on("paste", "#text", function(e) {
    e.preventDefault();
  });
  $("body").on("keydown", "#text", function(event) {
    //$('.character').text($(this).text().length);
    if ($(this).text().length === 200 && event.keyCode != 8) {
      event.preventDefault();
    }
  });
  // Click to show clicked smiley
  $("body").on("click",".emoji-box", function(){
      var emojiKey = $(this).attr("data-smiley");
      var emojiURL = $(this).attr("data-url"); 
      $("#text").append("<img src="+emojiURL+" class='app-moji'>"); 
      $("#text").focus();
  });
});
html, body {
    width: 100%;
    height: 100%;
    padding: 0px;
    margin: 0px;
    font-family: 'Helvetica Neue', helvetica, arial, sans-serif;
    -moz-osx-font-smoothing: grayscale;
    -webkit-font-smoothing: antialiased;
    -ms-text-size-adjust: 100%;
    -webkit-texts-size-adjust: 100%;
    -webkit-backface-visibility: hidden;
}
.container {
  position:relative;
  width:100%;
  max-width:500px;
  margin:0px auto;
  padding-top:100px;
}
.input {
  position:relative;
  width:100%;
  display:inline-block;
  padding:5px 0px;
}
#text {
  width:100%;
  outline:none;
  border:1px solid #d8dbdf;
  padding:15px;
  border-radius:3px;
  -webkit-border-radius:3px;
  font-weight:300;
  font-size:14px;
  color:#444;  
  line-height: 17px;
  word-wrap: break-word; 
  text-align: left !important;
   
}
#text img { 
  width:25px;
  height:25px;
  vertical-align: middle; 
}
.app-moji {
  margin-left:5px;
  margin-right:5px;
  display: inline-block;
}
[contenteditable=true]:empty:before {
  content: attr(placeholder);
  display: block; /* For Firefox */
  color:#d8dbdf;
}
.button {
  float:right;
  width:100px;
  padding:8px;
  text-align:center;
  background-color:#d8dbdf;
  border-raduis:3px;
  -webkit-border-radius:3px;
  cursor:pointer;
   transition: background-color 1s linear;
    -moz-transition: background-color 1s linear;
    -o-transition: background-color 1s linear;
    -webkit-transition: background-color 1s linear;
}
.button:hover {
  background-color:#000;
  color:#fff;
     
}
div.coloranimation {
  transition: background-color 1s linear;
    -moz-transition: background-color 1s linear;
    -o-transition: background-color 1s linear;
    -webkit-transition: background-color 1s linear;
  background-color:#000000;
}

.ornekgoster {
  position:relative;
  width:100%;
  padding:10px;
}
.ornek {
  position:relative;
  width:100%;
  font-weight:300;
  font-size:13px;
  color:#444;
} 

*{
  box-sizing:border-box;
  -webkit-box-sizing:border-box;
}

.ap-emoji {
  position: relative;
  float: left;
  width: 100%;
  padding-right: 10px;
   overflow:hidden;
 margin-top:20px;
}

.emoji-box {
   position:relative;
   width:29px;
   height:29px;
   float:left;  
   padding:2px;
   cursor:pointer;
}
.emoji-box img {
   width:100%;
   position:relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
  <div class="input">
    <div id="text" placeholder="Wite something..." contenteditable="true"></div>
    <input type="hidden" id="hidden" value=""/>
  </div> 
  
  <div class="ap-emoji" id="emoji1">
    <div class="emoji-box" data-smiley=":P" data-url="https://cdn.shopify.com/s/files/1/1061/1924/products/Hungry_Emoji_Icon_c20f1808-f3e2-4051-8941-3d157764e8cb.png"><img src="https://cdn.shopify.com/s/files/1/1061/1924/products/Hungry_Emoji_Icon_c20f1808-f3e2-4051-8941-3d157764e8cb.png"></div>
     <div class="emoji-box" data-smiley=":D" data-url="http://www.bigmouthdesign.co.uk/wp-content/uploads/2017/08/Happy-Face.png"><img src="http://www.bigmouthdesign.co.uk/wp-content/uploads/2017/08/Happy-Face.png"></div>
     <div class="emoji-box" data-smiley="<3" data-url="http://clipart.info/images/ccovers/1496184263Heart-Eyes-Emoji-png-transparent-2.png"><img src="http://clipart.info/images/ccovers/1496184263Heart-Eyes-Emoji-png-transparent-2.png"></div>
    </div>
</div>

【问题讨论】:

    标签: javascript jquery html css


    【解决方案1】:

    使用Selection对象如下

    $(document).ready(function() {
      $("body").on("paste", "#text", function(e) {
        e.preventDefault();
      });
      $("body").on("keydown", "#text", function(event) {
        //$('.character').text($(this).text().length);
        if ($(this).text().length === 200 && event.keyCode != 8) {
          event.preventDefault();
        }
      });
      // Click to show clicked smiley
      $("body").on("click", ".emoji-box", function() {
        var emojiKey = $(this).attr("data-smiley");
        var emojiURL = $(this).attr("data-url");
        $("#text").append("<img src=" + emojiURL + " class='app-moji'>");
        $("#text").focus();
        var el = document.getElementById("text");
        placeCaretAtEnd(el);
    
      });
    });
    
    function placeCaretAtEnd(el) {
      el.focus();
      if (typeof window.getSelection != "undefined" &&
        typeof document.createRange != "undefined") {
        var range = document.createRange();
        range.selectNodeContents(el);
        range.collapse(false);
        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
      } else if (typeof document.body.createTextRange != "undefined") {
        var textRange = document.body.createTextRange();
        textRange.moveToElementText(el);
        textRange.collapse(false);
        textRange.select();
      }
    }
    html,
    body {
      width: 100%;
      height: 100%;
      padding: 0px;
      margin: 0px;
      font-family: 'Helvetica Neue', helvetica, arial, sans-serif;
      -moz-osx-font-smoothing: grayscale;
      -webkit-font-smoothing: antialiased;
      -ms-text-size-adjust: 100%;
      -webkit-texts-size-adjust: 100%;
      -webkit-backface-visibility: hidden;
    }
    
    .container {
      position: relative;
      width: 100%;
      max-width: 500px;
      margin: 0px auto;
      padding-top: 100px;
    }
    
    .input {
      position: relative;
      width: 100%;
      display: inline-block;
      padding: 5px 0px;
    }
    
    #text {
      width: 100%;
      outline: none;
      border: 1px solid #d8dbdf;
      padding: 15px;
      border-radius: 3px;
      -webkit-border-radius: 3px;
      font-weight: 300;
      font-size: 14px;
      color: #444;
      line-height: 17px;
      word-wrap: break-word;
      text-align: left !important;
    }
    
    #text img {
      width: 25px;
      height: 25px;
      vertical-align: middle;
    }
    
    .app-moji {
      margin-left: 5px;
      margin-right: 5px;
      display: inline-block;
    }
    
    [contenteditable=true]:empty:before {
      content: attr(placeholder);
      display: block;
      /* For Firefox */
      color: #d8dbdf;
    }
    
    .button {
      float: right;
      width: 100px;
      padding: 8px;
      text-align: center;
      background-color: #d8dbdf;
      border-raduis: 3px;
      -webkit-border-radius: 3px;
      cursor: pointer;
      transition: background-color 1s linear;
      -moz-transition: background-color 1s linear;
      -o-transition: background-color 1s linear;
      -webkit-transition: background-color 1s linear;
    }
    
    .button:hover {
      background-color: #000;
      color: #fff;
    }
    
    div.coloranimation {
      transition: background-color 1s linear;
      -moz-transition: background-color 1s linear;
      -o-transition: background-color 1s linear;
      -webkit-transition: background-color 1s linear;
      background-color: #000000;
    }
    
    .ornekgoster {
      position: relative;
      width: 100%;
      padding: 10px;
    }
    
    .ornek {
      position: relative;
      width: 100%;
      font-weight: 300;
      font-size: 13px;
      color: #444;
    }
    
    * {
      box-sizing: border-box;
      -webkit-box-sizing: border-box;
    }
    
    .ap-emoji {
      position: relative;
      float: left;
      width: 100%;
      padding-right: 10px;
      overflow: hidden;
      margin-top: 20px;
    }
    
    .emoji-box {
      position: relative;
      width: 29px;
      height: 29px;
      float: left;
      padding: 2px;
      cursor: pointer;
    }
    
    .emoji-box img {
      width: 100%;
      position: relative;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div class="container">
      <div class="input">
        <div id="text" placeholder="Wite something..." contenteditable="true"></div>
        <input type="hidden" id="hidden" value="" id="txt" />
      </div>
    
      <div class="ap-emoji" id="emoji1">
        <div class="emoji-box" data-smiley=":P" data-url="https://cdn.shopify.com/s/files/1/1061/1924/products/Hungry_Emoji_Icon_c20f1808-f3e2-4051-8941-3d157764e8cb.png"><img src="https://cdn.shopify.com/s/files/1/1061/1924/products/Hungry_Emoji_Icon_c20f1808-f3e2-4051-8941-3d157764e8cb.png"></div>
        <div class="emoji-box" data-smiley=":D" data-url="http://www.bigmouthdesign.co.uk/wp-content/uploads/2017/08/Happy-Face.png"><img src="http://www.bigmouthdesign.co.uk/wp-content/uploads/2017/08/Happy-Face.png"></div>
        <div class="emoji-box" data-smiley="<3" data-url="http://clipart.info/images/ccovers/1496184263Heart-Eyes-Emoji-png-transparent-2.png"><img src="http://clipart.info/images/ccovers/1496184263Heart-Eyes-Emoji-png-transparent-2.png"></div>
      </div>
    </div>

    【讨论】:

    • 感谢您的回答。但是您的答案中缺少一些东西。光标在表情符号的前面,但例如:如果我写了这个Hi how are you ?,然后点击Hi,如果我点击表情符号,表情符号应该在你好(这里)之后,但它在文本结尾之后。
    【解决方案2】:

    实际上,您想要的是 更新的插入符号位置后插入/删除。 您还必须考虑到用户可以自己更新插入的表情符号之间的任何位置的插入符号位置。 更好的解决方案是在给定的插入符号位置插入 HTML

    这也适用于粘贴 HTML 内容。只需从 body 上的粘贴侦听器中删除您的 event.preventDefault()

    对于 contentEditable 代码,您应该参考 stackoverflow 上 TimDown 给出的解决方案。他是一些评价最高的解决方案。 ContentEditable 很容易变得复杂。我相信您的要求不会到此结束。 如果可能,请尝试使用一个好的标准库,这将为您节省大量时间和精力。

    参考下面的sn-p,希望对你有帮助。

    $(document).ready(function() {
      $("body").on("paste", "#text", function(e) {
        e.preventDefault();
      });
      $("body").on("keydown", "#text", function(event) {
        //$('.character').text($(this).text().length);
        if ($(this).text().length === 200 && event.keyCode != 8) {
          event.preventDefault();
        }
      });
      // Click to show clicked smiley
      $("body").on("click",".emoji-box", function(){
          var emojiKey = $(this).attr("data-smiley");
          var emojiURL = $(this).attr("data-url"); 
          //$("#text").append("<img src="+emojiURL+" class='app-moji'>"); 
          //$("#text").focus();
          insertHTMLAtCaret("<img src="+emojiURL+" class='app-moji'>")
      });
      
      function insertHTMLAtCaret(html) {
        var sel, range;
        if (window.getSelection) {
            // IE9 and non-IE
            sel = window.getSelection();
            if (sel.getRangeAt && sel.rangeCount) {
                range = sel.getRangeAt(0);
                range.deleteContents();
    
                // Range.createContextualFragment() would be useful here but is
                // non-standard and not supported in all browsers (IE9, for one)
                var el = document.createElement("div");
                el.innerHTML = html;
                var frag = document.createDocumentFragment(), node, lastNode;
                while ( (node = el.firstChild) ) {
                    lastNode = frag.appendChild(node);
                }
                range.insertNode(frag);
                
                // Preserve the selection
                if (lastNode) {
                    range = range.cloneRange();
                    range.setStartAfter(lastNode);
                    range.collapse(true);
                    sel.removeAllRanges();
                    sel.addRange(range);
                }
            }
        } else if (document.selection && document.selection.type != "Control") {
            // IE < 9
            document.selection.createRange().pasteHTML(html);
        }
      }
    });
    html, body {
        width: 100%;
        height: 100%;
        padding: 0px;
        margin: 0px;
        font-family: 'Helvetica Neue', helvetica, arial, sans-serif;
        -moz-osx-font-smoothing: grayscale;
        -webkit-font-smoothing: antialiased;
        -ms-text-size-adjust: 100%;
        -webkit-texts-size-adjust: 100%;
        -webkit-backface-visibility: hidden;
    }
    .container {
      position:relative;
      width:100%;
      max-width:500px;
      margin:0px auto;
      padding-top:100px;
    }
    .input {
      position:relative;
      width:100%;
      display:inline-block;
      padding:5px 0px;
    }
    #text {
      width:100%;
      outline:none;
      border:1px solid #d8dbdf;
      padding:15px;
      border-radius:3px;
      -webkit-border-radius:3px;
      font-weight:300;
      font-size:14px;
      color:#444;  
      line-height: 17px;
      word-wrap: break-word; 
      text-align: left !important;
       
    }
    #text img { 
      width:25px;
      height:25px;
      vertical-align: middle; 
    }
    .app-moji {
      margin-left:5px;
      margin-right:5px;
      display: inline-block;
    }
    [contenteditable=true]:empty:before {
      content: attr(placeholder);
      display: block; /* For Firefox */
      color:#d8dbdf;
    }
    .button {
      float:right;
      width:100px;
      padding:8px;
      text-align:center;
      background-color:#d8dbdf;
      border-raduis:3px;
      -webkit-border-radius:3px;
      cursor:pointer;
       transition: background-color 1s linear;
        -moz-transition: background-color 1s linear;
        -o-transition: background-color 1s linear;
        -webkit-transition: background-color 1s linear;
    }
    .button:hover {
      background-color:#000;
      color:#fff;
         
    }
    div.coloranimation {
      transition: background-color 1s linear;
        -moz-transition: background-color 1s linear;
        -o-transition: background-color 1s linear;
        -webkit-transition: background-color 1s linear;
      background-color:#000000;
    }
    
    .ornekgoster {
      position:relative;
      width:100%;
      padding:10px;
    }
    .ornek {
      position:relative;
      width:100%;
      font-weight:300;
      font-size:13px;
      color:#444;
    } 
    
    *{
      box-sizing:border-box;
      -webkit-box-sizing:border-box;
    }
    
    .ap-emoji {
      position: relative;
      float: left;
      width: 100%;
      padding-right: 10px;
       overflow:hidden;
     margin-top:20px;
    }
    
    .emoji-box {
       position:relative;
       width:29px;
       height:29px;
       float:left;  
       padding:2px;
       cursor:pointer;
    }
    .emoji-box img {
       width:100%;
       position:relative;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div class="container">
      <div class="input">
        <div id="text" placeholder="Wite something..." contenteditable="true"></div>
        <input type="hidden" id="hidden" value=""/>
      </div> 
      
      <div class="ap-emoji" id="emoji1">
        <div class="emoji-box" data-smiley=":P" data-url="https://cdn.shopify.com/s/files/1/1061/1924/products/Hungry_Emoji_Icon_c20f1808-f3e2-4051-8941-3d157764e8cb.png"><img src="https://cdn.shopify.com/s/files/1/1061/1924/products/Hungry_Emoji_Icon_c20f1808-f3e2-4051-8941-3d157764e8cb.png"></div>
         <div class="emoji-box" data-smiley=":D" data-url="http://www.bigmouthdesign.co.uk/wp-content/uploads/2017/08/Happy-Face.png"><img src="http://www.bigmouthdesign.co.uk/wp-content/uploads/2017/08/Happy-Face.png"></div>
         <div class="emoji-box" data-smiley="<3" data-url="http://clipart.info/images/ccovers/1496184263Heart-Eyes-Emoji-png-transparent-2.png"><img src="http://clipart.info/images/ccovers/1496184263Heart-Eyes-Emoji-png-transparent-2.png"></div>
        </div>
    </div>

    【讨论】:

      【解决方案3】:

      execCommand()

      对于易于绑定到按钮并定位插入符号位置或选定区域的文本编辑器功能,请使用execCommand()

      以下演示:

      回调函数可以在插入符号处插入或用一些选择的表情符号、粗体和斜体文本覆盖选定区域。 emoji unicode 是十进制格式:

      &amp;#代码;

      这种格式将直接呈现为 HTML。更多表情符号,请参考amp-what.com


      演示

      const edit = document.forms.editor;
      
      const editText = event => {
        const evt = event.type;
        const tgt = event.target;
        const cur = event.currentTarget;
        const ui = cur.elements;
      
        if (evt === 'click') {
          switch (tgt.id) {
            case 'emoji':
              let icon = ui.picto.value;
              document.execCommand('insertHTML', false, icon);
              break;
            case 'bold':
              document.execCommand('bold', false, null);
              break;
            case 'italic':
              document.execCommand('italic', false, null);
              break;
            default:
              break;
          }
        }
      };
      
      edit.onclick = editText;
      button,
      select {
        display: inline-block;
        font: inherit;
        width: 5ch;
        height: 3ex;
        cursor: pointer;
        text-align: center;
        padding: 0 5px;
        line-height: 3ex;
        vertical-align: middle;
      }
      
      select {
        width: 6ch;
      }
      <!DOCTYPE html>
      <html>
      
      <head>
        <meta charset='utf-8'>
        <style>
          html,
          body {
            font: 400 16px/1.3 Helvetica, sans-serif;
            color: #333;
          }
          
          #text {
            outline: none;
            margin: 10px;
            min-height: 200px;
          }
        </style>
      </head>
      
      <body>
        <form id='editor'>
          <fieldset id="text" contentEditable="true"></fieldset>
          <fieldset id='panel'>
            <button id='bold'><b>B</b></button>
            <button id='italic'><i>I</i></button>
            <select id='picto'>
              <option value='&#11088;'>&#11088;</option>
              <option value='&#127921;'>&#127921;</option>
              <option value='&#128128;'>&#128128;</option>
              <option value='&#128163;'>&#128163;</option>
              <option value='&#129302;'>&#129302;</option>
            </select>
            <button id='emoji' type='button'>&#11088;</button>
          </fieldset>
        </form>
        <script>
          <!--JavaScript goes here-->
        </script>
      </body>
      
      </html>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-18
        • 2019-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-15
        • 2016-02-29
        相关资源
        最近更新 更多