#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) {
}
}