14

Я начал играть с шаблоном приложения для одной страницы для MVC 5, который поставляется с Visual Studio 2013. Я более чем знаком с Knockout.js, и хотя я не был с Sammy.js Я ' вы читали на нем, и это не кажется сложным.Понимание шаблона VS2013 MVC 5 SPA

То, что я, похоже, не могу оборачивать, - это то, как MVC 5 SPA Template объединяет эти технологии или что команда Visual Studio имела в виду для шаблона в качестве примера; шаблон содержит, помимо прочего, файл home.viewModel.js, который должен служить отправной точкой, но я не могу понять, как я могу добавить больше видов с помощью маршрутов Sammy.js. Если бы они предоставили второй частичный вид и модель обзора.

Моего вопрос

Итак, короткий рассказ долго, мои настоящие вопросы,

  1. как я могу идти об отображении частичного вида, связанном с маршрутом #users таким образом, что имитирует прилагаемую home.viewmodel.js, так что я могу перемещаться назад от #home до #users? Каким будет определение маршрута Sammy.js в users.viewModel.js?
  2. Нужно ли мне что-либо делать, чтобы включить кнопку возврата браузеров, или она будет работать, как только я правильно определил свои маршруты?
  3. Это он или этот шаблон чувствует себя наполовину испеченным примером?

Следующий код предназначен только для дополнительной справки/контекста, но, возможно, это не обязательно для ответа на вопрос.


Некоторого контекст

Давайте предположим, что я создал частичный вид, _Users.cshtml, обслуживаемый UserController, который является контроллером MVC и не WebAPI контроллера, и что я хочу показать, что частичный вид на средства маршрута Sammy.js, с которого я создал users.viewModel.js. Теперь ...

Index.cshtml Предоставленного вид выглядит следующим образом:

@section SPAViews { 
    @Html.Partial("_Home") 
} 
@section Scripts{ 
    @Scripts.Render("~/bundles/knockout") 
    @Scripts.Render("~/bundles/app") 
} 

Что я полагаю, это означает, как страницы приложения «оболочка», где остальная часть частичного вида будет загружены, чтобы заменить содержимое _Home частичный. Проблема заключается в том, что на home.viewmodel.jsSammy маршрут инициализируется без прохождения в селекторе для элемента, который будет содержать контент, как этот

Sammy(function() { 
    this.get('#home', function() { 
    // more code here 
} 

вместо, например

Sammy("#content", function() { 
    this.get('#home', function() { 
    // more code here 
} 

Am I предположительно разместить _Users частично с _Home с самого начала, так что вид Index выглядит так:

@section SPAViews { 
    @Html.Partial("_Home") 
    @Html.Partial("_Users") 
} 
@section Scripts{ 
    @Scripts.Render("~/bundles/knockout") 
    @Scripts.Render("~/bundles/app") 
} 

Это, конечно же, будет отображать оба вида одновременно, что не то, что мы хотим.

Мой users.viewmodel.js выглядит следующим образом:

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

    Sammy(function() { 
     this.get('#users', function() { 
      // the following line only makes sense if _Users is not 
      // called from Index.cshtml 
      //this.load(app.dataModel.shoppingCart).swap(); 
     }); 
    }); 

    return self; 
} 

app.addViewModel({ 
    name: "Users", 
    bindingMemberName: "users", 
    factory: UsersViewModel 
}); 

Я попытался с помощью метода Sammy.jsswap, но так как мой _Users вид является частичным и Sammy не настроен действовать на определенный элемент всей страницы заменяется ... и кнопка возврата браузера не работает.

Извините за огромное количество текста, и если это очень пустячный вопрос. Меня это беспокоит, что я не могу понять это самостоятельно, даже после прохождения документов.

+0

Привет, Серджи, у меня были те же вопросы, что и вы, но ответы ниже на самом деле не отвечают на них. Вы когда-нибудь это понимали? – Ezi

+0

Hi @Ezi, не совсем. Через очень короткое время я решил отказаться от этого подхода и написать приложение в Durandal ... И в настоящее время я не использую ничего другого, что [Aurelia] (http://aurelia.io) в [сочетании с ASP.NET 5 ] (https://github.com/aurelia/skeleton-navigation/tree/master/skeleton-es2016-asp.net5) :) –

+0

Спасибо за информацию, я думаю, мне придется изменить подход, так как я не могу цифра, что один из. Странно, почему Microsoft решила создать этот шаблон .. – Ezi

ответ

3

Это, конечно же, будет отображать оба вида одновременно, чего мы не хотим.

На самом деле, во многих случаях это именно то, что вы хотите (или, скорее, вы хотите их присутствие и контролировать их видимость.) В дополнение к свойству видимости на ViewModel и некоторых вспомогательных методов JS (или класс), чтобы показать/скрыть свои взгляды (с помощью ссылок ViewModel, как правило, связаны с конкретным URL, а)

Псевдо _Home.cshtml:.

<!-- ko with: $root.home --> 
<div data-bind="visible: isVisible"> 
    <!-- view markup/etc here --> 
</div> 
<!-- /ko --> 

Псевдо: app.viewmanager.js

MyViewManager = function() { 
    this.registerView = function(route, selector, viewmodel) {/**/}; 
    this.showView = function(selector, callback) {}; 
    this.cancelView = function(callback) {/**/}; 
    this.showModal = function(selector, callback) {/**/}; 
    this.closeModal = function(selector, callback) {/**/}; 
} 

Они будут обрабатывать интеграции с History API для маршрутизации/глубокой сшиванию, и нокаута, чтобы показать/скрыть элементы DOM (через IsVisible связывания). Вышеупомянутый «registerView» заменил бы addViewModel со стандартного леса. Все это, ИМО, мусор.

Я уже несколько лет разрабатываю ООП на базе MVC. Шаблон MVC5 SPA представляет собой интересное проявление интереса, но он имеет проблемы. Правильная глубокая привязка, инициализация и просмотр представлений - более очевидные проблемы, но с небольшим количеством смазки локтя вы можете легко кодировать то, что вам нужно.

Я также считаю раздел SPAViews бесполезным и предпочитаю использовать RenderBody для частичной доставки, что требует некоторой модификации _Layout.cshtml. В конце концов, для достаточно большого SPA вы завершите доставку почти всех ваших основных видов в одну страницу/просмотр в любом случае (редко можно увидеть частичные части Ajax в SPA, даже большой). И единственное значение в разделе SPAViews это размещение внутри _Layout, эффективно дублируя функцию RenderBody() (так как тело вашего SPA всегда будет собирать невидимые виды.)

+0

Или вот так: http://stackoverflow.com/questions/14583018/knockout-flickering-issue – decades

+0

@decades в представленном примере вы можете увидеть 'data-bind = «visible: isVisible» - причина, по которой вы не хотите связывать «visible: true» или «visible: false», заключается в том, что это может привести к произвольному отображению элементов пользовательского интерфейса во время выполнения «ko.applyBindings». для того, чтобы контролировать «мерцание начальной загрузки», вы всегда должны применять ** static css ** к элементу parent-most. стиль должен применяться статически, но удален динамически. вы должны удалить его из 'callback'' showView' (см. выше), гарантируя, что пользователь ни разу не увидит неинициализированное представление. –

7

Наткнувшись на это, мне удалось применить свой собственный маленький «взломать» ' чтобы исправить это.

При сравнении «старого» шаблона с новым я заметил, что Sammy.js больше встроен в шаблон. Хотя это и хорошо, оригинальная нокаут with из оригинальной коробки, чтобы показать ваши взгляды, сломан.

Чтобы применить исправление, в первую очередь необходимо понимать нокауты with.Ввиду по умолчанию home есть

<!-- ko with: home--> 

заявление, которое должно обеспечить видимость home view только тогда, когда член home присутствует. В этом случае полное имя будет app.home

Если мы исследуем это имя членов, мы видим, что вычисленная элемент определяется таким образом, как (app.viewmodel.js):

// Add binding member to AppViewModel (for example, app.home); 
self[options.bindingMemberName] = ko.computed(function() { 
    if (!dataModel.getAccessToken()) { 
     //omitted for clearity 
     if (fragment.access_token) { 
      //omitted for clearity 
     } else { 
      //omitted for clearity  
     } 
    } 

    return self.Views[options.name]; 
}); 

Как вы можете видеть, он всегда возвращает полный инициализированный вид из коллекции Views.

Если сравнить со старым шаблоном мы можем видеть изменения здесь:

// 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); 
}); 

который возвращает нулевое значение, если текущий вид не является целевым viewItem. Это имеет решающее значение для привязки нокаута with.

Дальнейшая проверка обоих шаблонов показывает лучшую интеграцию с sammy.js. Важная часть этого лежит в ViewModels (home.viewmodel.js):

Sammy(function() { 
    this.get('#home', function() { 
    }); 
    this.get('/', function() { this.app.runRoute('get', '#home') }); 
}); 

Поскольку sammy.js обрабатывает навигацию, ранее упомянутых viewItem, инкапсулированные в app.view() не установлено. Это, опять же, имеет решающее значение для привязки нокаута.

Таким образом, предложенный мой исправление следующим образом:

app.viewmodel.js

// Add binding member to AppViewModel (for example, app.home); 
self[options.bindingMemberName] = ko.computed(function() { 
    if (!dataModel.getAccessToken()) { 
     //omitted for clearity 
     if (fragment.access_token) { 
      //omitted for clearity 
     } else { 
      //omitted for clearity  
     } 
    } 

    ///change start here 
    if (self.view() !== viewItem) { 
      return null; 
     } 

    return self.Views[options.name]; 
}); 

и во всех пользовательских ViewModel:

home.viewmodel.js

Sammy(function() { 
    this.get('#home', function() { 
     app.view(self); //this line is added 
    }); 
    this.get('/', function() { this.app.runRoute('get', '#home') }); 
}); 

Отказ от ответственности: Поскольку я только что запустил это, у меня не было времени проанализировать любые нежелательные побочные эффекты. Кроме того, изменение основного шаблона шаблона не очень удовлетворительно, поэтому лучшие решения приветствуются.

+0

приятно, отлично работает с этими изменениями спасибо – Jay

1

Да, это определенно сбивает с толку, и, похоже, не так много документов. Я подозреваю, что количество способов делать вещи настолько велико, что им пришлось оставить его наполовину испеченным. FWIW Я сделал простой страницы нав, добавив следующую строку в app.viewmodel

navigator = function() { 

      self.view(viewItem); //THIS IS ADDED 



      window.location.hash = options.bindingMemberName; 
     }; 

и в index.cshtml у меня есть это:

@section SPAViews { 
<!-- ko if: app.view() === app.Views.Login --> 
    @Html.Partial("_login") 
<!-- /ko --> 
<!-- ko if: app.view() === app.Views.MyDashboard --> 
    @Html.Partial("_myDashboard") 

}

Я думаю, что они, вероятно, ожидают, что вы настроитесь на то, что общее состояние представления каким-то образом связано с моделью просмотра «app» (изменение вида, видимое видимое каким-то образом перегруппировывает страницу). Помимо простого подхода выше, не уверен, как лучше всего это сделать.