Каталог книг демо с помощью Knockout, jQuery и JSON с


Я знаю, что это много кода, но я не ищу какой-либо подробный обзор кода. Я просто надеюсь, что некоторые хорошие гуру JavaScript могут получать в десятки раз больше и предложить все необходимые советы по использованию ООП в JavaScript лучше, чем я.

Вот несколько проблемных вопросов, которые у меня есть, что не совсем , кажется, как будто они идеальны.

  • Страница 4 объектов, которые взаимодействуют друг с другом, просто плавая в середине нигде.

  • Объекты создаются путем вызова анонимных конструкторов, так как я не хочу им функций, которые используются только один раз ошивается.

  • Большинство конструкторов имеют в качестве первой линии ВАР я = это; поскольку это меняет контекст.

  • Есть около 4 или 5 глобальных полей и функций, которые не вписываются в любые объекты, так что я просто оставил их висеть в глобальном контексте.

Никаких указаний на использование объектно-ориентированного программирования в JavaScript будет высоко ценится.

    var mode = "dev";
    var currentSrc = [];
    var initialTitleValue = "   [Title]              ";
    var initialSelectedSubject = { id: -1, txt: "Books' Subjects" };
    var currentDisplay = "";


    $(function () {
        $("#header h1").text("Knockout / jQuery Book Demo");

        $("#tbTitleSearch").blur(function () {
            if (!$(this).val().trim()) {
                viewModel.titleValue(initialTitleValue);
                $(this).addClass("watermark");
            }
        });

        $("#tbTitleSearch").click(function () {
            if ($(this).val() == initialTitleValue) {
                viewModel.titleValue("");
                $(this).removeClass("watermark");
            }
        });

        $("#tbGenreSearch").click(function () {
            if (viewModel.selectedSubjects().length == 1 && viewModel.selectedSubjects()[0] == initialSelectedSubject) {
                $(this).removeClass("watermark");
                viewModel.selectedSubjects.removeAll();
            }
            openSubjectWindow();
        });

        viewModel.selectedSubjects.subscribe(function () {
            if (viewModel.selectedSubjects().length == 1 && viewModel.selectedSubjects()[0] == initialSelectedSubject)
                $("#tbGenreSearch").addClass("watermark");
        });

        $(window).bind('resize', function () {
            gridManager.sizeGrid();
        }).trigger('resize');

        $(".bookItem").live("mouseover", function () { $(this).addClass("highlight"); });
        $(".bookItem").live("mouseout", function () { $(this).removeClass("highlight"); });

        $(".smCovTempl").live("mouseover", function () { $(this).addClass("highlight"); });
        $(".smCovTempl").live("mouseout", function () { $(this).removeClass("highlight"); });

        $(".bookItem").live("click", function () { $(this).toggleClass("selected"); });

        $(".smCovTempl > img").live("click", function () { bookDetailsPopup($(this).data("id")); });

        theme("grid");

        ko.applyBindings(viewModel);
        dataLoader.loadSubjects();
    });


    var viewModel = new (function () {
        var me = this;

        this.rows = ko.observableArray([]);
        this.currentTemplate = ko.observable("bookTemplate1");
        this.displayTemplate = function () { return me.currentTemplate(); };

        this.subjects = ko.observableArray([]);
        this.selectedSubjects = ko.observableArray([initialSelectedSubject]);
        this.selectedSubjectNames = function () { return $(me.selectedSubjects()).map(function (i, o) { return o.txt; }).get(); };
        this.selectedSubjectIds = function () { return $(me.selectedSubjects()).map(function (i, o) { return o.id; }).get(); };
        this.manageSingleSelectedSubject = function () {
            if (me.selectedSubjects().length == 0)
                me.selectedSubjects.push(initialSelectedSubject);
        };

        this.readStatus = ko.observable(-1);
        this.includeChildSubjects = ko.observable(true);
        this.titleValue = ko.observable(initialTitleValue);

        this.animateOnEntry = true;
        this.templateItemRendered = function (element) {
            if (me.animateOnEntry)
                $(element).fadeIn();
        };
    })();

    var dataLoader = new (function () {
        var me = this;

        this.loadAllBooks = function () {
            dataManager.clearCurrentData();

            if (mode == 'dev')
                me.loadTestData();
            else
                post("../PublicServices/KnockoutService.asmx/ReadAll", '{}',
                    function (d) {
                        currentSrc = d.d;
                        dataManager.refreshCurrentData();
                    });
        };

        this.searchForBooks = function () {
            alert(viewModel.titleValue());
        };

        this.loadSubjects = function () {
            viewModel.subjects([{ name: "Sub1", id: 1, children: [] },
                { name: "Sub2", id: 2, children: [{ name: "Sub2a", id: 4, children: [{ name: "Sub2a1", id: 6, children: []}] }, { name: "Sub2b", id: 5, children: []}] },
                { name: "Sub3", id: 3, children: []}]);

            $("#jsTreeTarget").jstree({
                "themes": {
                    "theme": "default",
                    "dots": false,
                    "icons": false
                },
                "checkbox": { "two_state": true },
                "plugins": ["themes", "html_data", "checkbox", "ui"]
            });

            $("#jsTreeTarget").bind("change_state.jstree", function () {
                viewModel.selectedSubjects(
                    $("li.jstree-checked > a", "#jsTreeTarget").map(function (i, o) { return { txt: $(o).text(), id: $(o).data("id") }; }).get());
            });
        };

        this.loadTestData = function () {
            currentSrc = [{ id: 1, title: "Mr. Jefferson's Hammer.  William Henry Harrison and the foundation of Indian Policy", authors: ["a1", "a2"], subjects: ["sub1", "sub2"], smImg: 1, medImg: 1, pub: "Oxford", pubYear: 2004, pages: 250, asin: "a", isRead: false },
                { id: 1, title: "Founding Brothers", authors: ["a1", "a2"], subjects: ["sub1", "sub2"], smImg: 1, medImg: 1, pub: "Oxford", pubYear: 2004, pages: 250, asin: "a", isRead: false },
                { id: 1, title: "American Creation", authors: ["a1", "a2"], subjects: ["sub1", "sub2"], smImg: 1, medImg: 1, pub: "Oxford", pubYear: 2004, pages: 250, asin: "a", isRead: false}];

            for (var i = 0; i < 50; i++)
                currentSrc.push({ id: 1, title: "American Creation", authors: ["a1", "a2"], subjects: ["sub1", "sub2"], smImg: 1, medImg: 1, pub: "Oxford", pubYear: 2004, pages: 250, asin: "a", isRead: false });
            dataManager.refreshCurrentData();
        };
    })();


    var dataManager = new (function () {
        var me = this;
        this.templateDataNotLoaded = false;

        this.refreshCurrentData = function () {
            if (currentDisplay == "grid")
                gridManager.reloadGrid();
            else {
                me.templateDataNotLoaded = false;
                me.cascadeData();
            }
        };

        this.cascadeData = function (index) {
            me.animateOnEntry = true;

            if (!index)
                index = 0;

            if (index == currentSrc.length - 1)
                return;

            if (index >= 30) {
                viewModel.animateOnEntry = false;
                for (var i = index; i < currentSrc.length; i++)
                    viewModel.rows.push(currentSrc[i]);
            } else {
                viewModel.rows.push(currentSrc[index]);
                setTimeout(function () { me.cascadeData(index + 1); }, 60);
            }
        };

        this.dumpDataWithoutCascade = function () {
            me.templateDataNotLoaded = false;
            viewModel.rows(currentSrc);
        };

        this.clearCurrentData = function () {
            currentSrc.length = 0;
            viewModel.rows.removeAll();
            gridManager.unloadGrid();
            me.templateDataNotLoaded = true;
        };
    })();

    var gridManager = new (function () {
        var me = this;

        this.gridDataNotLoaded = false;

        this.reloadGrid = function () {
            me.gridDataNotLoaded = false;

            $("#jqGridElement").jqGrid({
                datastr: { rows: currentSrc },
                jsonReader: { repeatitems: false },
                datatype: "jsonstring",
                colNames: ['', 'Title', 'Pages', 'Publisher', 'Authors', "Subjects"],
                colModel: [
                    { name: 'smImg', index: 'smImg', width: 65, fixed: true, sortable: false, formatter: gridCoverFormatter, title: false },
                    { name: 'title', width: 250, formatter: titleFormatter, title: false },
                    { name: 'pages', width: 80, fixed: true, align: 'center', title: false },
                    { name: 'pub', index: 'pub', width: 100, formatter: publisherFormatter, title: false },
                    { name: 'authors', width: 100, formatter: authorFormatter, sortable: false, title: false },
                    { name: 'subjects', width: 100, formatter: subjectFormatter, sortable: false, title: false}],
                height: 'auto',
                gridview: true,

                rowNum: -1
            });

            me.sizeGrid();
        };

        this.unloadGrid = function () {
            me.gridDataNotLoaded = true;
            $("#jqGridElement").jqGrid('GridUnload');
        };

        this.sizeGrid = function () {
            var targetContainer = "#contentParent";
            var gridID = "#jqGridElement";

            var width = $(targetContainer).width();
            var height = $(targetContainer).height();

            width = width - 20; // Fudge factor to prevent horizontal scrollbars
            height = height - 40;

            if (width > 0) //&& Math.abs(width - $(gridID).width()) > 5) {
                $(gridID).jqGrid('setGridWidth', width);

            if (height > 0) // && Math.abs(height - jQuery(gridID).height()) > 5)
                $(gridID).jqGrid('setGridHeight', height);
        };

        function gridCoverFormatter(cellvalue, options, rowObject) {
            return "<div style='height:85px;'><img src='../Books/Covers/Small/" + cellvalue + ".jpg' style='margin-top:5px;' /></div>";
        }

        function titleFormatter(cellvalue, options, rowObject) {
            return "<div title='" + cellvalue.toString().replace("'", "") + "'>" + cellvalue + "</div><a href='http://www.google.com?a=" + rowObject.asin + "' target='_blank'><img src='../Img/Misc/Amazon.png'</a>";
        }

        function publisherFormatter(cellvalue, options, rowObject) {
            var formattedVal = cellvalue.toString().replace("'", "");
            if ((formattedVal != "") && (rowObject.pubYear))
                formattedVal += " - " + rowObject.pubYear;

            return "<div title='" + formattedVal + "'>" + formattedVal + "</div>";
        }

        function authorFormatter(cellvalue, options, rowObject) {
            var result = "";
            for (var i = 0; i < cellvalue.length; i++)
                result += "<li><span>" + cellvalue[i] + "</span></li>";
            return "<ul class='grAUL'>" + result + "</ul>";
        }

        function subjectFormatter(cellvalue, options, rowObject) {
            var result = "";
            for (var i = 0; i < cellvalue.length; i++)
                result += "<li title='" + cellvalue[i] + "'>" + "Oxford - 2004" + "</li>";
            return "<ul class='grSUL'>" + result + "</ul>";
        }
    })();


    function theme(value) {
        if (value == "grid") {
            manageDisplay("#gridParent", "#templateElement", 'emptyBookTemplate');
            if (gridManager.gridDataNotLoaded)
                gridManager.reloadGrid();
        } else {
            manageDisplay("#templateElement", "#gridParent", value);
            if (dataManager.templateDataNotLoaded)
                dataManager.dumpDataWithoutCascade();
        }
        currentDisplay = value;
    }

    function manageDisplay(showID, hideID, newTemplate) {
        $(showID).show();
        $(hideID).hide();
        viewModel.currentTemplate(newTemplate);
    }


    function bookDetailsPopup(id) {
        var divToPopup = $("#bookInfoPopup").clone();
        $(divToPopup).dialog({ width: 400, height: 400 });
        $.get("PartialBookInfo.aspx?id=" + id, function (response) {
            $(".popupContent", divToPopup).html(response);
            $(".tabDiv", divToPopup).tabs();
            $(".loadingMsg", divToPopup).remove();
        });
    }

    function openSubjectWindow() {
        $("#treeWrapper").dialog({
            title: "Header",
            close: function () { viewModel.manageSingleSelectedSubject(); }
        });
    }

    function post(targetURL, dataInput, success) {
        $.ajax({
            url: targetURL,
            type: "POST",
            contentType: "application/json; charset=utf-8",
            data: dataInput,
            dataType: "json",
            success: success,
            async: true
        });
    }


Комментарии
1 ответ

Если вы хотите быть безопаснее, обернуть все это в выполнено закрытие (функция () { /* код */ })().

Я не думаю, что вам нужно ВАР я = это так на беглый взгляд все функции вызываются в случаях, что позволит сделать сайта этого экземпляра объекта.

Нет ничего плохого в использовании анонимных конструкторов, насколько я знаю, но, наверное, было бы лучше использовать {} , чтобы создать свои объекты и падение нового сайта. Это позволит вам сэкономить поиск ссылки, как

var gridManager =  (function () {

function gridCoverFormatter(cellvalue, options, rowObject) {
return "<div style='height:85px;'><img src='../Books/Covers/Small/" + cellvalue + ".jpg' style='margin-top:5px;' /></div>";
}

function titleFormatter(cellvalue, options, rowObject) {
return "<div title='" + cellvalue.toString().replace("'", "") + "'>" + cellvalue + "</div><a href='http://www.google.com?a=" + rowObject.asin + "' target='_blank'><img src='../Img/Misc/Amazon.png'</a>";
}

function publisherFormatter(cellvalue, options, rowObject) {
var formattedVal = cellvalue.toString().replace("'", "");
if ((formattedVal != "") && (rowObject.pubYear))
formattedVal += " - " + rowObject.pubYear;

return "<div title='" + formattedVal + "'>" + formattedVal + "</div>";
}

function authorFormatter(cellvalue, options, rowObject) {
var result = "";
for (var i = 0; i < cellvalue.length; i++)
result += "<li><span>" + cellvalue[i] + "</span></li>";
return "<ul class='grAUL'>" + result + "</ul>";
}

function subjectFormatter(cellvalue, options, rowObject) {
var result = "";
for (var i = 0; i < cellvalue.length; i++)
result += "<li title='" + cellvalue[i] + "'>" + "Oxford - 2004" + "</li>";
return "<ul class='grSUL'>" + result + "</ul>";
}

return {
"gridDataNotLoaded": falsse,

"reloadGrid": function () {
me.gridDataNotLoaded = false;

$("#jqGridElement").jqGrid({
datastr: { rows: currentSrc },
jsonReader: { repeatitems: false },
datatype: "jsonstring",
colNames: ['', 'Title', 'Pages', 'Publisher', 'Authors', "Subjects"],
colModel: [
{ name: 'smImg', index: 'smImg', width: 65, fixed: true, sortable: false, formatter: gridCoverFormatter, title: false },
{ name: 'title', width: 250, formatter: titleFormatter, title: false },
{ name: 'pages', width: 80, fixed: true, align: 'center', title: false },
{ name: 'pub', index: 'pub', width: 100, formatter: publisherFormatter, title: false },
{ name: 'authors', width: 100, formatter: authorFormatter, sortable: false, title: false },
{ name: 'subjects', width: 100, formatter: subjectFormatter, sortable: false, title: false}],
height: 'auto',
gridview: true,

rowNum: -1
});

this.sizeGrid();
},

"unloadGrid": function () {
this.gridDataNotLoaded = true;
$("#jqGridElement").jqGrid('GridUnload');
},

"sizeGrid": function () {
var targetContainer = "#contentParent";
var gridID = "#jqGridElement";

var width = $(targetContainer).width();
var height = $(targetContainer).height();

width = width - 20; // Fudge factor to prevent horizontal scrollbars
height = height - 40;

if (width > 0) //&& Math.abs(width - $(gridID).width()) > 5) {
$(gridID).jqGrid('setGridWidth', width);

if (height > 0) // && Math.abs(height - jQuery(gridID).height()) > 5)
$(gridID).jqGrid('setGridHeight', height);
}
};
})();

Но в целом, на JavaScript-очень гибкий язык, когда дело доходит до объектов. Вы можете заставить классовой структуры или использовать делегирование прототипирования. Он идет дальше с узорами модуля и расширения объектов. Выбор остается за вами.

1
ответ дан 11 сентября 2011 в 02:09 Источник Поделиться