<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      Knockout應用開發指南 第九章:高級應用舉例

      2011-12-02 15:04  湯姆大叔  閱讀(24595)  評論(11)    收藏  舉報

      1   Contacts editor

      這個例子和微軟為演示jQuery Data Linking Proposal例子提供的例子一樣的提供的,我們可以看看Knockout實現是難了還是容易了。

      代碼量的多少不重要(盡快Knockout 的實現很簡潔),重要的看起來是否容易理解且可讀。查看HTML源代碼,看看如何實現的view model以及綁定的。

       

       

      代碼: View

      View Code
      <h2>Contacts</h2>
      <div id="contactsList" data-bind='template: "contactsListTemplate"'>
      </div>
      <script type="text/html" id="contactsListTemplate">
      <table class='contactsEditor'>
      <tr>
      <th>First name</th>
      <th>Last name</th>
      <th>Phone numbers</th>
      </tr>

      {{each(i, contact) contacts()}}
      <tr>
      <td>
      <input data-bind="value: firstName"/>
      <div><a href="#" data-bind="click: function() { viewModel.removeContact(contact) }">Delete</a></div>
      </td>
      <td><input data-bind="value: lastName"/></td>
      <td>
      <table>
      {{each(i, phone) phones}}
      <tr>
      <td><input data-bind="value: type"/></td>
      <td><input data-bind="value: number"/></td>
      <td><a href="#" data-bind="click: function() { viewModel.removePhone(contact, phone) }">Delete</a></td>
      </tr>
      {{/each}}
      </table>
      <a href="#" data-bind="click: function() { viewModel.addPhone(contact) }">Add number</a>
      </td>
      </tr>
      {{/each}}
      </table>
      </script>
      <p>
      <button data-bind="click: addContact">
      Add a contact</button>
      <button data-bind="click: save, enable: contacts().length > 0">
      Save to JSON</button>
      </p>
      <textarea data-bind="value: lastSavedJson" rows="5" cols="60" disabled="disabled"> </textarea>


      代碼: View model

      View Code
      var viewModel = {
      contacts: new ko.observableArray([
      { firstName: "Danny", lastName: "LaRusso", phones: [
      { type: "Mobile", number: "(555) 121-2121" },
      { type: "Home", number: "(555) 123-4567"}]
      },

      { firstName: "Sensei", lastName: "Miyagi", phones: [
      { type: "Mobile", number: "(555) 444-2222" },
      { type: "Home", number: "(555) 999-1212"}]
      }
      ]),

      addContact: function () {
      viewModel.contacts.push({ firstName: "", lastName: "", phones: [] });
      },

      removeContact: function (contact) {
      viewModel.contacts.remove(contact);
      },

      addPhone: function (contact) {
      contact.phones.push({ type: "", number: "" });
      viewModel.contacts.valueHasMutated();
      },

      removePhone: function (contact, phone) {
      ko.utils.arrayRemoveItem(contact.phones, phone);
      viewModel.contacts.valueHasMutated();
      },

      save: function () {
      viewModel.lastSavedJson(JSON.stringify(viewModel.contacts(), null, 2));
      },

      lastSavedJson: new ko.observable("")
      };

      ko.applyBindings(viewModel);

       

      2   Editable grid

      該例是使用“foreach”綁定為數組里的每一項來render到 template上。好處(相對于模板內部使用for循環)是當你添加或者刪除item項的時候,Knockout不需要重新render – 只需要render新的item項。就是說UI上其它控件的狀態(比如驗證狀態)不會丟失。

      如何一步一步構建這個例子并集成ASP.NET MVC,請參閱此貼

       

       

      代碼: View

      View Code
      <form action="/someServerSideHandler">
      <p>
      You have asked for <span data-bind="text: gifts().length">&nbsp;</span> gift(s)</p>
      <table data-bind="visible: gifts().length > 0">
      <thead>
      <tr>
      <th>Gift name</th>
      <th>Price</th>
      <th></th>
      </tr>
      </thead>
      <tbody data-bind='template: { name: "giftRowTemplate", foreach: gifts }'>
      </tbody>
      </table>
      <button data-bind="click: addGift">
      Add Gift</button>
      <button data-bind="enable: gifts().length > 0" type="submit">
      Submit</button>
      </form>
      <script type="text/html" id="giftRowTemplate">
      <tr>
      <td><input class="required" data-bind="value: name, uniqueName: true"/></td>
      <td><input class="required number" data-bind="value: price, uniqueName: true"/></td>
      <td><a href="#" data-bind="click: function() { viewModel.removeGift($data) }">Delete</a></td>
      </tr>
      </script>


      代碼: View model

      View Code
      var viewModel = {
      gifts: ko.observableArray([
      { name: "Tall Hat", price: "39.95" },
      { name: "Long Cloak", price: "120.00" }
      ]),

      addGift: function () {
      this.gifts.push({ name: "", price: "" });
      },

      removeGift: function (gift) {
      this.gifts.remove(gift);
      },

      save: function (form) {
      alert("Could now transmit to server: " + ko.utils.stringifyJson(this.gifts));
      // To transmit to server, write this: ko.utils.postJson($("form")[0], this.gifts);
      }
      };

      ko.applyBindings(viewModel);

      $("form").validate({ submitHandler: function () { viewModel.save() } });


      3   Shopping cart screen

      這個例子展示的是依賴監控屬性(dependent observable)怎么樣鏈在一起。每個cart對象都有一個dependentObservable對象去計算自己的subtotal,這些又被一個進一步的dependentObservable對象依賴計算總的價格。當改變數據的時候,整個鏈上的依賴監控屬性都會改變,所有相關的UI元素也會被更新。

      這個例子也展示了如何創建聯動的下拉菜單。

       

      代碼: View

      View Code
      <div id="cartEditor">
      <table width="100%">
      <thead>
      <tr>
      <th width="25%">Category</th>
      <th width="25%">Product</th>
      <th width="15%" class='price'>Price</th>
      <th width="10%" class='quantity'>Quantity</th>
      <th width="15%" class='price'>Subtotal</th>
      <th width="10%"></th>
      </tr>
      </thead>
      <tbody data-bind='template: {name: "cartRowTemplate", foreach: lines}'>
      </tbody>
      </table>
      <p class="grandTotal">
      Total value: <span data-bind="text: formatCurrency(grandTotal())"></span>
      </p>
      <button data-bind="click: addLine">
      Add product</button>
      <button data-bind="click: save">
      Submit order</button>
      </div>
      <script type="text/html" id="cartRowTemplate">
      <tr>
      <td><select data-bind='options: sampleProductCategories, optionsText: "name", optionsCaption: "Select...", value: category'></select></td>
      <td><select data-bind='visible: category, options: category() ? category().products : null, optionsText: "name", optionsCaption: "Select...", value: product'></select></td>
      <td class='price'><span data-bind='text: product() ? formatCurrency(product().price) : ""'></span></td>
      <td class='quantity'><input data-bind='visible: product, value: quantity, valueUpdate: "afterkeydown"'/></td>
      <td class='price'><span data-bind='visible: product, text: formatCurrency(subtotal())'></span></td>
      <td><a href="#" data-bind='click: function() { cartViewModel.removeLine($data) }'>Remove</a></td>
      </tr>
      </script>


      代碼: View model

      View Code
      function formatCurrency(value) { return "$" + value.toFixed(2); }

      var cartLine = function () {
      this.category = ko.observable();
      this.product = ko.observable();
      this.quantity = ko.observable(1);
      this.subtotal = ko.dependentObservable(function () {
      return this.product() ? this.product().price * parseInt("0" + this.quantity(), 10) : 0;
      } .bind(this));

      // Whenever the category changes, reset the product selection
      this.category.subscribe(function () { this.product(undefined); } .bind(this));
      };

      var cart = function () {
      // Stores an array of lines, and from these, can work out the grandTotal
      this.lines = ko.observableArray([new cartLine()]); // Put one line in by default
      this.grandTotal = ko.dependentObservable(function () {
      var total = 0;
      for (var i = 0; i < this.lines().length; i++)
      total += this.lines()[i].subtotal();
      return total;
      } .bind(this));

      // Operations
      this.addLine = function () { this.lines.push(new cartLine()) };
      this.removeLine = function (line) { this.lines.remove(line) };

      this.save = function () {
      var dataToSave = $.map(this.lines(), function (line) {
      return line.product() ? { productName: line.product().name, quantity: line.quantity()} : undefined
      });

      alert("Could now send this to server: " + JSON.stringify(dataToSave));
      };
      };

      var cartViewModel = new cart();

      ko.applyBindings(cartViewModel, document.getElementById("cartEditor"));

       

      4   Twitter client

      這是一個復雜的例子,展示了幾乎所有Knockout特性來構建一個富客戶端。

      用戶數據存在一個JavaScript模型里,通過模板來展示。就是說我們可以通過清理用戶列表里的數據來達到隱藏用戶信息的目的,而不需要手動去隱藏DOM元素。

      按鈕將根據他們是否可操作來自動變成enabled或disabled狀態。例如,有一個叫hasUnsavedChanges的依賴監控屬性(dependentObservable)控制這“Save”按鈕的enabled狀態。

      可以非常方便地從外部JSON服務獲取數據,并集成到view model里,然后顯示在頁面上。

       

      代碼: View

      View Code
      <div class="loadingIndicator">
      Loading...</div>
      <div class="configuration">
      <div class="listChooser">
      <button data-bind='click: deleteList, enable: editingList.name'>
      Delete</button>
      <button data-bind='click: saveChanges, enable: hasUnsavedChanges'>
      Save</button>
      <select data-bind='options: savedLists, optionsValue: "name", value: editingList.name'>
      </select>
      </div>
      <p>
      Currently viewing <span data-bind="text: editingList.userNames().length">&nbsp;</span>
      user(s):</p>
      <div class="currentUsers" data-bind='template: { name: "usersTemplate", data: editingList }'>
      </div>
      <form data-bind="submit: addUser">
      <label>
      Add user:</label>
      <input data-bind='value: userNameToAdd, valueUpdate: "keyup", css: { invalid: !userNameToAddIsValid() }' />
      <button type="submit" data-bind='enable: userNameToAddIsValid() && userNameToAdd() != ""'>
      Add</button>
      </form>
      </div>
      <div class="tweets" data-bind='template: { name: "tweetsTemplate", data: currentTweets }'>
      </div>
      <script type="text/html" id="tweetsTemplate">
      <table width="100%">
      {{each $data}}
      <tr>
      <td><img src="${ profile_image_url }"/></td>
      <td>
      <a class="twitterUser" href="http://twitter.com/${ from_user }">${ from_user }</a>
      ${ text }
      <div class="tweetInfo">${ created_at }</div>
      </td>
      </tr>
      {{/each}}
      </table>
      </script>
      <script type="text/html" id="usersTemplate">
      <ul>
      {{each(i, userName) userNames()}}
      <li><button data-bind="click: function() { userNames.remove(userName) }">Remove</button> <div>${ userName }</div></li>
      {{/each}}
      </ul>
      </script>


      代碼: View model

      View Code
      // The view model holds all the state we're working with. It also has methods that can edit it, and it uses
      //
      dependentObservables to compute more state in terms of the underlying data
      //
      --
      //
      The view (i.e., the HTML UI) binds to this using data-bind attributes, so it always stays up-to-date with
      //
      the view model, even though the view model does not know or care about any view that binds to it

      var viewModel = {
      savedLists: ko.observableArray([
      { name: "Celebrities", userNames: ['JohnCleese', 'MCHammer', 'StephenFry', 'algore', 'StevenSanderson'] },
      { name: "Microsoft people", userNames: ['BillGates', 'shanselman', 'haacked', 'ScottGu'] },
      { name: "Tech pundits", userNames: ['Scobleizer', 'LeoLaporte', 'techcrunch', 'BoingBoing', 'timoreilly', 'codinghorror'] }
      ]),

      editingList: {
      name: ko.observable("Tech pundits"),
      userNames: ko.observableArray()
      },

      userNameToAdd: ko.observable(""),
      currentTweets: ko.observableArray([])
      };

      viewModel.findSavedList = function (name) {
      var lists = this.savedLists();

      for (var i = 0; i < lists.length; i++)
      if (lists[i].name === name)
      return lists[i];
      };

      // Methods
      viewModel.addUser = function () {
      if (this.userNameToAdd() && this.userNameToAddIsValid()) {
      this.editingList.userNames.push(this.userNameToAdd());
      this.userNameToAdd("");
      }
      }

      viewModel.saveChanges = function () {
      var saveAs = prompt("Save as", this.editingList.name());

      if (saveAs) {
      var dataToSave = this.editingList.userNames().slice(0);
      var existingSavedList = this.findSavedList(saveAs);
      if (existingSavedList)
      existingSavedList.userNames = dataToSave; // Overwrite existing list
      else
      this.savedLists.push({ name: saveAs, userNames: dataToSave }); // Add new list

      this.editingList.name(saveAs);
      }
      }

      viewModel.deleteList = function () {
      var nameToDelete = this.editingList.name();
      var savedListsExceptOneToDelete = $.grep(this.savedLists(), function (list) { return list.name != nameToDelete });
      this.editingList.name(savedListsExceptOneToDelete.length == 0 ? null : savedListsExceptOneToDelete[0].name);
      this.savedLists(savedListsExceptOneToDelete);
      };

      ko.dependentObservable(function () {
      // Observe viewModel.editingList.name(), so when it changes (i.e., user selects a different list) we know to copy the saved list into the editing list
      var savedList = viewModel.findSavedList(viewModel.editingList.name());

      if (savedList) {
      var userNamesCopy = savedList.userNames.slice(0);
      viewModel.editingList.userNames(userNamesCopy);
      } else
      viewModel.editingList.userNames([]);
      });

      viewModel.hasUnsavedChanges = ko.dependentObservable(function () {
      if (!this.editingList.name())
      return this.editingList.userNames().length > 0;

      var savedData = this.findSavedList(this.editingList.name()).userNames;
      var editingData = this.editingList.userNames();
      return savedData.join("|") != editingData.join("|");
      }, viewModel);

      viewModel.userNameToAddIsValid = ko.dependentObservable(function () {
      return (this.userNameToAdd() == "") || (this.userNameToAdd().match(/^\s*[a-zA-Z0-9_]{1,15}\s*$/) != null);
      }, viewModel);

      // The active user tweets are (asynchronously) computed from editingList.userNames
      ko.dependentObservable(function () {
      twitterApi.getTweetsForUsers(this.editingList.userNames(), function (data) { viewModel.currentTweets(data) })
      }, viewModel);

      ko.applyBindings(viewModel);

      // Using jQuery for Ajax loading indicator - nothing to do with Knockout
      $(".loadingIndicator").ajaxStart(function () { $(this).fadeIn(); })
      .ajaxComplete(function () { $(this).fadeOut(); });



      主站蜘蛛池模板: 成年午夜性影院| 国外av片免费看一区二区三区| 九九热免费精品视频在线| 熟女人妻aⅴ一区二区三区电影| 亚洲日本精品国产第一区| 99久久免费精品色老| 成人又黄又爽又色的视频| 亚洲 小说区 图片区 都市| 久久国产精品久久久久久| 日韩欧激情一区二区三区| 久久综合色天天久久综合图片 | 精品超清无码视频在线观看| 久久久亚洲欧洲日产国码606 | 欧美丰满熟妇xxxx性大屁股| 视频二区中文字幕在线| 久久久久99精品成人片牛牛影视| 亚洲偷自拍另类一区二区| 国产国产久热这里只有精品| 亚洲国产一区二区av| 鸡东县| 青草精品国产福利在线视频| 亚洲精品日韩精品久久| 嵊泗县| 国产乱人伦无无码视频试看| 亚洲综合国产成人丁香五| 国产成人精品视频国产| 花莲县| 草草浮力影院| 国产在线线精品宅男网址| 国产成人高清亚洲综合| 欧美人禽zozo动人物杂交| 性色欲情网站iwww九文堂| 国产色精品久久人妻| 国产高清自产拍av在线| 成人伊人青草久久综合网| 99久久国产宗和精品1上映| 亚洲国产成人久久77| 国产午夜精品一区二区三区漫画| 日韩中文字幕人妻一区| 日韩精品一区二区高清视频| 鄄城县|