Это немного странно, но если ваша цель состоит в том, чтобы повлиять на минимальные изменения в существующих представлениях (помимо перемещения визуализированных сценариев), то, как я делал это в прошлом (в частности, в веб-формах, но также применимо к MVC).) должен был переопределить TextWriter
с тем, который толкает сценарии к основанию.
По сути, вы просто пишете реализацию TextWriter
и подключаете ее к базовой странице MVC, которая ищет <script src="
и записывает имя файла во внутренний Queue
, а затем, когда он начинает получать Write
требует </body>
, он отображает все, что встроено в Queue
.Это можно сделать с помощью регулярных выражений, но это, вероятно, довольно медленно.В этой статье показан пример TextWriter
для перемещения ViewState, но тот же принцип должен применяться.
Чтобы переопределить зависимости, я затем определил файлы сценариев и зависимые файлы сценариев в моей сети..config, аналогично этому в ситуациях, когда мне нужно было переопределить порядок:
<scriptWriter>
<add file="~/scripts/jquery.ui.js">
<add dependency="~/scripts/jquery.js" />
</add>
</scriptWriter>
Отказ от ответственности Как я уже сказал, это хакерство, лучшее решение было бы использовать какой-то CommonJS /AMD, как синтаксис в ваших частичных (@Script.Require("~/scripts/jquery-ui.js")
), в основном вы могли бы написать функцию, которая, если главная страница / страница макета указывает свою регистрацию сценария захвата, она может прослушивать все дочерние регистрации, в противном случае она может просто выводить inline, так что не будетбольно просто использовать его везде.Конечно, это может нарушить intellisense.
Предполагая, что некоторый код в вашем мастере, например:
@using(Script.Capture()) {
@RenderBody()
@Html.Partial("Partial")
}
И часть:
@Script.Require("~/scripts/jquery-ui.js")
Тогда вы можете просто закодироватьчто-то вроде этого, чтобы справиться с этим:
public class ScriptHelper : IDisposable
{
bool _capturing = false;
Queue<string> _list = new Queue<string>();
readonly ViewContext _ctx;
public ScriptHelper Capture()
{
_capturing = true;
return this;
}
public IHtmlString Require(string scriptFile)
{
_list.Enqueue(scriptFile);
if (!_capturing)
{
return Render();
}
return new HtmlString(String.Empty);
}
public IHtmlString Render()
{
IHtmlString scriptTags;
//TODO: handle dependencies, order scripts, remove duplicates
_list.Clear();
return scriptTags;
}
public void Dispose()
{
_capturing = false;
_ctx.Writer.Write(Render().ToHtmlString());
}
}
Вам может понадобиться сделать Queue
ThreadStatic
или использовать HttpContext
или что-то еще, но я думаю, что это дает общую идею.