Использование Razor в JavaScript

возможно ли или существует обходной путь для использования синтаксиса 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 ответов


использовать <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 более правильным.

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

обновление 2

стоит отметить, что код просмотра действительно не является хорошим местом для размещения кода 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);
});

Я только что написал эту вспомогательную функцию. Положите его в 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);

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


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

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

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

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


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

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

<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 чтобы указать, что Razor должен переключиться в режим разметки.


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

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

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


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

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

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

</script>

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

<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>

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

<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 что вы можете получить доступ и использовать на клиенте. Двигатель бритвы, очевидно, извлек значение из @User.Identity.Name (переменная на стороне сервера)и поместите ее в код, который она записывает в тег скрипта.


следующее решение кажется мне более точным, чем объединение 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 (POCOs) это можно сериализовать, используя значение по умолчанию JavascriptSerializer.


есть и еще один вариант, чем @: и <text></text>.

используя блок.

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

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

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

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


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

<script type="text/javascript">

    var map = new google.maps.Map(document.getElementById('map'), {
        zoom: 10,
        center: new google.maps.LatLng(23.00, 90.00),
        mapTypeId: google.maps.MapTypeId.ROADMAP
    });

    @foreach (var item in Model)
    {
        <text>
            var markerlatLng = new google.maps.LatLng(@(item.LATITUDE), @(item.LONGITUDE));
            var title = '@(item.EMP_ID)';
            var description = '@(item.TIME)';
            var contentString = '<h3>' + "Employee " +title+ " was here at "+description+ '</h3>' + '<p>'+" "+ '</p>'

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

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

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

Я, наконец, нашел решение (*.vbhtml все):

function razorsyntax() {
    /* Double */
    @(MvcHtmlString.Create("var szam =" & mydoublevariable & ";"))
    alert(szam);

    /* String */
    var str = '@stringvariable';
    alert(str);
}