简体   繁体   English

jquery:将一组元素粘贴到另一组元素/合并元素上

[英]jquery: Paste a set of elements over another set of elements / merging elements

I have 2 sets of elements: 我有2套元素:

<div class='container container1'>
    <div class='colors'>
        <div class='blue'></div>
        <div class='red'></div>
    </div>
    <div class='drinks'>
        <div class='soda'>coke</div>
        <div class='juice'></div>
    </div>
</div>    

<div class='container container2'>
    <div class='cars'>
        <div class='sedans'></div>
        <div class='vans'></div>
    </div>
    <div class='drinks'>
        <div class='soda'>mountain dew</div>
        <div class='coffee'></div>
    </div>
</div>        

I want to paste container1 over container2 such that any replacements are over written and any uniques to each container are put left alone and put together. 我想将container1粘贴到container2上,以便覆盖任何替换,并且将每个容器的任何唯一内容放在一起并放在一起。

The result should be: 结果应该是:

<div class='container container-result'>
    <div class='colors'>
        <div class='blue'></div>
        <div class='red'></div>
    </div>
    <div class='cars'>
        <div class='sedans'></div>
        <div class='vans'></div>
    </div>
    <div class='drinks'>
        <div class='soda'>coke</div>
        <div class='juice'></div>
        <div class='coffee'></div>
    </div>
</div>        

The elements can have any arbitrary hierarchy / depth. 元素可以具有任意层次/深度。 What's the best way to do this? 最好的方法是什么?

Thanks in advance. 提前致谢。

Since your question is tagged jQuery here's a slightly shorter answer using that library: 由于您的问题被标记为jQuery,因此使用该库的答案稍微短一些:

function copy(from, to) {
    from.children().each(function() {
      var match = to.children("." + this.className.split(' ').join('.'));
        if(match.length) {
            if(match.children().length == 0) {
                match.replaceWith(this);
            } else {
                copy($(this), match);
            }
        } else {
            to.append(this);
        }
    }).end().remove();
    from.remove();
}

Then you'd just call it like this: 然后你就像这样称呼它:

copy($(".container1"), $(".container2"));

You can give it a try here , the result is: 你可以在这里尝试一下 ,结果是:

<div class="container container2">
  <div class="cars">
    <div class="sedans"></div>
    <div class="vans"></div>
  </div>
  <div class="drinks">
    <div class="soda">coke</div>
    <div class="coffee"></div>
    <div class="juice"></div></div>
  <div class="colors">
    <div class="blue"></div>
    <div class="red"></div>
  </div>
</div>

Note that the class name is still container2 if you want to replace that just add this to switch the class after the copy() call: 请注意,如果要替换,类名仍然是container2 ,只需在copy()调用之后添加它以切换类:

$(".container2").toggleClass("container2 container-result");

The match is based on all classes the element contains, so if an element has class="car blue" and there's a corresponding class="blue car" it'll choose that one to overwrite. 匹配基于元素包含的所有类,因此如果元素具有class="car blue"并且存在相应的class="blue car"则它将选择要覆盖的类。

This isn't the most efficient route since you're firing up the selector engine on the children each iteration, but unless you're doing lots of elements, it should be pretty quick. 这不是最有效的路线,因为你每次迭代都会在子项上启动选择器引擎,但除非你做了很多元素,否则应该很快。

With regard to unique merging I can't help you there, but if your app by any chance happens to be in PHP then you can use php's array_merge function to merge them before outputting the HTML. 关于独特的合并,我无法帮助你,但如果你的应用程序碰巧是在PHP中,那么你可以使用php的array_merge函数在输出HTML之前合并它们。

ReplaceWith is a nice jquery function to replace aka "paste" over, it may will help you with half of your solution. ReplaceWith是一个很好的jquery函数来代替“粘贴”,它可能会帮助你解决一半的问题。

This appears to do what you wanted: 这似乎做你想要的:

  <div class='container container1'>
      <div class='colors'>
          <div class='blue'></div>
          <div class='red'></div>
      </div>
      <div class='drinks'>
          <div class='soda'>coke</div>
          <div class='juice'></div>
      </div>
  </div>    

  <div class='container container2'>
      <div class='cars'>
          <div class='sedans'></div>
          <div class='vans'></div>
      </div>
      <div class='drinks'>
          <div class='soda'>mountain dew</div>
          <div class='coffee'></div>
      </div>
  </div>        

  <div class='container container-result'>
  </div>

  <script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js" type="text/javascript"></script>
  <script type="text/javascript">

    function getContainerArray(containers, level) {
      level = level || 0;
      var result = [];
      for (var i=0; i<containers.length; ++i) {
        var el = containers.eq(i);
        var obj = { "class": el.attr("class") };
        if (level == 0) {
          obj.items = getContainerArray(el.children("div"), 1);
        } else {
          obj.text = el.text();
        }
        result.push(obj);
      }
      return result;
    }

    function mergeContainers(containerArray) {
      var result = [];

      function indexOfClass(name) {
        for (var i = 0; i < result.length; ++i) {
          if (result[i]["class"] == name) {
            return i;
          }
        }
        return -1;
      }

      for (var i = 0; i < containerArray.length; ++i) {
        var obj = containerArray[i];
        var name = obj["class"];
        var index = indexOfClass(name);
        if (index < 0) {
          result.push(obj);
        } else if (obj.items != null) {
          result[index].items = mergeContainers(new Array().concat(result[index].items, obj.items));
        }
      }

      return result;
    }

    function getHtml(objArray) {
      var result = [];
      for (var i = 0; i < objArray.length; ++i) {
        var obj = objArray[i];
        result.push("<div class=\"", obj["class"], "\">");
        if (obj.text != null && obj.text != "") {
          result.push(obj.text);
        }
        if (obj.items != null) {
          result.push(getHtml(obj.items));
        }
        result.push("</div>");
      }
      return result.join("");
    }

    var html = getHtml(mergeContainers(getContainerArray($("div.container1>div,div.container2>div"))));
    $("div.container-result").append(html);
  </script>

This answer: 这个答案:

  1. Does exactly what you asked for. 完全符合你的要求。
  2. Handles repeated mergings, if div class container-result already exists. 如果div类container-result已经存在,则处理重复的mergings。
  3. Merges any number of container divs. 合并任意数量的容器div。
  4. Uses jQuery and is more efficient than some other solutions. 使用jQuery并且比其他一些解决方案更有效。

See it in action at jsfiddle.net. 在jsfiddle.net上查看它的实际操作。

/*--- Get all "container" divs but exclude any "container-result" divs.
*/
var zContainers = $("div.container").not ("div.container-result");
if (zContainers  &&  zContainers.length)
{
    //--- Get or create the results div.
    var zResultDiv  = $("div.container-result");
    if (!zResultDiv  ||  !zResultDiv.length)
    {
        zResultDiv  = zContainers.parent ().append ("<div class='container container-result'></div>");
        zResultDiv  = $("div.container-result");
    }

    //--- Move the container's contents to the master container, preserving order.
    zContainers.each (function () {$(this).children ().appendTo (zResultDiv);} )

    //--- Kill the old container(s).
    zContainers.remove ();

    RecursivelyMergeDivsByClass (zResultDiv);
}

function RecursivelyMergeDivsByClass (jNode)
{
    /*--- Get a list of the direct-child div's class names.
        Sort and winny out a list of duplicates.
    */
    var zDirectChildDivs    = jNode.find ("> div");
    var aClassList          = zDirectChildDivs.map (function () {return this.className;} ).get ();
    aClassList.sort ().unshift (0);

    for (var J = aClassList.length-1;  J > 0;  J--)
        if (aClassList[J] != aClassList[J-1])   aClassList.splice (J, 1); // Delete items without duplicates.

    aClassList.splice (0, 1);

    /*--- For any duplicates, copy the contents into the first instance, preserving order.
        For exact duplicate nodes, the first (oldest) version is kept and the remaining are discarded.
    */
    for (var J = aClassList.length-1;  J >= 0;  J--)
    {
        var zDupClasses     = zDirectChildDivs.filter ("." + aClassList[J]);

        var zFirstDiv       = zDupClasses.first ();
        zDupClasses         = zDupClasses.not (zFirstDiv);

        zDupClasses.each (function () {$(this).children ().appendTo (zFirstDiv);} )
        zDupClasses.remove ();

        RecursivelyMergeDivsByClass (zFirstDiv)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM