如何使用不完整的CSS处理Chrome渲染动态添加的元素

时间:2016-06-23 06:34:47

标签: javascript jquery html css svg

我在<A>个元素(在原始HTML中显示)上设置类名,在这些元素下添加SVG元素,因为它们正在加载$ .get。 SVG元素具有未在Chrome上应用的样式,除非我执行强制重新渲染的操作。例如,在Developer视图中检查/取消选中样式属性的框,或使用Brackets IDE并修改CSS(这会导致Brackets撕掉我们所有的CSS并替换每个键入的字符)。

当我将类添加代码放在setTimeout上时,间隔至少为80毫秒,它可以工作。在IE11,Edge,Safari和Firefox中,它可以在没有这种解决方法的情况下工作。根据网络面板,CSS在脚本之前加载(也尝试将它们放在尾部而不是头部),这是Chrome无法正确管理渲染序列的问题(最有可能尝试使用最少的重新渲染算法太聪明了对我不利。)

我该如何妥善处理?

这是一个working version,因为我对通常应用jQuery的样式进行了硬编码(在生产中我会渲染这个服务器端,但它不是一个令人满意的解决方案)。

这里是broken version

您可以验证将navigation.js中的第55-64行移动到setTimeout是否有效。

在Mac OS X上使用Chrome版本51.0.2704.103(64位)

编辑:根据要求提供相关的HTML和JS,请参阅上面的链接以获取完整的图片。

的index.htm

<html>
  <head>
    <link rel="stylesheet" type="text/css" href="styles.css"></link>
  <script type="text/javascript" src="scripts/jquery.min.js"></script>
  <script type="text/javascript" src="scripts/navigation.js"></script>
  </head>

<body>
  <header>
    <div id="logo" class="icon" data-src="images/logo.svg"></div>

    <nav data-src="images/navigation.svg">
      <a href="index.htm">news</a>
      <a href="articles.htm">articles</a>
      <a href="projects.htm">projects</a>
      <a href="about.htm">about</a>
    </nav>

navigation.js

$(document).ready(function() {
  loadNavigationButtons();
});

function loadNavigationButtons() {
  var buttonParts =
      [
        "matte",
        "border",
        "highlight",
        "icon",
        "selection"
      ];

  return $.Deferred(function(callback) {
    $("nav a").each(function(index) {
      var navigationIconSet = $(this)
        .closest("nav[data-src]")
        .attr("data-src");

      var buttonName = $(this).text();
      $(this).text("");

      if (document.URL.indexOf($(this).attr("href")) != -1) {
        // Add navigation-selected class to <a>
        $(this).addClass("navigation-selected");
      } else {
        // Add navigation-unselected class to <a>
        $(this).addClass("navigation-unselected");
      }

      for (var partIndex in buttonParts) {
        loadIcon(
          // Prepend to this element.
          $(this),

          // Attempt to find a part for this specific button.
          navigationIconSet + "#" + buttonName + "-" + buttonParts[partIndex],

          // Fallback to generic part name.
          navigationIconSet + "#" + buttonParts[partIndex],

          // Class to apply.
          "navigation navigation-" + buttonParts[partIndex]

          // Not passing callback parameter
        );
      }

      // Append button text.
      $("<div></div>")
        .text(buttonName)
        .addClass("navigation navigation-text")
        .appendTo($(this));
    });

    callback.resolve();
  });
}

function loadIcon($container, iconUri, fallbackUri, classToApply, callbackParameter) {
  if (~iconUri.indexOf("#")) {
    var sourceComponents = iconUri.split("#");
    var fallbackComponents;

    if (fallbackUri) {
      fallbackComponents = fallbackUri.split("#");

      // Support fallback only within the same icon set.
      if (sourceComponents[0] != fallbackComponents[0]) {
        return $.Deferred(function(callback) {
          callback.reject($container, null, callbackParameter)
        });
      }
    } else {
      fallbackComponents = [null, null];
    }

    return loadIconFromDefinition(
      $container,
      sourceComponents[0],
      sourceComponents[1],
      fallbackComponents[1],
      classToApply,
      callbackParameter);
  } else {
    return loadIconFromFile(
      $container, iconUri, classToApply, callbackParameter);
  }
}

function loadIconFromFile($container, iconUri, classToApply, callbackParameter) {
  return $.Deferred(function(callback) {
    $.get(iconUri).done(function(icon) {
      callback.resolve(
        $("svg", icon).prependTo($container),
        null,
        callbackParameter);
    });
  });
}

function loadIconDefinition(definitionUri) {
  if (!loadIconDefinition.loaded) {
    loadIconDefinition.loaded = {};
  }

  if (loadIconDefinition.loaded[definitionUri]) {
    return loadIconDefinition.loaded[definitionUri];
  }

  loadIconDefinition.loaded[definitionUri] =
    $.Deferred(function(callback) {
      loadIconFromFile($("body"), definitionUri)
        .then(function($loaded) {
      // Hide definition after it's loaded.
      $loaded.get(0).setAttributeNS(null, "style", "display:none");
      callback.resolve($loaded);
    });
  });

  return loadIconDefinition.loaded[definitionUri];
}

function loadIconFromDefinition(
$container, definitionUri, groupName, fallbackGroupName, classToApply, callbackParameter) {
  return $.Deferred(function(callback) {
    loadIconDefinition(definitionUri).then(function($loaded) {
      if (fallbackGroupName &&
          !$loaded.find("#" + groupName).length) {
        groupName = fallbackGroupName;
      }
      callback.resolve(
        $("<svg class=\"" + classToApply + "\"><use xlink:href='#" + groupName + "'></use></svg>")
        .prependTo($container),
        $loaded,
        callbackParameter);
    });
  });
}

1 个答案:

答案 0 :(得分:0)

我觉得这个问题在炼狱中花了足够的时间。

建议的解决方法:

  • 继续动态添加子项,但始终在服务器端设置父元素类。在ASP.net的情况下,使用Razor表达式,在浏览器获取页面之前,为已经设置的类属性呈现有问题的父元素的简短HTML。这是我选择的解决方法。
  • 隐藏有问题的元素,直到setTimeout经过足够长的延迟,设置所有必需的类并取消隐藏元素以减少闪烁。通过在&#34;对话框中使用加载进度条,可以进一步平滑用户体验。它使页面的其余部分变暗并继续淡入。

这个解决方案没有完成:

  • 当浏览器处于更新DOM元素的类属性能够触发重新渲染的状态时,找到我们可以挂钩的事件或Promise。

其他:

  • 提起Chromium bug描述这种情况......也许在5年后它将被修复。