0

我正在尝试创建自己的各种 jQuery 小部件。我已经编写了所有的 HTML 和 jQuery,我正在尝试使用以下方法将其动态添加到页面中:

<div class='searchbar'></div>

该小部件使用 Knockout.js,以及我自己编写的大量代码。我遇到的问题 [我怀疑] 涉及我的脚本的加载顺序。

这是我得到的错误:

Timestamp: 11/20/2012 9:26:13 AM
Error: Error: Unable to parse binding attribute.
Message: SyntaxError: syntax error;
Attribute value: value: query, valueUpdate: 
Source File: http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-1.2.1.js
Line: 44

如果我注释掉 Knockout 绑定块,一切正常(减去下拉列表的值)。不知道为什么它没有通过这段代码。

我的 jQuery 在下面,但是它目前正在做的实时版本是可用的HERE是一个工作版本,无需尝试动态加载所有内容,只是为了让您知道它应该是什么样子。

(function() {

    var jQuery;

    /******** Load jQuery if not present *********/
    if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.8.0') {
        var script_tag = document.createElement('script');
        script_tag.setAttribute("type","text/javascript");
        script_tag.setAttribute("src",
            "http://code.jquery.com/jquery-1.8.0.min.js");
        if (script_tag.readyState) {
          script_tag.onreadystatechange = function () { // For old versions of IE
              if (this.readyState == 'complete' || this.readyState == 'loaded') {
                  scriptLoadHandler();
              }
          };
        } else {
          script_tag.onload = scriptLoadHandler;
        }
        (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
    } else {
        jQuery = window.jQuery;
        main();
    }

    /******** Called once jQuery has loaded ******/
    function scriptLoadHandler() {
        jQuery = window.jQuery.noConflict(true);
        main(); 
    }

    /******** Our main function ********/
    function main() { 
        jQuery(document).ready(function($) {

            $("head").append("<link href='style.css' rel='stylesheet' type='text/css' />");         
            $.getScript("http://knockoutjs.com/js/jquery.tmpl.js", function(){});
            $.getScript("http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-1.2.1.js", function(){});

            $(".searchBox").append("<div id='refine'>Creator</div>");
            $(".searchBox").append("<input class='inline' placeholder='Search...' size='30' type='text' id='search' data-bind='value: query, valueUpdate: 'keyup'' autocomplete='off' />");
            $(".searchBox").append("<div id='submit'>Search</div>");
            $(".searchBox").append("<div id='refineDropdown'><ul id='refineList'></ul></div>");
            $(".searchBox").append("<div id='dropdown'><ul data-bind=\"template: { name:'obj', foreach:objects }, click: function(){ $('.listObjItem').on('click', function(){ $('#search').val($(this).text()); $('#dropdown').hide(); $('#search').focus();});}\"></ul></div>");
            $(".searchBox").append("<script type='text/html' id='obj'><li class='listObjItem'><span data-bind='text: name'></span>&nbsp;in&nbsp;<strong data-bind='text: type'></strong></li></script>");

            /* Begin Knockout Bindings */

            var objects = [
              {name:"Pacers Game",              type:"Activities"},
              {name:"Colts Game",               type:"Activities"},
              {name:"Ice Game",                 type:"Activities"},
              {name:"Indians Game",             type:"Activities"},
              {name:"Fever Game",               type:"Activities"},
              {name:"Purdue Game",              type:"Activities"},
              {name:"Campaign Posters",         type:"Projects"},
              {name:"Campaign Media",           type:"Projects"},
              {name:"Event Booking",            type:"Projects"},
              {name:"New Product Seminar",      type:"Projects"},
              {name:"State Fair",               type:"Projects"},
              {name:"Draft Designs",            type:"Tasks"},
              {name:"Design Posters",           type:"Tasks"},
              {name:"Review Designs",           type:"Tasks"},
              {name:"Book Venue",               type:"Tasks"},
              {name:"Decorate ICC",             type:"Tasks"},
              {name:"Book Live Music",          type:"Tasks"},
              {name:"Arrange for DJ Payment",   type:"Tasks"},
              {name:"Event Cleanup",            type:"Tasks"}
            ];

            var viewModel = { query: ko.observable('') };

            viewModel.objects = ko.dependentObservable(function() {
                var search = this.query().toLowerCase();
                return ko.utils.arrayFilter(objects, function(obj) {
                    return obj.name.toLowerCase().indexOf(search) >= 0;
                });
            }, viewModel);

            ko.applyBindings(viewModel);

            /* End Knockout Bindings */

            var refine = ["All", "ID", "Creator", "Name", "Description", "Last Modified"];

            refine = refine.sort();
            for (var i = 0; i < refine.length; i++)
                $('#refineList').append('<li>' + refine[i] + '</li>');

            testLength();
            $("#dropdown").hide();
            $("#refineDropdown").hide();

            if($.browser.chrome) {
                $('#search').css('height','26px');
                $('#search').css('padding','0px 5px 0px 5px');
                $('#refine').css('margin-right','-3px');
            }
            else if($.browser.mozilla) {
                $('#search').css('height','25px');
                $('#search').css('padding','0px 5px 0px 5px');
                $('#search').css('margin-top','-6px');
                $('#refine').css('margin-right','-1px');
            }
            else if($.browser.msie) {
                $('#search').css('height','22px');
                $('#search').css('padding','4px 5px 0px 5px');
            }

            var $hidden = $('#hidden');
            $("input").keyup(function(e) {
                testLength();
                $('#refine').removeClass('refineClicked');
                $('#refineDropdown').hide();
                if (this.value.length) {
                    var that = this;
                    $("#dropdown li").each(function() {
                        if ($(this).html().toLowerCase().indexOf(that.value.toLowerCase()) == -1) $(this).appendTo($hidden);
                    });
                    $('#hidden li').each(function() {
                        if ($(this).html().toLowerCase().indexOf(that.value.toLowerCase()) !== -1) $(this).appendTo('#list');
                    });
                    $("#search").css('border-bottom-right-radius', '0px');
                    $("#dropdown").show();
                }
                else {
                    $("#dropdown").hide();
                }
                if (e.which !== 40 && e.which !== 38) {
                    $('#dropdown li,#hidden li').each(function() {
                        $(this).removeClass('selected');
                    });
                    liSelected = null;
                }
            });

            $('#dropdown li').click(function() {
                $('#search').val($(this).text());
                $('#search').focus();
                $("#dropdown").hide();
            });

            var li = $('li');
            var liSelected;

            $('input').keydown(function(e) {
                liSelected = $('#dropdown .selected');

                if (e.which === 40) { // down-arrow
                    if (liSelected.length) {
                        var next = liSelected.next();

                        if (next.length) {
                            liSelected.removeClass('selected');
                            liSelected = next.addClass('selected');
                        }
                    }
                    else {
                        liSelected = $('#dropdown li').eq(0).addClass('selected');
                    }
                }
                else if (e.which === 38) { // up-arrow
                    if (liSelected.length) {
                        var prev = liSelected.prev();

                        if (prev.length) {
                            liSelected.removeClass('selected');
                            liSelected = prev.addClass('selected');
                        }
                        else {
                            liSelected = $('#dropdown li').eq(-1).addClass('selected');
                        }
                    }
                    else {
                        liSelected = li.last().addClass('selected');
                    }
                }
                else if (e.which === 13) {
                    $('#search').val(liSelected.text());
                    $("#dropdown").hide()
                    $('#search').blur();
                }
            });

            $('#refine').click(function() {
                $("#dropdown").hide();
                if (!$('#refine').hasClass('refineClicked')) {
                    $('#refine').addClass('refineClicked');
                    $('#refineDropdown').show();
                }
                else {
                    $('#refine').removeClass('refineClicked');
                    $('#refineDropdown').hide();
                }
            });

            $('#refineDropdown li').click(function() {
                var tmp = $('#refine').width();
                $('#refine').html($(this).text());
                $('#refine').removeClass('refineClicked');
                $("#refineDropdown").hide();
                testLength();
                $('#search').css('width', $('#search').width() + (tmp - $('#refine').width()));
            });

            $('#submit').click(function() {
                alert('Searching for ' + $('#search').val() + '...');
            }); 

            function testLength() {
                if ($('#refine').text().length > 7) {
                    $('#refine').html($('#refine').text().substring(0, 6) + "...");
                }
                $('#dropdown').css('width', $('#search').width() + 4);

                if($.browser.chrome)
                    $('#dropdown').css('margin-left', $('#refine').width() + 11);
                else
                    $('#dropdown').css('margin-left', $('#refine').width() + 13);
            }
        });
    }
}());
4

2 回答 2

0

您应该尝试使用 AMD 之类的 require.js 来按顺序加载脚本。

于 2013-08-04T20:05:05.547 回答
0

我想出了一个解决办法。我没有在脚本中动态加载,而是将它们直接放入我的 HTML 页面的头部。我可能会在我的脚本文件中添加一个检查以查看是否加载了外部库,但我认为这最终会成为很多额外的、不必要的工作。

对于此问题的未来访问者,以下脚本的顺序对于使用 Knockout 的任何操作都是绝对必要的。此外,值得注意的是 jQuery tmpl 加载速度比 Knockout.js 慢。当我尝试动态加载它们时,我的函数会在外部库完成加载时触发。即使 tmpl 首先列出,Knockout 总是首先加载(除非浏览器首先处理最后一个警报,然后回滚到以前的警报......如果这是错误的,请纠正我)。

    <head>
        <title>Search Prototype</title>
        <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
        <script type="text/javascript" src="https://raw.github.com/jquery/jquery-tmpl/master/jquery.tmpl.js"></script>
        <script type="text/javascript" src="http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-2.2.0.js"></script>
        <script type="text/javascript" src="search.js"></script>
    </head>
于 2012-11-20T15:37:29.893 回答