WinJS无法卸载js/css文件

7
我正在开发一个Windows 8 Metro应用程序,我发现即使是在他们的示例应用程序中(我没有更改过代码),当你在页面之间导航时,顶级的 "default.html" 会获取应用程序运行期间加载过的每个js和css文件。
这导致我的css在不同页面之间发生冲突,给我带来了很多麻烦。我是否漏掉了什么或者这是一个严重的错误?
4个回答

13

不卸载JavaScript和CSS是一个有意为之的选择,而不是疏忽或失误。

首先,要明白页面控件完全是JavaScript构建的 - 浏览器引擎完全不知道它们的存在。浏览器只看到由脚本动态生成的DOM块。

Web平台不允许您卸载脚本文件 - 一旦它们加载到上下文中,它们将永久存在。

对于CSS,他们可以尝试删除标签,但这会带来很多麻烦。根据导航到页面的顺序不同,您可能会在同一应用程序中应用不同的样式。如果两个页面都引用相同的样式表怎么办?您添加两个相同的链接标记吗?那要删除哪一个呢?

这是一团乱麻。相反,WinJS保证脚本和样式表仅在第一次被引用时加载一次。因此,您可以使应用程序中的每个页面都引用“myStyles.css”,它只会被加载一次(并且只会有一个样式标记)。

那么如何防止出现您所见到的问题?首先要记住你正在构建一个应用程序,而不是将任意增长的新内容添加到网站。确定您的通用样式和类别。将共享的样式放在default.css中,并从default.html文件引用它。

对于各个页面,最简单的方法是为样式名称加上页面名称前缀。而不是:

<div class='intro'></div>

执行

<div class='page1-intro'></div>

如果您使用命名空间,就可以确保避免冲突。

如果您要通过ID引用页面元素,请不要这样做。在页面中使用ID会导致各种潜在的奇怪问题(如果同时呈现相同的页面控件会怎样?另外,ID要在页面加载到DOM后才存在,这意味着基于ID的data-win-options引用不起作用)。但如果您坚持要这么做,考虑使用页面前缀作为ID的命名空间。

基本上,设置临时命名空间可以避免冲突。这比手动删除链接标记要容易得多,并且会产生比执行完整导航更好的应用程序体验。


脚本文件并不是什么问题,很容易命名函数以避免冲突,或者只需使用WinJS.Namespace。然而,CSS文件可能会被卸载,似乎这样做是明智的。目前看来,似乎每个人都已经接受了为所有CSS类命名空间的方式,这实际上是一个完全的hack...至少它是有意为之的,但长期来看,我相信这是微软将要受到批评的又一件事情。 - Endophage
除了每个页面加载时加载CSS文件之外,我不确定问题是什么。示例告诉您确保为页面命名空间;这很有意义。您可能可以使用LESS / SCSS来帮助命名空间,例如Web Essentials或Web Workbench。 - kamranicus

3
这不是一个bug,而是WinJS模板默认应用程序模式的一部分。默认WinJS模板使用单页模型,意味着所有内容都通过PageNavigatorControl加载到default.html中。结果是,在任何时候都有一个单一的DOM(文档对象模型)存在于内存中。如果您在常规浏览器中遵循类似的模式,您会看到相同的行为。
如果您想要的话,可以使用更传统的多页面导航和传统的href链接。这不是推荐的方法,但如果您试图将使用该模型构建的现有Web资产引入,它可能会使事情变得更加容易。

我明白单页模型,我只是觉得微软会更聪明一些,在您导航离开内部页面时卸载资源。 - Endophage

0

这可能是一个采用约定命名方法的好解决方案:

var currentPage = Application.navigator.pageControl.uri.replace("ms-appx://" + Windows.ApplicationModel.Package.current.id.name.toLowerCase(), "");
var currentCss = currentPage.replace(".html", ".css");

var ignoreList = ["/css/ui-dark.css", "/css/ui-light.css", "/css/default.css"];

WinJS.Utilities.query("link").forEach(function (linkElem) {
    if (linkElem.href.toLowerCase().indexOf(currentCss) > -1) {
        linkElem.disabled = false;
    } else {
        var ignore = false;
        ignoreList.forEach(function (ignoreItem) {
        if (linkElem.href.toLowerCase().indexOf(ignoreItem.toLowerCase()) > -1) {
            ignore = true;
        }});
        if (!ignore) {
            linkElem.disabled = true;
        }
        }
});

0
您可以通过查询导入样式的link元素,并禁用不需要的元素来解决此问题。确保不要禁用MS CSS文件和项目中的default.css文件(假设您使用它来定义应用程序的通用样式)。
以下是一个示例,展示如何实现。这是一个名为page2.html的文件,在WinJS.Pages.UI.render方法加载时将定位和禁用不需要的link元素。确保启用page2.css文件并保留简单忽略的文件列表。
(我将其放在ready处理程序函数中,但我倾向于在WinJS.Navigation事件处理程序中使用此技术,并依靠一致的文件命名获得所需结果)。
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>UnloadCSS</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

    <!-- UnloadCSS references -->
    <link href="/css/page2.css" rel="stylesheet" />

<script>
    WinJS.UI.Pages.define("/page2.html", {
        ready: function () {

            var ignoreList = ["/css/ui-dark.css", "/css/ui-light.css", "/css/default.css"];
            var myCSS = "/css/page2.css";

            WinJS.Utilities.query("link").forEach(function (linkElem) {
                if (linkElem.href.indexOf(myCSS) > -1) {
                    linkElem.disabled = false;
                } else {
                    var ignore = false;
                    ignoreList.forEach(function (ignoreItem) {
                        if (linkElem.href.indexOf(ignoreItem) > -1) {
                            ignore = true;
                        }
                    });
                    if (!ignore) {
                        linkElem.disabled = true;
                    }
                }
            });
        }
    });
</script>
</head>
<body>
    <button>Change </button>
</body>
</html>

是的,我知道我可以那样做,但这正是我试图避免需要硬编码的。我可能会切换到多页面实现,并且不为各个部分设置任何CSS,每个主页面都将是一个模板,所有CSS都在单个文件中,然后加载的子页面将不具有自己的CSS。 - Endophage

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接