Adding multiple VML elements via JavaScript in IE8

2019-07-07 09:26发布

问题:

Working with IE 8, I am attempting to add two VML ovals (A,B) to my page, through javascript. Whichever oval is appended to the parent DIV is rendered, but I the second is not.

If I appendChild(A) then appendChild(B), Oval A is rendered, B is not. If I appendChild(B) then appendChild(A), Oval B is rendered, A is not.

document.namespaces.add("v","urn:schemas-microsoft-com:vml");

this.container = Document.getElementById(mydiv);

var grid2 = document.createElement("v:oval");
grid2.style.left=   "300px";
grid2.style.top=    "250px";
grid2.style.width=  "25pt";
grid2.style.height= "75pt";
grid2.style.position="absolute";
grid2.style.behavior="url(#default#VML)";
grid2.style.display="inline-block";
grid2.setAttribute("fillcolor","#FF0000");
grid2.setAttribute("id", "marker2");    

var grid = document.createElement("v:oval");
grid.style.left="100px";
grid.style.top="100px";
grid.style.width="94pt";
grid.style.height="164pt";
grid.style.position="absolute";
grid.style.behavior="url(#default#VML)";
grid.style.display="inline-block";
grid.setAttribute("fillcolor","#0000FF");
grid.setAttribute("id", "marker");

this.container.appendChild(grid2);
this.container.appendChild(grid);

Am I missing some trick to adding VML?

I have tried it in IE 9, with same results.

Due to corporate rules, only IE is supported within the company, and many users are still using IE8, so I cannot switch the HTML5 Canvas at this time.

Thanks for any suggestions

回答1:

I dealt with a similar problem, where the first VML object added to IE rendered properly, but subsequent ones were rendered too small to see.

This blog article was helpful in determining that IE doesn't support set/getAttribute for VML anymore:

http://louisremi.com/2009/03/30/changes-in-vml-for-ie8-or-what-feature-can-the-ie-dev-team-break-for-you-today/

It turns out not only do set/getAttribute not work, but even setting the attributes directly on the DOM element (e.g. grid2.style.left="300px") didn't work.

Ultimately, what seemed to work was generating all the markup for each element as a string, and injecting it into the DOM by setting it as another element's innerHTML.

var html2 = "<v:oval style=\"left: 300px; top: 250px; width: 25pt; height: 75pt; position: absolute; display: inline-block;\" fillcolor=\"#0000FF\" id=\"marker2\"></v:oval>";
var html = "<v:oval style=\"left: 300px; top: 400px; width: 94pt; height: 164pt; position: absolute; display: inline-block;\" fillcolor=\"#0000FF\" id=\"marker\"></v:oval>";

someNode.innerHTML = html2;
someNode2.innerHTML = html;

I made a dummy node which I used to host the VML: set innerHTML, then move it to the desired parent, repeat.

Ugly, but it worked!



回答2:

Use a documentFragment to add the second node:

document.namespaces.add("v","urn:schemas-microsoft-com:vml");

this.container = document.documentElement;
var frag = document.createDocumentFragment();

var grid2 = document.createElement("v:oval");
grid2.style.left=   "300px";
grid2.style.top=    "250px";
grid2.style.width=  "25pt";
grid2.style.height= "75pt";
grid2.style.position="absolute";
grid2.style.behavior="url(#default#VML)";
grid2.style.display="inline-block";
grid2.setAttribute("fillcolor","#FF0000");
grid2.setAttribute("id", "marker2");    

var grid = frag.appendChild(document.createElement("v:oval"));
grid.style.left="300px";
grid.style.top="400px";
grid.style.width="94pt";
grid.style.height="164pt";
grid.style.position="absolute";
grid.style.behavior="url(#default#VML)";
grid.style.display="inline-block";
grid.setAttribute("fillcolor","#0000FF");
grid.setAttribute("id", "marker");

this.container.appendChild(frag);
this.container.appendChild(grid2);