I want to wrap all the nodes within the #slidesContainer
div with JavaScript. I know it is easily done in jQuery, but I am interested in knowing how to do it with pure JS.
Here is the code:
<div id="slidesContainer">
<div class="slide">slide 1</div>
<div class="slide">slide 2</div>
开发者_如何学Python <div class="slide">slide 3</div>
<div class="slide">slide 4</div>
</div>
I want to wrap the divs with a class of "slide" collectively within another div with id="slideInner"
.
If your "slide"s are always in slidesContainer you could do this
org_html = document.getElementById("slidesContainer").innerHTML;
new_html = "<div id='slidesInner'>" + org_html + "</div>";
document.getElementById("slidesContainer").innerHTML = new_html;
Like BosWorth99, I also like to manipulate the dom elements directly, this helps maintain all of the node's attributes. However, I wanted to maintain the position of the element in the dom and not just append the end incase there were siblings. Here is what I did.
var wrap = function (toWrap, wrapper) {
wrapper = wrapper || document.createElement('div');
toWrap.parentNode.insertBefore(wrapper, toWrap);
return wrapper.appendChild(toWrap);
};
How to "wrap content" and "preserve bound events"?
// element that will be wrapped
var el = document.querySelector('div.wrap_me');
// create wrapper container
var wrapper = document.createElement('div');
// insert wrapper before el in the DOM tree
el.parentNode.insertBefore(wrapper, el);
// move el into wrapper
wrapper.appendChild(el);
or
function wrap(el, wrapper) {
el.parentNode.insertBefore(wrapper, el);
wrapper.appendChild(el);
}
// call function
// wrapping element "wrap_me" into a new element "wrapper"
wrap(document.querySelector('div.wrap_me'), document.createElement('div'));
ref
https://plainjs.com/javascript/manipulation/wrap-an-html-structure-around-an-element-28
If you patch up document.getElementsByClassName for IE, you can do something like:
var addedToDocument = false;
var wrapper = document.createElement("div");
wrapper.id = "slideInner";
var nodesToWrap = document.getElementsByClassName("slide");
for (var index = 0; index < nodesToWrap.length; index++) {
var node = nodesToWrap[index];
if (! addedToDocument) {
node.parentNode.insertBefore(wrapper, node);
addedToDocument = true;
}
node.parentNode.removeChild(node);
wrapper.appendChild(node);
}
Example: http://jsfiddle.net/GkEVm/2/
A general good tip for trying to do something you'd normally do with jQuery, without jQuery, is to look at the jQuery source. What do they do? Well, they grab all the children, append them to a a new node, then append that node inside the parent.
Here's a simple little method to do precisely that:
const wrapAll = (target, wrapper = document.createElement('div')) => {
;[ ...target.childNodes ].forEach(child => wrapper.appendChild(child))
target.appendChild(wrapper)
return wrapper
}
And here's how you use it:
// wraps everything in a div named 'wrapper'
const wrapper = wrapAll(document.body)
// wraps all the children of #some-list in a new ul tag
const newList = wrapAll(document.getElementById('some-list'), document.createElement('ul'))
I like to manipulate dom elements directly - createElement, appendChild, removeChild etc. as opposed to the injection of strings as element.innerHTML
. That strategy does work, but I think the native browser methods are more direct. Additionally, they returns a new node's value, saving you from another unnecessary getElementById
call.
This is really simple, and would need to be attached to some type of event to make any use of.
wrap();
function wrap() {
var newDiv = document.createElement('div');
newDiv.setAttribute("id", "slideInner");
document.getElementById('wrapper').appendChild(newDiv);
newDiv.appendChild(document.getElementById('slides'));
}
jsFiddle
Maybe that helps your understanding of this issue with vanilla js.
To simply wrap a div without the need of the parent:
<div id="original">ORIGINAL</div>
<script>
document.getElementById('original').outerHTML
=
'<div id="wrap">'+
document.getElementById('original').outerHTML
+'</div>'
</script>
Working Example: https://jsfiddle.net/0v5eLo29/
More Practical Way:
const origEle = document.getElementById('original');
origEle.outerHTML = '<div id="wrap">' + origEle.outerHTML + '</div>';
Or by using only nodes:
let original = document.getElementById('original');
let wrapper = document.createElement('div');
wrapper.classList.add('wrapper');
wrapper.append(original.cloneNode(true));
original.replaceWith(wrapper);
Working Example: https://jsfiddle.net/wfhqak2t/
A simple way to do this would be:
let el = document.getElementById('slidesContainer');
el.innerHTML = `<div id='slideInner'>${el.innerHTML}</div>`;
Note - below answers the title of the question but is not specific to the OP's requirements (which are over a decade old)
Using the range
API is making wrapping easy, by creating a Range which selects only the node wished to be wrapped, and then use the surroundContents
API to wrap it.
Below code wraps the first (text) node with a <mark>
element and the last node with a <u>
element:
const wrapNode = (nodeToWrap, wrapWith) => {
const range = document.createRange();
range.selectNode(nodeToWrap);
range.surroundContents(wrapWith);
}
wrapNode(document.querySelector('p').firstChild, document.createElement('mark'))
wrapNode(document.querySelector('p').lastChild, document.createElement('u'))
<p>
first node
<span>second node</span>
third node
</p>
From what I understand @Michal 's answer is vulnerable to XXS attacks (using innerHTML is a security vulnerability) Here is another link on this.
There are many ways to do this, one that I found and liked is:
function wrap_single(el, wrapper) {
el.parentNode.insertBefore(wrapper, el);
wrapper.appendChild(el);
}
let divWrapper;
let elementToWrap;
elementToWrap = document.querySelector('selector');
// wrapping the event form in a row
divWrapper = document.createElement('div');
divWrapper.className = 'row';
wrap_single(elementToWrap, divWrapper);
This works well. However for me, I sometimes want to just wrap parts of an element. So I modified the function to this:
function wrap_some_children(el, wrapper, counter) {
el.parentNode.insertBefore(wrapper, el);
if ( ! counter ) {
counter = el.childNodes.length;
}
for(i = 0; i < counter; i++) {
wrapper.appendChild( el.childNodes[0] );
}
}
// wrapping parts of the event form into columns
let divCol1;
let divCol2;
// the elements to wrap
elementToWrap = document.querySelector('selector');
// creating elements to wrap with
divCol1 = document.createElement('div');
divCol1.className = 'col-sm-6';
divCol2 = document.createElement('div');
divCol2.className = 'col-sm-6';
// for the first column
wrap_some_children(elementToWrap, divCol1, 13); // only wraps the first 13 child nodes
// for the second column
wrap_some_children(elementToWrap, divCol2);
I hope this helps.
wrapInner multiple tag content
function wilWrapInner(el, wrapInner) {
var _el = [].slice.call(el.children);
var fragment = document.createDocumentFragment();
el.insertAdjacentHTML('afterbegin', wrapInner);
var _wrap = el.children[0];
for (var i = 0, len = _el.length; i < len; i++) {
fragment.appendChild(_el[i]);
}
_wrap.appendChild(fragment);
}
Link Demo Jsbin
精彩评论