Использование Razor в JavaScript - PullRequest
406 голосов
/ 05 января 2011

Возможно или есть обходной путь для использования синтаксиса Razor в JavaScript, который находится в представлении (cshtml)?

Я пытаюсь добавить маркеры на карту Google ... Например, я пробовал это, но получаю массу ошибок компиляции:

<script type="text/javascript">

    // Some JavaScript code here to display map, etc.

    // Now add markers
    @foreach (var item in Model) {

        var markerlatLng = new google.maps.LatLng(@(Model.Latitude), @(Model.Longitude));
        var title = '@(Model.Title)';
        var description = '@(Model.Description)';
        var contentString = '<h3>' + title + '</h3>' + '<p>' + description + '</p>'

        var infowindow = new google.maps.InfoWindow({
            content: contentString
        });

        var marker = new google.maps.Marker({
            position: latLng,
            title: title,
            map: map,
            draggable: false
        });

        google.maps.event.addListener(marker, 'click', function () {
            infowindow.open(map, marker);
        });
    }
</script>

Ответы [ 12 ]

600 голосов
/ 05 января 2011

Используйте псевдоэлемент <text>, как описано здесь , чтобы принудительно вернуть Razor-компилятор в режим содержимого:

<script type="text/javascript">

    // Some JavaScript code here to display map, etc.


    // Now add markers
    @foreach (var item in Model) {
        <text>
            var markerlatLng = new google.maps.LatLng(@(Model.Latitude), @(Model.Longitude));
            var title = '@(Model.Title)';
            var description = '@(Model.Description)';
            var contentString = '<h3>' + title + '</h3>' + '<p>' + description + '</p>'

            var infowindow = new google.maps.InfoWindow({
                content: contentString
            });

            var marker = new google.maps.Marker({
                position: latLng,
                title: title,
                map: map,
                draggable: false
            });

            google.maps.event.addListener(marker, 'click', function () {
                infowindow.open(map, marker);
            });
        </text>
    }
</script>

Обновление:

Скотт Гатри недавно опубликовал о синтаксисе @: в Razor, что немного менее неуклюже, чем тег <text>, если вам нужно добавить одну или две строки кода JavaScript для добавления.Следующий подход, вероятно, будет предпочтительнее, поскольку он уменьшает размер сгенерированного HTML.(Вы можете даже переместить функцию addMarker в статический кешированный файл JavaScript, чтобы еще больше уменьшить размер):

<script type="text/javascript">

    // Some JavaScript code here to display map, etc.
    ...
    // Declare addMarker function
    function addMarker(latitude, longitude, title, description, map)
    {
        var latLng = new google.maps.LatLng(latitude, longitude);
        var contentString = '<h3>' + title + '</h3>' + '<p>' + description + '</p>';

        var infowindow = new google.maps.InfoWindow({
            content: contentString
        });

        var marker = new google.maps.Marker({
            position: latLng,
            title: title,
            map: map,
            draggable: false
        });

        google.maps.event.addListener(marker, 'click', function () {
            infowindow.open(map, marker);
        });
    }

    // Now add markers
    @foreach (var item in Model) {
        @:addMarker(@item.Latitude, @item.Longitude, '@item.Title', '@item.Description', map);
    }
</script>

Обновлен код выше, чтобы сделать вызов addMarker более правильным.

Для пояснения, @: возвращает Razor обратно в текстовый режим, хотя вызов addMarker очень похож на код C #.Затем Razor выбирает синтаксис @item.Property, чтобы сказать, что он должен напрямую выводить содержимое этих свойств.

Обновление 2

Стоит отметить, что код View действительно не является хорошим местом дляпоставить код JavaScript.Код JavaScript должен быть помещен в статический файл .js, а затем он должен получить необходимые данные либо из вызова Ajax, либо путем сканирования атрибутов data- из HTML.Помимо возможности кэширования вашего кода JavaScript, это также позволяет избежать проблем с кодировкой, поскольку Razor предназначен для кодирования для HTML, но не для JavaScript.

Просмотр кода

@foreach(var item in Model)
{
    <div data-marker="@Json.Encode(item)"></div>
}

Код JavaScript

$('[data-marker]').each(function() {
    var markerData = $(this).data('marker');
    addMarker(markerData.Latitude, markerData.Longitude,
              markerData.Description, markerData.Title);
});
38 голосов
/ 07 ноября 2011

Я только что написал эту вспомогательную функцию.Поместите это в App_Code/JS.cshtml:

@using System.Web.Script.Serialization
@helper Encode(object obj)
{
    @(new HtmlString(new JavaScriptSerializer().Serialize(obj)));
}

Тогда в вашем примере вы можете сделать что-то вроде этого:

var title = @JS.Encode(Model.Title);

Обратите внимание, как я не заключаю в кавычки.Если заголовок уже содержит кавычки, он не взорвется.Кажется, хорошо справляется и со словарями, и анонимными объектами!

22 голосов
/ 05 января 2011

Вы пытаетесь заклинить квадратный колышек в круглое отверстие.

Razor был задуман как язык шаблонов, генерирующий HTML. Вы можете получить его для генерации кода JavaScript, но он не предназначен для этого.

Например: что, если Model.Title содержит апостроф? Это нарушит ваш код JavaScript, и Razor по умолчанию не сможет его избежать.

Вероятно, было бы более уместно использовать генератор String в вспомогательной функции. Вероятно, при таком подходе будет меньше непредвиденных последствий.

16 голосов
/ 05 января 2011

Какие конкретные ошибки вы видите?

Что-то вроде этого может работать лучше:

<script type="text/javascript">

//now add markers
 @foreach (var item in Model) {
    <text>
      var markerlatLng = new google.maps.LatLng(@Model.Latitude, @Model.Longitude);
      var title = '@(Model.Title)';
      var description = '@(Model.Description)';
      var contentString = '<h3>' + title + '</h3>' + '<p>' + description + '</p>'
    </text>
}
</script>

Обратите внимание, что вам нужен магический тег <text> после foreach, чтобы указать, чтоБритва должна переключиться в режим разметки.

11 голосов
/ 05 января 2011

Это будет работать нормально, если оно находится на странице CSHTML, а не во внешнем файле JavaScript.

Механизм шаблонов Razor не заботится о том, что он выводит, и не различает <script> или другиетеги.

Однако вам необходимо закодировать строки, чтобы предотвратить XSS атаки.

10 голосов
/ 13 марта 2012

Я предпочитаю "<! -" "->" как "текст>"

<script type="text/javascript">
//some javascript here     

@foreach (var item in itens)
{                 
<!--  
   var title = @(item.name)
    ...
-->

</script>
8 голосов
/ 31 мая 2011

Одна вещь, которую нужно добавить - я обнаружил, что синтаксис Razor (и, возможно, компилятор) интерпретирует положение открывающей скобки по-разному:

<script type="text/javascript">
    var somevar = new Array();

    @foreach (var item in items)
    {  // <----  placed on a separate line, NOT WORKING, HILIGHTS SYNTAX ERRORS
        <text>
        </text>
    }

    @foreach (var item in items) {  // <----  placed on the same line, WORKING !!!
        <text>
        </text>
    }
</script>
6 голосов
/ 09 апреля 2015

Следующее решение кажется мне более точным, чем объединение JavaScript с Razor. Проверь это: https://github.com/brooklynDev/NGon

Вы можете добавить практически любые сложные данные в ViewBag.Ngon и получить к ним доступ в JavaScript

В контроллере:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var person = new Person { FirstName = "John", LastName = "Doe", Age = 30 };
        ViewBag.NGon.Person = person;
        return View();
    }
}

В JavaScript:

<script type="text/javascript">
    $(function () {
        $("#button").click(function () {
            var person = ngon.Person;
            var div = $("#output");
            div.html('');
            div.append("FirstName: " + person.FirstName);
            div.append(", LastName: " + person.LastName);
            div.append(", Age: " + person.Age);
        });
    });
</script>

Он допускает любые простые старые объекты CLR (POCO), которые можно сериализовать с использованием значения по умолчанию JavascriptSerializer.

6 голосов
/ 04 марта 2014

Простой и хороший прямой пример:

<script>
    // This gets the username from the Razor engine and puts it
    // in JavaScript to create a variable I can access from the
    // client side.
    //
    // It's an odd workaraound, but it works.
    @{
        var outScript = "var razorUserName = " + "\"" + @User.Identity.Name + "\"";
    }
    @MvcHtmlString.Create(outScript);
</script>

Это создает скрипт на вашей странице в месте, где вы размещаете код выше, который выглядит следующим образом:

<script>
    // This gets the username from the Razor engine and puts it
    // in JavaScript to create a variable I can access from
    // client side.
    //
    // It's an odd workaraound, but it works.

    var razorUserName = "daylight";
</script>

Теперь у вас есть глобальная переменная JavaScript с именем razorUserName, к которой вы можете обращаться и использовать на клиенте. Механизм Razor, очевидно, извлек значение из @User.Identity.Name (серверная переменная) и поместил его в код, который записывается в тэг сценария.

5 голосов
/ 03 апреля 2013

Существует также еще одна опция, чем @: и <text></text>.

Использование <script> самого блока.

Когда вам нужно сделать большие куски JavaScript в зависимости от кода Razor, вы можете сделать это следующим образом:

@if(Utils.FeatureEnabled("Feature")) {
    <script>
        // If this feature is enabled
    </script>
}

<script>
    // Other JavaScript code
</script>

Плюсы этого способа в том, что он не слишком смешивает JavaScript и Razor, потому что их частое смешивание в конечном итоге вызовет проблемы с читаемостью. Также большие текстовые блоки не очень читабельны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...