如何使用 jQuery 拖放与段落元素

Posted

技术标签:

【中文标题】如何使用 jQuery 拖放与段落元素【英文标题】:How to use jQuery drag and drop with paragraph element 【发布时间】:2020-01-31 00:03:21 【问题描述】:

我需要使用JQuery UI 创建一个可自定义的段落。

这是我的代码。

$(document).ready(function() 
  var given = $("p.given").text();

  var new_given = given.replace(/blank/g, '  <div class="blanks"></div>  ');
  $("p.given").html(new_given);

  function updateDroppables() 
    $("div.blanks").droppable(
      accept: "span.given",
      classes: 
        "ui-droppable-hover": "ui-state-hover"
      ,
      drop: function(event, ui) 
        var dragedElement = ui.draggable.text();
        var dropped = ui.draggable;
        console.log(dropped);
        dropped.hide();
        console.log(dragedElement);
        $(this).replaceWith(
          " <span class='answers'><b class='blue-text' rel='" +
          ui.draggable.attr("rel") +
          "'>" +
          dragedElement +
          "</b> <a href='#' class='material-icons cancel md-16'>highlight_off</a></span> "
        );
      
    );
  

  updateDroppables();

  $("span.given").draggable(
    helper: "clone",
    revert: "invalid"
  );

  $(document).on("click", "a.cancel", function(e) 
    e.preventDefault();
    var rel = $(this).prev().attr('rel');
    console.log(rel);

    $(this)
      .parent()
      .replaceWith("<div class='blanks'></div>");
    updateDroppables();
    $('.btn-flat[rel=' + rel + ']').show();
  );
);
div.blanks 
  display: inline-block;
  min-width: 50px;
  border-bottom: 2px solid #000000;
  color: #000000;


div.blanks.ui-droppable-active 
  min-height: 20px;


span.answers>b 
  border-bottom: 2px solid #000000;


span.given 
  margin: 5px;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<p><b><i>In the text below some words are missing. Drag words from the box below to the appropriate place in the text. To undo an answer choice, drag the word back to the box below the text.</i></b></p>

<div class="row">
  <p class="given">
    He wants to get a better [blank] and earn more money. Managers set objectives, and decide [blank] their organization can achieve them. A defect can be caused [blank] negligen ce by one of the members of a team.
  </p>
</div>

<div class="divider"></div>
<br>
<div class="section">
  <section>
    <div class="card blue-grey ">
      <div class="card-content white-text">
        <div class="row">
          <div class="col s12">

            <span class="given btn-flat white-text red lighten-1" rel="1">the Santee, thDakota</span>
            <span class="given btn-flat white-text red lighten-1" rel="2">America</span>

            <span class="given btn-flat white-text red lighten-1" rel="3">Qatar</span>

            <span class="given btn-flat white-text red lighten-1" rel="4">Philippines</span>

          </div>
        </div>
      </div>
    </div>
  </section>
</div>

这可行,但问题是在上面的代码中,可拖动组件只能添加到[blank] 区域。我需要在段落&lt;p&gt; 的任何地方添加可拖动组件我该怎么做?我是code pen sample,你可以玩看看上面的代码是如何工作的

简单我把上面的代码改成如下,

$("p.given").droppable(
  accept: "span.given",
  classes: 
    "ui-droppable-hover": "ui-state-hover"
  

但它将整个段落&lt;p&gt; 替换为拖动的组件。如何将可拖动组件添加到段落&lt;p&gt;标签的任何位置。

【问题讨论】:

只是澄清一下:您希望能够将可拖动的内容作为新段落插入到原始文本中的任何其他 2 个段落之间? 不请自来的迂腐:我们不使用 javascript 操作 标签。我们使用元素。在您的情况下,它是一个段落元素。标签就是在标记中定义元素的方式。 这里的主要问题是 Droppable 需要绑定到一个元素。这就是为什么它适用于空白而不适用于段落中的其他单词的原因。 [blank] 模板被替换为空的 &lt;span&gt; 元素,然后它是可放置的。您需要将用户添加的文本转换为元素,很可能&lt;span&gt; 然后可以成为可放置的目标。当用户将一个单词拖到 droppable 上时,它可以在目标之后追加新单词。 @LePhil 不,先生,我只需要将可拖动的内容拖放到段落的任何位置(原始文本)。简单地说我的要求和代码笔的例子一样。问题是它唯一的拖累[blank] 区域。我需要删除段落的任何地方 【参考方案1】:

由于您要完成的事情很多,因此您需要准备很多东西。这是一个非常粗略的例子。

$(function() 
  function textWrapper(str, sp) 
    if (sp == undefined) 
      sp = [
        0,
        0
      ];
    
    var txt = "<span class='w'>" + str + "</span>";
    if (sp[0]) 
      txt = "&nbsp;" + txt;
    
    if (sp[1]) 
      txt = txt + "&nbsp;";
    
    return txt;
  

  function chunkWords(p) 
    var words = p.split(" ");
    words[0] = textWrapper(words[0], [0, 1]);
    var i;
    for (i = 1; i < words.length; i++) 
      if (words[0].indexOf(".")) 
        words[i] = textWrapper(words[i], [1, 0]);
       else 
        words[i] = textWrapper(words[i], [1, 1]);
      
    
    return words.join("");
  

  function makeBtn(tObj) 
    var btn = $("<span>", 
      class: "ui-icon ui-icon-close"
    ).appendTo(tObj);
    btn.click(function(e) 
      $(this).parent().remove();
    );
  

  function makeDropText(obj) 
    return obj.droppable(
      drop: function(e, ui) 
        var txt = ui.draggable.text();
        var newSpan = textWrapper(txt, [1, 0]);
        $(this).after(newSpan);
        makeBtn($(this).next("span.w"));
        makeDropText($(this).next("span.w"));
        $("span.w.ui-state-highlight").removeClass("ui-state-highlight");
      ,
      over: function(e, ui) 
        $(this).add($(this).next("span.w")).addClass("ui-state-highlight");
      ,
      out: function() 
        $(this).add($(this).next("span.w")).removeClass("ui-state-highlight");
      
    );
  

  $("p.given").html(chunkWords($("p.given").text()));

  $("span.given").draggable(
    helper: "clone",
    revert: "invalid"
  );

  makeDropText($("p.given span.w"));
);
p.given 
  display: flex;
  flex-wrap: wrap;


p.given span.w span.ui-icon 
  cursor: pointer;


div.blanks 
  display: inline-block;
  min-width: 50px;
  border-bottom: 2px solid #000000;
  color: #000000;


div.blanks.ui-droppable-active 
  min-height: 20px;


span.answers>b 
  border-bottom: 2px solid #000000;


span.given 
  margin: 5px;
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class="row">
  <p class="given" contenteditable="true">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
</div>

<div class="divider"></div>
<div class="section">
  <section>
    <div class="card blue-grey ">
      <div class="card-content white-text">
        <div class="row">
          <div class="col s12">
            <span class="given btn-flat white-text red lighten-1" rel="1">the Santee, thDakota</span>
            <span class="given btn-flat white-text red lighten-1" rel="2">America</span>
            <span class="given btn-flat white-text red lighten-1" rel="3">Qatar</span>
            <span class="given btn-flat white-text red lighten-1" rel="4">Philippines</span>
          </div>
        </div>
      </div>
    </div>
  </section>
</div>

这将获取&lt;p&gt; 中的当前文本,并使用无分隔空格来包装每个单词。它试图遵守句子语法。

现在每个单词都被包装了,我们可以让每个单词都可以放置。这假设一个单词将放在前面的单词上,并突出显示它会放在中间的两个单词。删除后,将创建一个新的 &lt;span&gt; 并将其附加到目标之后。我添加了一个“x”按钮来删除它。

【讨论】:

非常感谢,但问题是当我尝试将可放置组件作为段落的第一个单词删除时,我无法做到这一点,您能否建议我一个解决方案来对其进行排序, 无论如何非常感谢您一直以来的支持 另一个问题是当我通过键入来编辑文本时。假设我输入了两个词,我不能在这两个词之间删除可放置组件。新输入的两个词作为一个词:( @Adam 你问过如何将文本拖放到段落中,我回答了这个问题。您可以在特定事件中再次运行$("p.given").html(chunkWords($("p.given").text())); 以分解输入的新单词。如果您需要更多帮助,我建议您为这个问题标记一个答案,稍微处理一下新问题,然后如果需要,问另一个问题。 谢谢先生,我再问一个问题 你能看看这个吗,我问的是另一个***.com/questions/58215677/…【参考方案2】:
    用单词创建数组。 创建新片段:https://developer.mozilla.org/en-US/docs/Web/API/Document/createDocumentFragment#JavaScript 使用 forEach() 和 append 迭代数组,使用 &lt;span data-index="indexNumber"&gt;arrayWord&lt;/span&gt; 对每个单词进行分段。 迭代后,将片段附加到您的&lt;p&gt;。 然后你得到你的句子用单独的词。 为每个 span 元素添加 data-dropped-value 属性。 on drop拖动元素你将更新跨度,它将是data-dropped-value="your dragged value"。 然后您可以将此值附加到此跨度。

    拖放时将文本附加到悬停的跨度。 不需要

【讨论】:

这可能有效,但需要在当前放置点之后附加&lt;span&gt;。我认为 OP 不希望删除的元素或单词成为当前 &lt;span&gt; 的一部分。 另外,当用户输入新文本时会发生什么? @Twisty 是的,你的权利先生。这就是问题 也许在点击事件上追加输入会有所帮助,点击 span,获取 event.target,然后追加输入。但你需要将pspan 更改为div,因为语义,我认为 输入应该是最好的解决方案。然后你可以处理输入并增加价值。所以它将是可写和可删除的。

以上是关于如何使用 jQuery 拖放与段落元素的主要内容,如果未能解决你的问题,请参考以下文章

如何让 jQueryUI 拖放与触摸设备一起使用

拖放与物理行为

拖放与视觉指示

nstableview 拖放与自定义单元格视图

jQuery拖放 - 如何获取被拖动的元素

QListWidget 拖放与通过 setItemWidget 设置的自定义小部件