Windows Store Cordova App + WinJS:应用程序在启动时因JavaScript运行时错误而崩溃

时间:2014-12-21 23:09:06

标签: javascript cordova windows-store-apps winjs

我试图在Visual Studio 2015中学习如何在Cordova应用程序中使用WinJS。我目前正在努力获得Try WinJS website所述的基本列表视图。该应用程序在我的Android手机上成功启动,但是在我的Windows 8.1 PC上应用程序拒绝启动超过启动画面,给我错误0x800a138f - JavaScript runtime error: Unable to get property 'firstElementChild' of undefined or null reference

我当前的index.html如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>WinJSTest</title>

    <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
    <meta name="msapplication-tap-highlight" content="no" />

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

    <!-- WinJSTest CSS references -->
    <link href="css/index.css" rel="stylesheet" />
</head>
<body>
    <!-- Simple template for the ListView instantiation  -->
    <div class="smallListIconTextTemplate" data-win-control="WinJS.Binding.Template" style="display: none">
        <div class="smallListIconTextItem">
            <div class="smallListIconTextItem-Detail">
                <h4 data-win-bind="textContent: title"></h4>
                <h6 data-win-bind="textContent: text"></h6>
            </div>
        </div>
    </div>

    <!-- The declarative markup necesary for ListView instantiation -->
    <!-- Call WinJS.UI.processAll() in your initialization code -->
    <div id="listView"
         class="win-selectionstylefilled"
         data-win-control="WinJS.UI.ListView"
         data-win-options="{
            itemDataSource: Sample.ListView.data.dataSource,
            itemTemplate: select('.smallListIconTextTemplate'),
            selectionMode: 'single',
            tapBehavior: 'none',
            swipeBehavior: 'none',
            layout: { type: WinJS.UI.ListLayout }
    }">
    </div>

    <script src="js/WinJS.js"></script>

    <!-- Cordova reference, this is added to your app when it's built. -->
    <script src="cordova.js"></script>
    <script src="scripts/platformOverrides.js"></script>

    <script src="scripts/index.js"></script>
</body>
</html>

index.js也可以在下面找到:

// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkID=397704
// To debug code on page load in Ripple or on Android devices/emulators: launch your app, set breakpoints, 
// and then run "window.location.reload()" in the JavaScript Console.
(function () {
    "use strict";

    document.addEventListener( 'deviceready', onDeviceReady.bind( this ), false );

    function onDeviceReady() {
        // Handle the Cordova pause and resume events
        document.addEventListener( 'pause', onPause.bind( this ), false );
        document.addEventListener( 'resume', onResume.bind( this ), false );

        // TODO: Cordova has been loaded. Perform any initialization that requires Cordova here.
        var items = [];

        // Generate 2000 items
        for (var i = 0; i < 2000; i++) {
            items.push({ title: "Lorem Ipsum " + i, text: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s " });
        }

        var itemList = new WinJS.Binding.List(items);

        WinJS.Namespace.define("Sample.ListView", {
            data: itemList
        });

        WinJS.UI.processAll();

    };

    function onPause() {
        // TODO: This application has been suspended. Save application state here.
    };

    function onResume() {
        // TODO: This application has been reactivated. Restore application state here.
    };

} )();

希望有经验的人可以弄清楚我做错了什么:D

3 个答案:

答案 0 :(得分:1)

我会检查FirElement是什么,以及它是否为空。

从那里,你可以尝试找出第一个孩子是什么。我开始时就像一个疯狂的人一样使用console.log。

所以在这种情况下,我用以下内容启动应用程序:

<强>的console.log(对象)

然后

<强>的console.log(object.firstElementChild)

这个帖子也更详细地解释了它:Unable to get property 'options' of undefined or null reference

答案 1 :(得分:1)

将它放在你的启动代码中。有点时髦,但有效...

  1. 代码将追加到element.innerHTML属性setter,以便随后删除head / body。
  2. 代码将附加到WinJS.UI.processAll以随后清除所有头部/身体。
  3. 大部分代码都是从早期的海报(HeTh)中偷来的
  4. 这只应用于Windows应用商店。

    (function () {
    var winjs_drop_head_body = function (elem) {
    if (!elem.winControl)
        return;
    
        //var before = elem.innerHTML;
        var head = elem.firstElementChild;
        if (head.localName == 'head') {
            var body = head.nextElementSibling;
            while (body.firstElementChild) {
                elem.insertBefore(body.firstElementChild, head);
            }
            $(head).remove();
            $(body).remove();
        }
        //var after = elem.innerHTML;
    };
    
    var winjs_drop_head_body_all = function () {
        var heads = document.querySelectorAll('head');
        for (var h = 0; h < heads.length; h++) {
            var head = heads[h];
            if (head.parentNode.localName != 'html') {
                winjs_drop_head_body(<any>head.parentNode);
            }
        }
    };
    
    // drop the head after setting innerHTML
    WinJS.Utilities.ready(() => {
        var property = "innerHTML";
        var propertyDescriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, property);
        var getter = propertyDescriptor.get;
        var setter = propertyDescriptor.set;
        Object.defineProperty(HTMLElement.prototype, property, {
            get: getter,
            set: function (value) {
                var that = this;
                setter.call(that,value);
                winjs_drop_head_body(that);
            },
            enumerable: propertyDescriptor.enumerable,
            configurable: propertyDescriptor.configurable,
        });
    });
    
    var oldApplyAll = WinJS.UI.processAll;
    WinJS.UI.processAll = function (rootElement?, skipRoot?) {
        var oldVal = oldApplyAll(rootElement, skipRoot);
        oldVal.done(() => {
            winjs_drop_head_body_all();
        });
        return oldVal;
    }
    

    })();

答案 2 :(得分:0)

我遇到了同样的问题。我发现设置innerHTML没有按预期工作。内容始终设置为 <head></head><body>CONTENTS</body>如果内容包含标记。

即使您在调试器中的QuickWatch中手动设置它。

我认为这与商店应用中的安全限制有关。

我写了一个删除头部和身体元素的函数:

export function winjs_drop_head_body_all() {
        var heads = document.querySelectorAll('head');
        for (var h = 0; h < heads.length; h++) {
            var head = heads[h];
            if (head.parentNode.localName != 'html') {
                HMSMapUtil.winjs_drop_head_body(head.parentNode);
            }
        }
    }
    export function winjs_drop_head_body(elem) {
        var head = elem.firstElementChild
        if (head.localName == 'head') {
            var body = head.nextElementSibling;
            while (body.firstElementChild) {                
                elem.insertBefore(body.firstElementChild, head);
            }
        }
    }

我在winjs.js中winjs_drop_head_body_all()的每一行之后WinJS.UI.processAll().done(...)winjs_drop_head_body(elem)结束时调用.innerHTML =

这是一个修补程序,而不是一个真正的解决方案,但我还没有找到其他办法。

希望有人能找到更好的解决方案。