目前,我正在尝试开发一个HTML/JavaScript 8现代应用程序,在该应用程序中,我希望访问安装目录中的本地XML文件。在阅读了许多关于web的想法和代码片段之后,我想出了一种复杂的异步访问文件的方法,这是可行的。但是,这是否是像访问本地XML文件这样简单的事情的最佳/正确方法呢?此外,我希望能够有一个函数加载xml文件,并将XMLDocument对象保存为“全局”变量,以便在按下按钮和其他触发器时,可以访问和解析XMLDocument对象。这是所有问题的起点,因为一个方法是异步的,然后变量是未定义的,等等.
(function () {
"use strict";
WinJS.UI.Pages.define("/pages/reader/reader.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
// TODO: Initialize the page here.
var button = document.getElementById("changeText");
button.addEventListener("click", this.buttonClickHandler, false);
var dropdown = document.getElementById("volumeDropdown");
dropdown.addEventListener("change", this.volumeChangeHandler, false);
var loadSettings = new Windows.Data.Xml.Dom.XmlLoadSettings;
loadSettings.prohibitDtd = false;
loadSettings.resolveExternals = false;
//previous attempt, also didn't work:
//this.xmlDoc = null;
//this.loadXMLdoc(this, this.testXML);
//also not working:
this.getXmlAsync().then(function (doc) {
var xmlDoc = doc;
});
//this never works also, xmlDoc always undefined, or an error:
//console.log(xmlDoc);
},
buttonClickHandler: function (eventInfo) {
// doesn't work, xmlDoc undefined or error:
console.log(xmlDoc);
},
volumeChangeHandler: function (eventInfo) {
var e = document.getElementById("volumeDropdown");
// of course doesn't work, since I can't save the XMLDocument object into a variable (works otherwise):
var nodelist2 = xmlDoc.selectNodes('//volume[@name="volumeName"]/chapter/@n'.replace('volumeName', list[0]));
var volumeLength = nodelist2.length;
for (var index = 0; index < volumeLength; index++) {
var option = document.createElement("option");
option.text = index + 1;
option.value = index + 1;
var volumeDropdown = document.getElementById("chapterDropdown");
volumeDropdown.appendChild(option);
}
},
getXmlAsync: function () {
return Windows.ApplicationModel.Package.current.installedLocation.getFolderAsync("books").then(function (externalDtdFolder) {
externalDtdFolder.getFileAsync("book.xml").done(function (file) {
return Windows.Data.Xml.Dom.XmlDocument.loadFromFileAsync(file);
})
})
},
loadXMLdoc: function (obj, callback) {
var loadSettings = new Windows.Data.Xml.Dom.XmlLoadSettings;
loadSettings.prohibitDtd = false;
loadSettings.resolveExternals = false;
Windows.ApplicationModel.Package.current.installedLocation.getFolderAsync("books").then(function (externalDtdFolder) {
externalDtdFolder.getFileAsync("book.xml").done(function (file) {
Windows.Data.Xml.Dom.XmlDocument.loadFromFileAsync(file, loadSettings).then(function (doc) {
var nodelist = doc.selectNodes("//volume/@name");
var list = [];
for (var index = 0; index < nodelist.length; index++) {
list.push(nodelist[index].innerText);
};
for (var index = 0; index < list.length; index++) {
var option = document.createElement("option");
option.text = list[index] + "new!";
option.value = list[index];
var volumeDropdown = document.getElementById("volumeDropdown");
volumeDropdown.appendChild(option);
};
var nodelist2 = doc.selectNodes('//volume[@name="volumeName"]/chapter/@n'.replace('volumeName', list[0]));
var volumeLength = nodelist2.length;
for (var index = 0; index < volumeLength; index++) {
var option = document.createElement("option");
option.text = index + 1;
option.value = index + 1;
var volumeDropdown = document.getElementById("chapterDropdown");
volumeDropdown.appendChild(option);
};
obj.xmlDoc = doc;
callback(obj);
})
})
});
},
initializeXML: function (doc, obj) {
console.log("WE ARE IN INITIALIZEXML NOW")
obj.xmlDoc = doc;
},
testXML: function (obj) {
console.log(obj.xmlDoc);
},
});})();
总之,由于所有这些复杂的方法都失败了,我应该如何处理一些简单的事情,比如加载一个XML文件,然后将它作为一个可供其他函数使用的对象使用,等等?
谢谢你的帮忙!
PS:我是JavaScript和Windows 8现代应用程序/WinAPI的新手。以前的经验都是在Python和Java中完成的(在这里这样做很简单!)
发布于 2015-04-07 17:52:10
这里有几件事应该能帮到你。
首先,PageControl有三个不同的加载事件,对应于页面类中的方法。ready方法( VS项目模板中包含的惟一方法)只在流程结束时被调用,因此在执行异步文件加载的过程中有点晚。更合适的做法是在init方法中完成这项工作,在页面上创建任何元素之前调用init方法。(在WinJS.UI.processAll完成之后,在页面被添加到DOM之前调用已处理的方法。在DOM中的所有内容都被调用之后。
其次,您的getXMLAsync方法看起来很好,但是已完成的处理程序正在声明另一个xmlDoc变量,然后将其丢弃:
this.getXmlAsync().then(function (doc) {
var xmlDoc = doc; //local variable gets discarded
});"var xmlDoc“在处理程序中声明一个局部变量,但一旦处理程序返回,它就会被丢弃。您需要做的是分配this.xmlDoc = doc,但诀窍是确保"this“是您希望它成为的对象,而不是全局上下文,后者是匿名函数的默认设置。人们通常使用的模式如下:
var that = this;
this.getXmlAsync().then(function (doc) {
that.xmlDoc = doc;
});当然,只有在匿名处理程序被调用之后,xmlDoc成员才会有效。也就是说,如果您将一个console.log放在上面代码的末尾,在}之后);则还没有从异步线程调用处理程序,因此xmlDoc不会有效。如果您将它放在that.xmlDoc = doc之后的处理程序中,那么它应该是有效的。
这只是为了适应异步的工作方式。:)
现在,为您简化一些事情,有一个静态方法StorageFile.getFileFromApplicationUriAsync,您可以使用它直接进入包中的文件单次调用,而不是导航文件夹。这样您就可以加载创建XmlDocument,如下所示:
getXmlAsync: function () {
return StorageFile.getFileFromApplicationUriAsync("ms-appx:///books/book.xml").then((function (file) {
return Windows.Data.Xml.Dom.XmlDocument.loadFromFileAsync(file);
}).then(function (xmlDoc) {
return xmlDoc;
});
}请注意,这三个/是必需的;ms-appx:/是一个URI方案,用于app包内容。
还请注意承诺是如何被链接而不是嵌套的。这通常是一个更好的结构,它允许这样的函数返回一个承诺,这个承诺将通过链中的最后一个返回值来实现。然后,这可以与分配that.xmlDoc的早期代码一起使用,并且避免传递obj和回调(承诺是为了避免此类回调)。
总之,如果您的应用程序中有任何其他页面要导航,那么您确实希望加载这个XML文件,并为应用程序创建一次XmlDocument,而不是使用特定的页面。否则,您将在每次导航到页面时重新加载该文件。因此,您可以选择在应用程序启动时加载,而不是页面加载,并使用WinJS.Namespace.define创建存储xmlDoc的命名空间变量。因为该代码将在启动时加载,而启动屏幕是可见的,所以当第一个页面出现时,一切都应该准备就绪。一些需要考虑的事情。
无论如何,考虑到您是这个领域的新手,我建议您下载我的免费电子书“http://aka.ms/BrockschmidtBook2”,其中第三章详细介绍了应用程序启动、页面控制和承诺(当然是在第1章和第2章的更广泛介绍之后)。
https://stackoverflow.com/questions/29454611
复制相似问题