2014-09-02 47 views
0

我最近剛剛負責創建SPA。所以,我創建了一個新項目並選擇了SPA,並發現它加載了我需要的所有文件,包括knockout.js。MVC SPA +淘汰

我是新來的knockout.js,所以我看了一些視頻,我看到了這個主意,但SPA項目似乎並沒有計算出來,因爲它不是單頁應用,因爲你有去一個新的URL登錄,註冊,授權,管理賬戶等(你明白了)。

因此,看看索引頁的代碼,我可以看到homeView的視圖模型。它看起來像這樣:

function HomeViewModel(app, dataModel) { 
    var self = this; 

    self.myHometown = ko.observable(""); 

    Sammy(function() { 
     this.get('#home', function() { 
      // Make a call to the protected Web API by passing in a Bearer Authorization Header 
      $.ajax({ 
       method: 'get', 
       url: app.dataModel.userInfoUrl, 
       contentType: "application/json; charset=utf-8", 
       headers: { 
        'Authorization': 'Bearer ' + app.dataModel.getAccessToken() 
       }, 
       success: function (data) { 
        self.myHometown('Your Hometown is : ' + data.hometown); 
       } 
      }); 
     }); 
     this.get('/', function() { this.app.runRoute('get', '#home') }); 
    }); 

    return self; 
} 

app.addViewModel({ 
    name: "Home", 
    bindingMemberName: "home", 
    factory: HomeViewModel 
}); 

和HTML看起來像這樣:

<!-- ko with: home --> 

<!-- removed HTML to make it concise --> 

<!-- /ko --> 

現在,從這個(糾正我,如果我錯了)的手柄指出一下,如果有是一個變量,稱爲,然後顯示它(我認爲這是bindingMembername是什麼)。

因此,看到我可以猜測,如果我添加了另一個局部頁面並將其包含在內。我可以創建這樣的視圖模型:

function DrawViewModel(app, dataModel) { 
    var self = this; 

    Sammy(function() { 
     this.get('#draw', function() { 
      app.home = null; 
     }); 
    }); 

    return self; 
} 

app.addViewModel({ 
    name: "Draw", 
    bindingMemberName: "draw", 
    factory: DrawViewModel 
}); 

所以,從理論上講,因爲這設置app.home爲null每當有人導航到#draw,那麼將不會顯示在家庭部分,同樣我可以添加應用程序.draw = null爲homeViewModel隱藏繪製局部的sammy路由。

我的問題是,它會越來越複雜,我創建更多的viewModels。那麼,有什麼我失蹤?有沒有更簡單的方法來做到這一點?

我的最終目標是將所有頁面移到SPA(包括登錄/註冊頁面)。

乾杯提前, /r3plica

+1

我不知道你爲什麼發送該鏈接。我知道每個ViewModel不是一個新頁面,頁面是加載的第一個頁面(在我的情況下是Index.cshtml),而且我試圖使用散列標籤吸引內容。 – r3plica 2014-09-02 12:46:46

+0

就像剛開始時一樣,我使用了基於KO的框架幾年來,但轉移到Angular發現它更容易。即使像Durandal這樣的大型框架也正在從KO上移開(參見http://blog.angularjs.org/2014/04/angular-and-durandal-converge.html)。這裏有一個很好的教程,讓你開始。它讓我們的團隊在非常短的時間內瞭解了很多 - https://www.youtube.com/watch?v=i9MHigUZKEM。 – HockeyJ 2014-09-02 12:51:00

+0

這很簡短,但主要想法是將'Sammy'導航到'app'(其中包含頁面數組和當前在'ko.observable'中選擇的頁面)。然後,在'layout.html'上,您將擁有一個ko模板,該模板將使用當前選定頁面的視圖模型。所以,當一個url改變時,在你的'Sammy'回調中你只需要改變當前頁面,ko會自動改變模板內容。因此,所有使用頁面和導航的工作都包含在一個地方 - 「應用程序」中。 – 2014-09-02 12:56:52

回答

1

嗯,有點亂搞之後我發現瞭如何做到這一點。 基本上我重寫了AddView方法,並使它看起來像這樣:

// Other operations 
self.addViewModel = function (options) { 
    var viewItem = new options.factory(self, dataModel), 
     navigator; 

    // Add view to AppViewModel.Views enum (for example, app.Views.Home). 
    self.Views[options.name] = viewItem; 

    // Add binding member to AppViewModel (for example, app.home); 
    self[options.bindingMemberName] = ko.computed(function() { 
     if (self.view() !== viewItem) { 
      return null; 
     } 

     return new options.factory(self, dataModel); 
    }); 

    if (typeof (options.navigatorFactory) !== "undefined") { 
     navigator = options.navigatorFactory(self, dataModel); 
    } else { 
     navigator = function() { 
      self.view(viewItem); 
     }; 
    } 

    // Add navigation member to AppViewModel (for example, app.NavigateToHome()); 
    self["navigateTo" + options.name] = navigator; 
}; 

是你可以看到,如果看到檢查當前持有的觀點是一個我添加不同的。如果是,那麼我返回null(這是我如何隱藏任何視圖,我不使用)。 爲了進一步回答我的問題,我需要工作如何直接到登錄頁面,如果用戶沒有登錄的方式

再在app.viewmodel.js我增加了一些可觀察的屬性:

// UI state 
self.user = ko.observable(null); 

self.loggedIn = ko.computed(function() { 
    return self.user() !== null; 
}); 

,並在我的新login.viewmodel.js我添加了這個功能:

// Operations 
self.login = function() { 
    self.loggingIn(true); 

    dataModel.login({ 
     grant_type: "password", 
     username: self.userName(), 
     password: self.password() 
    }).done(function (data) { 
     if (data.userName && data.access_token) { 
      app.navigateToLoggedIn(data.userName, data.access_token, self.rememberMe()); 
     } else { 
      //self.errors.push("An unknown error occurred."); 
     } 
    }).fail(function (jqXHR, textStatus, error) { 
     dataModel.displayError(jqXHR); 
    }).always(function() { 
     self.loggingIn(false); 
    }); 
}; 

這裏最重要的一點是app.naviateToLoggedIn方法。這位於app.viewmodel。JS,看起來像這樣:

// UI operations 
self.navigateToLoggedIn = function (userName, accessToken, persistent) { 
    if (accessToken) { 
     dataModel.setAccessToken(accessToken, persistent) 
    } 

    self.user(new UserViewModel(self, userName, dataModel)); 
    self.navigateToHome(); 
}; 

的userViewModel是死的簡單:

function UserViewModel(app, name, dataModel) { 
    var self = this; 

    // Data 
    self.name = ko.observable(name); 

    // Operations 
    self.logOff = function() { 
     dataModel.logout().done(function() { 
      app.navigateToLoggedOff(); 
     }).fail(function (jqHXR) { 
      dataModel.displayError(jqHXR); 
     }); 
    }; 

    return self; 
} 

最後,讓我們的初始加載權,在home.viewmodel.js js文件,我有此sammy聲明:

Sammy(function() { 
    this.get('#home', function() { 
     if (app.loggedIn()) { 
      app.navigateToHome(); 
     } else { 
      window.location.hash = "login"; 
     } 
    }); 
    this.get('/', function() { this.app.runRoute('get', '#home') }); 
});