Using jQuery clone outside the DOM

I was working on a small project where I use the jQuery .clone() method. Pitfall uses this in HTML, which has unique identifiers. So I continued with the implementation of getComputedStyle to find the style properties of the original unique elements, to copy it into a clone and give it a new identifier (yes, it can give performance problems, but it is experimental).

According to the jQuery specification, having done this after cloning, but before adding it will do manipulations outside the DOM (therefore, no "violation" of the identifier will be detected). But I noticed some strange behavior in browsers when I try to find the style properties of elements after cloning an object. Before that, all browsers return the same values, but after cloning:

  • Firefox is carefree, and interestingly, the computed clone style is the actual CSS value, not the calculated data (in pixels).

  • IE seems to work, but the value is not necessarily correct.

  • Chrome - does not calculate. Here is an example:

http://codepen.io/anon/pen/zxqmNK?editors=011

 var elements = []; var objects = []; $('body').find('[id]').each(function() { elements.push(this); }); $('body').clone().find('[id]').each(function() { objects.push(this); }); $.each(elements, function(key, element) { var current = window.getComputedStyle(element, null).getPropertyValue('width'); $('#log').append('<p>' + element.id + ': ' + current + '</p>'); }); $('#log').append('</br>'); $.each(objects, function(count, object) { var current = window.getComputedStyle(object, null).getPropertyValue('width'); $('#log').append('<p>' + object.id + ': ' + current + '</p>'); }); 

Does anyone know if this is a bug or similar behavior has been noticed before? Do not go around the network much (even Stackoverflow). Thanks in advance for your understanding.

Edit - did some more tests, and it looks like IE is behaving just like Chrome. Only instead of returning nothing, everything is set to "auto". If the type of cloned objects is accessed using .css() , all values ​​return 0px (including properties such as background). It seems that only Mozilla processes the cloned object as if some style were applied to it at all.

+8
jquery clone css dom-manipulation
source share
1 answer

First approach

This is how I decided it from the beginning ... calling Mozilla is differently tempting, but it will require sniffing the browser, so we will work without being able to access the cloning style.

Creating two arrays of objects that have unique identifiers - will first contain elements for copying the style from and for the second holding of cloned elements to which the style will be transferred:

 var individual = [], singular = []; $('.target').find('[id]').each(function() { individual.push(this); }) .end().clone().find('[id]').each(function() { singular.push(this); }); 

Now the properties and their values ​​are copied from the array of objects that were stored inside the DOM for clones - after that, the name of the current identifier changes to something unique:

 $.each(individual, function(key) { var tag = this.id, styles = window.getComputedStyle(this, null), element = singular[key]; $.each(styles, function() { var value = styles.getPropertyValue(this); $(element).css(this, value); }); $(element).attr('id', tag + '-cloned'); }); 

After that, the cloned element is inserted, so double identifiers are not present. Please note that this can lead to many style properties (for example, around 220 for each object in Firefox).

Demo

 var individual = [], singular = []; $('.target').find('[id]').each(function() { individual.push(this); }) .end().clone().find('[id]').each(function() { singular.push(this); }) .end().queue(function() { transFigure(); $(this).dequeue(); }) .appendTo('body'); function transFigure() { $.each(individual, function(key) { var tag = this.id, styles = window.getComputedStyle(this, null), element = singular[key]; $.each(styles, function() { var value = styles.getPropertyValue(this); $(element).css(this, value); }); $(element).attr('id', tag + '-cloned'); }); } 

++++++++++++++++++++++++++++++++++++++++++++++++++ +++ ++++++++++++++++++++++++

Second approach

Although the above works fine, it is not very effective, and the page resizing values ​​may start to vary. Thus, I found a better solution after I came across it and then did some digging on JavaScript cssRules . With this, you can directly access all style sheets!

Below is a pen that tries to explain the process, but it comes down to matching (with .test ) the unique identifiers inside the clone from cssText found inside the stylesheet. Then change the id value and save it in an array so that it is subsequently inserted / added to the stylesheet.

A pen

Besides a more efficient approach (without passing all the default values), the actual CSS is copied for all browsers instead of the calculated value. And any derivatives like img , p and such may also be included. It even copies @rules and remains responsive in this way.

Its essence:

 var singular = [], rules = []; $('#target').clone().find('[id]').each(function() { singular.push(this); }); var sheet = document.styleSheets[0], styles = sheet.cssRules; $.each(singular, function() { var selector = '#' + this.id, pattern = new RegExp(selector + '(:| |,)'); $.each(styles, function() { var string = this.cssText; if (pattern.test(string)) { var rule = string.replace(selector, selector + '-duplicate'); rules.push(rule); } }); }); $.each(rules, function() { var index = styles.length; sheet.insertRule(this, index); }); 

After that, the clone can be inserted into the DOM with all the unique identifiers and full style. Please note that in the above example, this was not actually done in order to simplify the code as much as possible when it comes to using cssRules . The image was placed in the markup in advance using another id - one that will correspond to the copied style rules.

+1
source share

All Articles