質問

Note: I had a previous similar question which I've now attempted to delete. I thought the problem was to do with the .NET webbrowser control but it's to do with IE.

The following code is the contents of an .htm file that simply displays 3 items that can be clicked. As each item is clicked a javascript method changes its background to blue and changes the previously selected item background back to white.

Here's the problem, which only occurs IE8, 9 and 10. It works in FF, chrome and I managed to demonstrate it works in IE5 and IE7 using IE10 developer preview.

Click on ITEM 1, then click on ITEM 1.1 - ITEM 1.1 is highlighted but ITEM 1 is not de-highlighted.

However (moving up the document tree):
Click on ITEM 1, then ROOT - No problem
Click on ITEM 1,1 then ITEM 1 - No problem.

Now, if I switch the javascript selectElement(e) method to first deselect then select, the problem becomes:

Click on ITEM 1.1 then click on ITEM 1 - There is a noticeable delay between ITEM 1 being clicked and the blue background being displayed.

If the image tags are removed, the problem goes away.

Scrolling the item out of view and then back in again fixes the rendering. Unfortunately, calling Invalidate or Update does not fix the problem.

Switching the display style of the previously selected element to none and then back again fixes the problem - unless the user selects the node text by mistake (eg double-click)

Some things I've tried:

  1. Instead of just changing the class, I've tried replacing the outerhtml completely but this makes no difference.
  2. Removing the image tag and including a background image makes no difference.

Code

*When testing this on your own machine, the web page will not be able to find the 'expand_tree_20x8.png' file; this doesn't matter as the behaviour is exhibited whether the images can be found or not. The important thing is that the image tags must be in the file.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en-GB">

    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />

        <style type="text/css">
            span, img {margin:0;padding:0}
            .child {margin-left: 10px;}
            .normal {background-color: White;}
            .selected {background-color: blue; color: white;}
        </style>

        <script type="text/javascript">

            var selectedElement;

            function selectElement(e) {

                /* Select new element */
                e.attributes["class"].value = "selected";

                /* Unselect currently selected */
                if (selectedElement) {
                    selectedElement.attributes["class"].value = "normal";
                }

                selectedElement = e;
            }


        </script>

    </head>

    <body>

        <div>

            <div class="child"><label id="root_id" class="normal" onclick="selectElement(this)">ROOT</label></div>

            <div class="child"><img alt="img" src="temp/expand_tree_20x8.png" />

                <label id="item1_id" class="normal" onclick="selectElement(this)">ITEM 1</label>

                <div class="child"><img alt="img" src="temp/expand_tree_20x8.png" />
                    <label id="item1_1_id" class="normal" onclick="selectElement(this)">ITEM 1.1</label>
                </div>

            </div>

        </div>

    </body>

</html>
役に立ちましたか?

解決

This will probably not fix the redraw issue you are facing, but this was way too long to include in a comment.

The variable e normally stands for an event object, not a dom object. So that is cnfusing for other developers when they look at your code. Change it to elem, ele, domObj, or anything else but e.

Second, the way you are setting the class name is strange. I would expect to see className.

var selectedElement;

function selectElement(elem) {

    /* Select new element */
    elem.className = "selected";

    /* Unselect currently selected */
    if (selectedElement) {
        selectedElement.className = "normal";
    }

    selectedElement = elem;
}

It probably would be better to use some helper functions to add and remove the class so you can have more than one class on the elements.

function hasClass(elem, cls) {
    return elem.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}
function addClass(elem, cls) {
    if (!this.hasClass(elem, cls)) elem.className += " " + cls;
}
function removeClass(elem, cls) {
    if (hasClass(elem, cls)) {
        var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
        elem.className = elem.className.replace(reg, ' ');
    }
}


var selectedElement;
function selectElement(elem) {

    /* Select new element */
    addClass(elem, "selected");

    /* Unselect currently selected */
    if (selectedElement) {
        removeClass(selectedElement, "normal";
    }

    selectedElement = elem;
}

Sometimes reading the height forces a redraw, so try doing something like this

var selectedElement;
function selectElement(elem) {

    /* Select new element */
    addClass(elem, "selected");

    /* Unselect currently selected */
    if (selectedElement) {
        removeClass(selectedElement, "normal";
    }

    /* Try to force a redraw */
    //elem.style.display = "none";  //if just reading offsetHeight, does not work try uncommenting the two lines of code.
    var redrawFix = elem.offsetHeight;
    //elem.style.display = "block";  //or inline or whatever

    selectedElement = elem;
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top