Использование 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>
Ответы
Ответ 1
Используйте псевдоэлемент <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>
Update:
Скотт Гатри недавно опубликовал о синтаксисе @:
в Razor, который немного менее clunky, чем тег <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
выглядит очень похож на код С#. Затем Razor подбирает синтаксис @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);
});
Ответ 2
Я только что написал эту вспомогательную функцию. Поместите его в 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);
Обратите внимание, что я не помещаю кавычки вокруг него. Если заголовок уже содержит кавычки, он не будет взорваться. Кажется, тоже хорошо обрабатывать словари и анонимные объекты!
Ответ 3
Вы пытаетесь зажать квадратный штифт в круглом отверстии.
Razor был предназначен как язык шаблонов HTML-генерации. Вы вполне можете получить его для генерации кода JavaScript, но он не был предназначен для этого.
Например: Что делать, если Model.Title
содержит апостроф? Это нарушит ваш JavaScript-код, и Razor не удастся избежать его по умолчанию.
Вероятно, было бы более целесообразно использовать генератор строк в вспомогательной функции. Вероятно, будет меньше непредсказуемых последствий этого подхода.
Ответ 4
Какие конкретные ошибки вы видите?
Что-то вроде этого может работать лучше:
<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 должен переключиться в режим разметки.
Ответ 5
Это будет работать нормально, если на странице CSHTML, а не на внешнем файле JavaScript.
Механизм шаблонов Razor не заботится о том, что он выводит и не проводит различия между <script>
или другими тегами.
Однако вам нужно закодировать свои строки, чтобы предотвратить атаки XSS.
Ответ 6
Я предпочитаю "<! -" "- > " как "текст > "
<script type="text/javascript">
//some javascript here
@foreach (var item in itens)
{
<!--
var title = @(item.name)
...
-->
</script>
Ответ 7
Одна вещь, которую нужно добавить - я обнаружил, что синтаксический hilighter 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>
Ответ 8
Простой и хороший прямой пример:
<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 an odd workaraound, but it works.
@{
var outScript = "var razorUserName = " + "\"" + @User.Identity.Name + "\"";
}
@MvcHtmlString.Create(outScript);
</script>
Это создает 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 an odd workaraound, but it works.
var razorUserName = "daylight";
</script>
Теперь у вас есть глобальная переменная JavaScript с именем razorUserName
, которую вы можете получить и использовать на клиенте. Двигатель Razor, очевидно, извлек значение из @User.Identity.Name
(серверная переменная) и поместил его в код, который он записывает в тэг script.
Ответ 9
Существует еще один вариант, чем @: и <text></text>
.
Использование <script>
блокирует себя.
Когда вам нужно делать большие куски JavaScript в зависимости от кода Razor, вы можете сделать это следующим образом:
@if(Utils.FeatureEnabled("Feature")) {
<script>
// If this feature is enabled
</script>
}
<script>
// Other JavaScript code
</script>
Плюсы такого способа заключаются в том, что он не слишком сильно смешивает JavaScript и Razor, потому что их смешение в конечном итоге вызовет проблемы с читабельностью. Также большие текстовые блоки не очень читаемы.
Ответ 10
Следующее решение кажется мне более точным, чем сочетание 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
.
Ответ 11
Ни одно из предыдущих решений не работает правильно... Я пробовал все пути, но это не дало ожидаемого результата... Наконец-то я обнаружил, что в коде есть некоторые ошибки... И полный код приведен ниже.
<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>
Ответ 12
Наконец, я нашел решение (*.vbhtml):
function razorsyntax() {
/* Double */
@(MvcHtmlString.Create("var szam =" & mydoublevariable & ";"))
alert(szam);
/* String */
var str = '@stringvariable';
alert(str);
}