1

我是 asp.net mvc4 和 knockoutjs 的新手,需要帮助了解视图的工作原理。

  1. 我在共享文件夹中有一个 _Layout.vbhtml,它是项目中所有页面的“主”页面。

  2. 我有 AccountController、HomeController 和 GrowerController

  3. 我在 Views 文件夹中有 GrowerController 的 Grower 文件夹。像往常一样,索引是默认视图。

  4. 在 Views/Grower/Index 中,我有一个从服务器检索数据的 knoockout ViewModel。

  5. 现在,当我转到 Home/Index 等其他视图时,我在 Firebug 的控制台中看到,即使我不在创建淘汰 ViewModel 的视图上,它也会发出这些调用以从服务器获取数据。

我很困扰。发生这种情况是因为我对所有页面都使用了 _layout.vbhtml 吗?我究竟做错了什么?

编辑: * _Layout.vbhtml*

    <!DOCTYPE html>
    <html lang="en">
      <head>
       <meta charset="utf-8" />
       <title>@ViewData("Title")</title>
       <meta name="viewport" content="width=device-width" />
       <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
       <link href="http://code.jquery.com/mobile/1.1.1/jquery.mobile-1.1.1.min.css" rel="stylesheet" type="text/css" />

        @* Javascrips files *@
        <script src="@Url.Content("~/Scripts/knockout-2.1.0.js")" type="text/javascript"></script>
        <script src="@Url.Content("http://code.jquery.com/jquery-1.7.1.min.js")" type="text/javascript"></script>
        <script src="@Url.Content("http://code.jquery.com/mobile/1.1.1/jquery.mobile-1.1.1.min.js")" type="text/javascript"></script>
        <script src="@Url.Content("~/Scripts/custom.js")" type="text/javascript"></script>


        <!-- Custom stylesheet overriding styles -->
        @If Request.QueryString("pr") = "dow" or ViewData("pr") = "dow" Then
         @<link rel="stylesheet" href="@Url.Content("~/Content/CustomDow.css")" />
        Else
         @<link rel="stylesheet" href="@Url.Content("~/Content/Custom.css")" />
        End If
     </head>
     <body>
       <div data-role="page" data-theme="b">
        <div data-role="header">
            @If IsSectionDefined("Header") Then
                @RenderSection("Header")
            Else
                @<h1>@ViewData("Title")</h1>
                @Html.Partial("_LoginPartial")
            End If
        </div>
        <div data-role="content">
            @RenderBody()
        </div>
    </div>

    @RenderSection("scripts", required:=False)
</body>

种植者/索引.vbhtml

    @Code
      ViewData("Title") = "Select a Grower/Branch"
    End Code

    @section scripts
      <script type="text/javascript">

      function SuperViewModel() {

        //====== GrowerInfo =======
        var self = this;
        self.GrowerName = ko.observable();
        self.GrowerCompany = ko.observable();
        self.GrowerAddress = ko.observable();
        self.ShowGrowerCompany = ko.observable();
        self.GrowerID = ko.observable();

        self.updateGrowerInfo = function () {
          $.getJSON("GetGrower", function (allData) {
          self.GrowerName(allData.Name);
          self.GrowerCompany(allData.CompanyName);
          self.GrowerAddress(allData.Address);
          self.ShowGrowerCompany(allData.ShowCompany);
          self.GrowerID(allData.ID);
         });
        };

        //Load initial state from server and populate viewmodel
        self.updateGrowerInfo();
        //========= End GrowerInfo ==========

         if ($("#hfFlag").val() == "1") {
          //========= BranchInfo ==========
          self.BranchName = ko.observable();
          self.Company = ko.observable();
          self.Address = ko.observable();
          self.ID = ko.observable();

          //Load initial state from server and populate viewmodel
          self.updateBranchInfo = function () {
           $.getJSON("GetBranch", function (allData) {
            self.BranchName(allData.Name);
            self.Company(allData.CompanyName);
            self.Address(allData.Address);
            self.ID(allData.ID);
          });
        };

        self.updateBranchInfo();
        //=========== End BranchInfo ==============
      }


      //=============== GrowerList ===============
      var MyGrower = function (data) {
       this.growerId = ko.observable(data.GrowerId);
       this.growerName = ko.observable(data.GrowerName);
     };

      self.growers = ko.observableArray([]);

      self.updateGrowers = function () {
        //refresh listview
        $("#ulGrowerList").listview();
        $("#ulGrowerList").listview("refresh");

      $.getJSON("GetGrowers", function (allData) {
        var mappedGrowers = $.map(allData, function (item) { return new MyGrower(item) });
        self.growers(mappedGrowers);


        });
      };

      self.setSelectedClassToGrowerList = function (item, event) {

        $(ulGrowerList).closest('ul').find('a').removeClass('highlight');
        $(ulGrowerList).closest('ul').find('.selected').remove();

        $(event.target).toggleClass("highlight");
        if ($(event.target).hasClass("highlight")) {
          $(event.target).append("<span class='selected'>Selected</span>");

          replaceByValue('GrowerID', event.target.id);
          postjsonToServerNow("grower");

          //update GrowerInfo 
          $.getJSON("GetGrower", function (allData) {
            self.GrowerName(allData.Name);
            self.GrowerCompany(allData.CompanyName);
            self.GrowerAddress(allData.Address);
            self.ShowGrowerCompany(allData.ShowCompany);
            self.GrowerID(allData.ID);
          });

        } else {
          $(event.target).find(".selected").remove();
        }
      };



      self.setSelectedClassToBranchList = function (item, event) {

        $(ulBranchList).closest('ul').find('a').removeClass('highlight');
        $(ulBranchList).closest('ul').find('.selected').remove();

        $(event.target).toggleClass("highlight");

        if ($(event.target).hasClass("highlight")) {
          $(event.target).append("<span class='selected'>Selected</span>");

          replaceByValue('BranchID', event.target.id);
          postjsonToServerNow("branch");
        } else {
          $(event.target).find(".selected").remove();
        }

      };



      //Load initial state from server and populate viewmodel
      self.updateGrowers();

      //============ End GrowerList =============
    }

    //============= End ViewModel Section ====================//


      $(document).bind('pageinit', function () {
        //enable ko
        ko.applyBindings(new SuperViewModel());


        $("#divBranchList").hide();

        //show hide lists
        $("#btnGrower").click(function () {
        $("#divGrowerList").show();
        $("#divBranchList").hide();
       });

       $("#btnBranch").click(function () {
         $("#divBranchList").show();
         $("#divGrowerList").hide();
       });

      });
    </script>
    End Section




    <table class="maintable" id="maintable">
      <tr>
        <td class="left">
          <div id="GrowerInfo">
            <strong>Grower</strong><br />
            <a data-role="button" data-theme="e" id="btnGrower" data-bind="click: updateGrowers">
              <h3>
               <span data-bind="text: GrowerName"></span>
              </h3>
              <span data-bind="text:GrowerCompany, visible: ShowGrowerCompany" class="block"></span><span data-bind="text: GrowerAddress">
              </span>
              <br />
              <span data-bind="text: GrowerID"></span>
            </a>
          </div>
          @If ViewData("IsDealer") Then
            @<div id="BranchInfo">
              <strong>Branch</strong> <a data-role="button" data-theme="e" id="btnBranch">
                <h3>
                  <span data-bind="text: BranchName"></span>
                </h3>
                <span data-bind="text: Company"></span>
                <br />
                <span data-bind="text: Address"></span>
                <br />
                <span data-bind="text: ID"></span></a>
            </div>
          End If
        </td>
        <td class="splitline">
        </td>
        <td class="right">
          <div class="content-right">
            <div id="divGrowerList" style="overflow: auto; height: 450px; padding: 10px;">

            <p>Total growers: <span data-bind="text: growers().length">&nbsp;</span></p>

               <ul data-inset="true" data-filter="true" data-bind="foreach: growers" data-role="listview" id="ulGrowerList">
                  <li><a data-bind="click: $parent.setSelectedClassToGrowerList, attr: {id: growerId}"><span data-bind="text: growerName, attr: {id: growerId}, click: $parent.setSelectedClassToGrowerList" /></a></li>
              </ul>

              <textarea name="growers" rows="10" data-bind="value: ko.toJSON(growers)"></textarea>

            </div>
            <div id="divBranchList">
              @If ViewData("IsDealer") Then
                @Html.Action("MyBranchList2")
              End If
            </div>
            @If ViewData("IsDealer") Then
              @<input type="hidden" id="hfFlag" value="1" />
            Else
              @<input type="hidden" id="hfFlag" value="0" />
            End If
          </div>
        </td>
      </tr>
    </table>
4

2 回答 2

0

_layout您已经在页面中定义了您的 Knockout ViewModel 。

如果您打算在所有页面上使用此视图模型,这很好,但听起来您不想这样做。将其移动到特定的操作视图中以将其隔离。

在上面对 Sethi 的评论中,您提到 javascript 在您这样做时不起作用……这可能是因为您在布局和视图中都放置了脚本标签。我敢打赌,您正在尝试在加载 knockout.js 之前构建视图模型。

好习惯:

在您的布局中,将您的脚本标签放在页面底部,就在</body>关闭标签之前...关闭之前的最后一个标签应该是您RenderSection()设置的调用。

现在,您可以在视图中的任何位置定义此脚本部分并确保它将在您的框架脚本之后发生 - 例如。jQuery、Knockout 等。

另外,请记住,使用 jQuery 几乎总是最好使用它$.ready()来确保您的脚本仅在 DOM 加载后运行。

于 2012-09-28T20:14:22.630 回答
0

script没有看到您的 _Layout.vbhtml 我不能肯定地说,但是由于您在每个页面上都运行了 javascript,因此您的 _Layout.vbhtml 上可能有您的标签

所以,把它移到你的 Index.vbhtml 中,或者把它放在<head>标签中,@RenderSection("Scripts")在你的 Layout.vbhtml 中使用 a 并在你的视图中使用:

@Section "Scripts"

@<script>
    // write JS here or reference a file using the src attribute
</script>

End Section

这会将您的 Layout.vbhtml 之间的所有内容放置@Section "SectionName"End Section@RenderSection("Scripts")

编辑:

从您对 one.beat.consumer 的评论中,我想我看到了您的问题。但请理解我仍在猜测,因为我还没有看到你的代码 -一个大问题,因为你没有提到你正在使用 jQuery Mobile

常规 MVC4 Web 应用程序和 jQuery Mobile 应用程序之间存在重大差异。

一个是:使用 jQM,您总是在同一个页面上——您通过 ajax 从服务器加载页面,然后将其剥离为<div data-role="page">...</div>. 这解释了为什么如果您将特定页面的脚本放在它们的<head>部分中,jQM 会忽略它。唯一<head>未被忽略的部分是加载的原始页面,它并不总是您的主页

因此,要为特定页面加载脚本,您不能<head>使用 MVC 部分将其放入元素中。您需要在<div data-role="page">. 虽然如果你正在缓存你的页面,它只会触发一次,pageshow如果你希望它再次触发,你可能需要绑定到它(也许刷新视图模型)。

最后,

你说你在你的pageinit处理程序中应用你的视图模型。每当从服务器获取页面并注入 DOM 时都会调用此方法。

如果您想让您的 js 不在视图中,您可以在 _Layout.vbhtml 中引用站点范围的 js 文件 (custom.js)<head>并使用:

$(document).on('pageinit', '#PageId', function(event) {
    /* do viewmodel stuff here */
});

每当一个<div data-role="page">withid="PageId"被获取并注入到 DOM 中时,这将运行。您可以在此处使用任何选择器,因此.require-vm可用于在class="require-vm"注入页面时触发。

于 2012-09-28T12:12:56.930 回答