Одностраничный дизайн с использованием Orchard CMS

#orchardcms

#orchardcms

Вопрос:

У меня есть клиент, который хочет создать одностраничный дизайн для своего сайта, где содержимое для каждой «страницы» отображается / скрывается с помощью javascript при навигации пользователя по сайту.

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

У кого-нибудь есть идеи или опыт о том, как лучше всего настроить это в Orchard CMS?


Вот решение, которое я использовал, основываясь на совете Бертрана:

 public ActionResult Display(int id)
{
     var contentItem = _contentManager.Get(id, VersionOptions.Published);
     dynamic model = _contentManager.BuildDisplay(contentItem);
     var ctx = _workContextAccessor.GetContext();
     ctx.Layout.Metadata.Alternates.Add("Layout_Null");
     return new ShapeResult(this, model);
}
  

Я создал новый модуль с контроллером, содержащим метод действия, описанный выше. Метод action принимает параметр для идентификатора части содержимого. Объекты _contentManager и _workContextAccessor внедряются в контроллер. Представление Layout.Null.cshtml было создано точно так, как предложил Бертран.

Комментарии:

1. Это чрезвычайно причудливый дизайн, который, кажется, противоречит SEO и всем известным удобствам использования. Чем это оправдано?

2. Похоже, вы разрабатываете мобильное приложение, верно? jQuery Mobile?

3. @BertrandLeRoy: Я не обязательно не согласен. Это то, чего хочет клиент (в частности, они хотят, чтобы я внедрил этот шаблон: udfrance.com/dev/STUDIO8/index_black.html ). Сайт очень легкий по содержанию, и SEO не является основной целью.

4. @pszmyd: не мобильное приложение jquery, но аналогичный вариант использования.

5. Не возвращает результаты _content manager. Получить разоблачение уязвимости безопасности, учитывая, что, насколько я знаю, все данные администратора можно получить с помощью content manager? Это просто вопрос выбора различных значений для идентификатора, пока вы не получите обратно информацию об учетной записи пользователя или некоторые другие привилегированные данные.

Ответ №1:

Вот что я бы сделал, чтобы добиться такого отточенного опыта, не жертвуя SEO, производительностью клиента и удобством обслуживания: по-прежнему создавайте сайт «классически» как набор страниц, сообщений в блогах и т. Д. С их собственными URL-адресами. Тогда макет домашней страницы должен отличаться и отображать содержимое этих других страниц с помощью вызовов Ajax. Один из методов, который я использовал для отображения того же содержимого, что и обычный элемент содержимого, но из вызова Ajax (то есть без chrome вокруг содержимого, без ввода таблицы стилей, поскольку она уже есть и т. Д.), — это иметь отдельное действие контроллера, которое возвращает содержимое в виде»нулевой макет»:

 var ctx = _workContextAccessor.GetContext();
ctx.Layout.Metadata.Alternates.Add("Layout_Null");
return new ShapeResult(this, shape);
  

Затем у меня есть файл Layout.Null.cshtml в моих представлениях, который выглядит следующим образом:

 @{
    Model.Metadata.Wrappers.Clear();
}
@Display(Model.Content)
  

Очистка оболочек удаляет рендеринг из document.cshtml, а сам шаблон отображает только одну зону — Контент. Таким образом, отображается только содержимое и ничего больше. Идеально подходит для внедрения из вызова ajax.

Помогает ли это?

Комментарии:

1. Это звучит как отличное решение. Куда отправляется действие контроллера, которое возвращает содержимое в «нулевом макете»?

2. Где вы хотите: модуль, тема, это не имеет значения.

3. Спасибо Бертран. Я попробую. Не уверен, как это сделать, но, надеюсь, это станет понятнее, когда я войду туда и поработаю над этим.

4. Вы также можете выполнить работу по добавлению альтернативы из обработчика a, если это проще.

5. Я добавил модуль (используя codegen), и в моем действии контроллера добавлен ваш первый блок кода. Однако мне неясно, откуда берутся объекты _workContextAccessor и shape. Можете ли вы дать мне некоторые рекомендации? Спасибо

Ответ №2:

Следуя примеру решения Бертрана, было бы разумнее реализовать это как FilterProvider / IResultFilter? Таким образом, нам не нужно обрабатывать логику поиска контента. Приведенный Бертраном пример, похоже, не работает для элементов содержимого списка.

У меня есть что-то подобное в моем модуле, который, кажется, работает:

 public class LayoutFilter : FilterProvider, IResultFilter {
    private readonly IWorkContextAccessor _wca;

    public LayoutFilter(IWorkContextAccessor wca) {
        _wca = wca;
    }

    public void OnResultExecuting(ResultExecutingContext filterContext) {
        var workContext = _wca.GetContext();
        var routeValues = filterContext.RouteData.Values;

        if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest()) {
            workContext.Layout.Metadata.Alternates.Add("Layout_Null");

        }           
    }

    public void OnResultExecuted(ResultExecutedContext filterContext) {
    }        
}
  

Комментарии:

1. Привет, Рахул, я реализую это для своего проекта, но как мне получить содержимое страницы из ajax?, спасибо

Ответ №3:

Повторное использование ответа Рахула с добавлением кода для ответа на вопрос @tuanvt. Я, честно говоря, не уверен, в чем заключается ваш вопрос, но если кажется, что вы хотите получить доступ к данным, отправленным с помощью запроса ajax. Если это JSON, который вы отправляете в запросе set ContentType: «application / json», JSON.stringify() , затем получите к нему доступ в предложенном Рахулом ActionFilter, извлекая его из потока запросов. Надеюсь, это поможет в любом случае.

 public class LayoutFilter : FilterProvider, IResultFilter {
  private readonly IWorkContextAccessor _wca;

  public LayoutFilter(IWorkContextAccessor wca) {
        _wca = wca;
  }

  public void OnResultExecuting(ResultExecutingContext filterContext) {
      var workContext = _wca.GetContext();
      var routeValues = filterContext.RouteData.Values;

      if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest()) {
           workContext.Layout.Metadata.Alternates.Add("Layout_Null");

           if (filterContext.HttpContext.Request.ContentType.ToLower().Contains("application/json"))
           {
                var bytes = new byte[filterContext.HttpContext.Request.InputStream.Length];
               filterContext.HttpContext.Request.InputStream.Read(bytes, 0, bytes.Length);
               filterContext.HttpContext.Request.InputStream.Position = 0;
               var json = Encoding.UTF8.GetString(bytes);
               var jsonObject = JObject.Parse(json);
               // access jsonObject data from ajax request
           }
      }           
  }

  public void OnResultExecuted(ResultExecutedContext filterContext) {
  }        
}