有没有办法将 div 合并在一起形成一个 div?

Posted

技术标签:

【中文标题】有没有办法将 div 合并在一起形成一个 div?【英文标题】:Is there a way to merge divs together to form one div? 【发布时间】:2021-11-13 00:23:04 【问题描述】:

我正在开展一个项目,用户可以在其中使用信息列表。下面我用代码解释一下。

<div>
  <div id="factmarker1" onmouseup="factFunction(1)">
     <b class="fact-num" id="fact-num1">1</b><mark id="fact1">The earth is spherical</mark>
  </div>
  <div id="factmarker2" onmouseup="factFunction(2)">
     <b class="fact-num" id="fact-num2">2</b><mark id="fact2">There is no gravity in space</mark>
  </div>
  <div id="factmarker3" onmouseup="factFunction(3)">
     <b class="fact-num" id="fact-num3">3</b><mark id="fact3">The earth is made up of more water</mark>
  </div>
  <div id="factmarker4" onmouseup="factFunction(4)">
     <b class="fact-num" id="fact-num4">4</b><mark id="fact4">There is a lunar year every four years</mark>
  </div>
  <div id="factmarker5" onmouseup="factFunction(5)">
     <b class="fact-num" id="fact-num5">5</b><mark id="fact5">Every lunar year has 366 days</mark>
  </div>
  <div id="factmarker6" onmouseup="factFunction(6)">
     <b class="fact-num" id="fact-num6">6</b><mark id="fact6">The earth is spherical</mark>
  </div>
  <div id="factmarker7" onmouseup="factFunction(7)">
     <b class="fact-num" id="fact-num7">7</b><mark id="fact7">The earth is spherical</mark>
  </div>
</div>
<div id="previewFact"></div>

现在这很简单。如果用户单击或突出显示任何事实,则会弹出一个由 javascript 启用的选项选项卡,用户可以在其中选择执行很多操作,例如复制、保存或共享每个事实。如果用户突出显示事实 5 并选择保存它,预览提示会显示如下内容:

/*
FACT 5

Every lunar year has 366 days

现在我的问题是:我希望能够允许用户同时突出显示多个事实,但我找不到方法来做到这一点。如果用户发现事实 1 到 4 有趣并突出显示,我希望预览是这样的:

/*
FACT 1 to 4

1 The earth is spherical
2 There is no gravity in space
3 The earth is made up of more water
4 There is a lunar year every four years
*/

用户还应该能够选择任意多个事实。另外,事实是用php从数据库中调出来的,所以我不知道事实有多少,内容是什么。

我尝试过使用window.getSelection() 方法。我尝试使用“fact-num”类,这样当我获得突出显示区域的内容时,我可以搜索其中的类 - 如下所示:

function factFunction(factNum) 
  var sel = window.getSelection();
  var factNumLength = sel.querySelectorAll('.fact-num').length;
  if(factNumLength > 1) //checking if it is a multiple highlight or not
    var factStart = sel.querySelectorAll('.fact-num')[0].innerhtml;
    var factStop = sel.querySelectorAll('.fact-num')[factNumLength - 1].innerHTML;
    var preview = "Fact "+factStart+" to "+factStop;
    preview += "<br/>"+sel.toString();
    document.getElementById('previewFact').innerHTML = preview;
  else
    var preview = "Fact "+factNum;
    preview += "<br/>"+sel.toString();
    document.getElementById('previewFact').innerHTML = preview;
  

这不是整个代码块,因为它要长得多,但这是整个事情的一般结构,它不起作用。我不知道我在使用时是否应该使用window.getSelection() 的值。

我非常感谢任何帮助,因为我昨天和今天大部分时间都在寻找答案。

谢谢

编辑

只是为了让我正确理解, 当像这样突出显示时: 它应该显示:

【问题讨论】:

让我清楚一点:您希望用户点击任意数量的“事实”,然后将该事实复制到预览区域?如果是这样,无论选择或重新编号的顺序如何,事实是否都保留其原始编号? @ProfessorAbronsius - 如果我正确理解您的问题,我的回答是,当事实被“突出显示”(未点击)时,事实将被复制到预览区域,但事实将保留其原始数字不管事实是从上到下还是从下到上突出显示。我希望这能回答你的问题 它们是如何突出显示的?通过用鼠标滑动选择? @ProfessorAbronsius - 完全正确 在选择文本后,我会看看这个调用事件的答案:***.com/a/3731367/1969888 【参考方案1】:

我无法在规范中找到Selection 提供querySelectorAll 的任何地方,但即使它存在,containsNodetruepartial 可能是更好的选择。

此外,您希望利用事件委托,而不是将事件处理程序附加到每个元素。这样您就可以更灵活地应用您想要应用的逻辑。

使用 data- 属性,您可以为元素提供一些额外的语义信息,例如您的事实 ID。

我克隆了 displayFactsResult 中的事实元素,但您可以肯定地再次更改它以匹配您想要的输出。

最终的代码可能看起来像这样(进一步的 cmets 代码的每个部分都做了什么):

function displayFactsResult(array) 
  const previewFact = document.getElementById("previewFact");

  // empty the facts preview
  previewFact.innerHTML = '';

  // create the info how many slected
  const infoNode = document.createElement('div')
  if (array.length == 1) 
    infoNode.textContent = 'Fact ' + array[0].dataset.fact
   else if (array.length > 1) 
    infoNode.textContent = 'Facts ' + array[0].dataset.fact + ' to ' + array[array.length-1].dataset.fact
  
  previewFact.appendChild(infoNode)

  // clone each of the selected facts and append them to the preview
  array.forEach(node => 
    previewFact.appendChild(node.cloneNode(true));
  )



// use event delegation instead of attaching the event handler to each element
document.querySelector('.facts').addEventListener('mouseup', (e) => 

  // traverse the DOM up until on element with `data-fact` or `.facts` element is reached
  let element = e.target
  while (element != e.currentTarget && !element.dataset.fact) 
    element = element.parentNode;
  

  // get the selection
  var sel = window.getSelection();

  // get all elements, and filter by those in the selection
  var factsInSelection = Array.from(document.querySelectorAll('[data-fact]'))
    .filter(node => 
      return sel.containsNode(node, true)
    );

  if (factsInSelection.length > 0) 
    // if there is at least one fact selected pass it to the display function
    displayFactsResult(factsInSelection)
   else if (element.dataset.fact) 
    // if the element at which we stopped traversing has `data-fact` use this to display
    displayFactsResult([element])
   else 
    displayFactsResult([])
  
)
<div class="facts">
  <div id="factmarker1" data-fact="1">
    <b class="fact-num" id="fact-num1">1</b><mark id="fact1">The earth is spherical</mark>
  </div>
  <div id="factmarker2" data-fact="2">
    <b class="fact-num" id="fact-num2">2</b><mark id="fact2">There is no gravity in space</mark>
  </div>
  <div id="factmarker3" data-fact="3">
    <b class="fact-num" id="fact-num3">3</b><mark id="fact3">The earth is made up of more water</mark>
  </div>
  <div id="factmarker4" data-fact="4">
    <b class="fact-num" id="fact-num4">4</b><mark id="fact4">There is a lunar year every four years</mark>
  </div>
  <div id="factmarker5" data-fact="5">
    <b class="fact-num" id="fact-num5">5</b><mark id="fact5">Every lunar year has 366 days</mark>
  </div>
  <div id="factmarker6" data-fact="6">
    <b class="fact-num" id="fact-num6">6</b><mark id="fact6">The earth is spherical</mark>
  </div>
  <div id="factmarker7" data-fact="7">
    <b class="fact-num" id="fact-num7">7</b><mark id="fact7">The earth is spherical</mark>
  </div>
</div>
<hr>
<div id="previewFact">
</div>

【讨论】:

当我看到这个时,我放弃了尝试寻找解决方案......非常好+1【参考方案2】:

我已对此进行了更新,以创建一个包含事实 ID 和文本的对象数组,这些对象会检查事实 ID 以避免重复,并将所有点击的事实保存到 previewFact div 中。

let savedFacts = [];

$('.fact').click(function() 

  let factText = $(this).children('mark').text();
  let factId = $(this).children('.fact-num').text();
  
  if (savedFacts.findIndex(x => x.id === factId) == -1) 

    savedFacts.push("id":factId,"fact":factText)

  
  
  $("#previewFact").html(savedFacts.map(function(elem)
        return `$elem.id $elem.fact`;
    ).join("<br />"));
  
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
  <div id="factmarker1" class="fact">
     <b class="fact-num" id="fact-num1">1</b><mark id="fact1">The earth is spherical</mark>
  </div>
  <div id="factmarker2" class="fact">
     <b class="fact-num" id="fact-num2">2</b><mark id="fact2">There is no gravity in space</mark>
  </div>
  <div id="factmarker3"  class="fact" >
     <b class="fact-num" id="fact-num3">3</b><mark id="fact3">The earth is made up of more water</mark>
  </div>
  <div id="factmarker4"  class="fact" >
     <b class="fact-num" id="fact-num4">4</b><mark id="fact4">There is a lunar year every four years</mark>
  </div>
  <div id="factmarker5"  class="fact">
     <b class="fact-num" id="fact-num5">5</b><mark id="fact5">Every lunar year has 366 days</mark>
  </div>
  <div id="factmarker6"  class="fact" >
     <b class="fact-num" id="fact-num6">6</b><mark id="fact6">The earth is spherical</mark>
  </div>
  <div id="factmarker7"  class="fact">
     <b class="fact-num" id="fact-num7">7</b><mark id="fact7">The earth is spherical</mark>
  </div>
</div>
<br />
<span>Saved facts:</span>
<div id="previewFact"></div>

【讨论】:

以上是关于有没有办法将 div 合并在一起形成一个 div?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法将 2 个或多个邮政编码边界添加在一起以形成区域?

jQuery 中有没有办法将 div 放在前面?

有没有办法将变量添加到 div 的 id? [关闭]

jQuery折叠褪色的div和扩展动画问题

附加代码以形成成功消息的脚本将图像放在消息 DIV 之外

有没有办法使用CSS向后工作[重复]