在JavaScript中使用Razor

是否有可能或有一个变通办法来在视图(cshtml)中使用JavaScript中的Razor语法?

我正在尝试添加标记到谷歌地图…例如,我尝试了这个,但我得到了大量的编译错误:

<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>
428568 次浏览

只要它在CSHTML页面中,而不是外部JavaScript文件中,就可以正常工作。

Razor模板引擎并不关心它输出什么,也不区分<script>或其他标签。

然而,你需要对你的字符串进行编码以防止XSS攻击。

你是想把方钉塞进圆洞里。

Razor的目的是作为一种html生成模板语言。您可以让它生成JavaScript代码,但它不是为此而设计的。

例如:如果Model.Title包含撇号怎么办?这将破坏JavaScript代码,默认情况下Razor不会正确转义它。

在辅助函数中使用String生成器可能更合适。这种做法可能会减少意想不到的后果。

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

更新:

如果你只有一两行JavaScript代码要添加的话,它比<text>标签稍微简单一些。下面的方法可能更可取,因为它减少了生成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

值得注意的是,视图代码确实不是放置JavaScript代码的好地方。JavaScript代码应该放在一个静态的.js文件中,然后它应该从Ajax调用或从HTML中扫描data-属性来获得所需的数据。除了可以缓存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);
});

您看到了哪些具体的错误?

这样做会更好:

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

注意,你需要在foreach之后加上神奇的<text>标记来指示Razor应该切换到标记模式。

有一件事要补充-我发现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>

我刚刚写了这个辅助函数。把它放在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);

注意我没有加引号。如果标题已经包含引号,它就不会爆炸。似乎处理字典和匿名对象也很好!

我更喜欢“<!”——" "——>"就像一个"文本>"

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


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


</script>

前面的解决方案都不能正常工作。我已经试过了所有的方法,但都没有达到预期的效果。最后我发现代码中有一些错误……完整的代码如下所示。

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

还有一个选项比@:和<text></text>多。

使用<script>块本身。

当你需要依赖Razor代码执行大块JavaScript时,你可以这样做:

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


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

这种方式的优点是它不会过多地混合JavaScript和Razor,因为过多地混合它们最终会导致可读性问题。此外,大的文本块也不是很可读。

我终于找到了解决方案(*.vbhtml):

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


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

一个简单明了的例子:

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

现在你有了一个名为razorUserName的全局JavaScript变量,你可以在客户端上访问和使用它。Razor引擎显然已经从@User.Identity.Name(服务器端变量)中提取了值,并将其放在它写入脚本标记的代码中。

下面的解决方案对我来说似乎比结合JavaScript和Razor更准确。看看这个: https://github.com/brooklynDev/NGon < / p >

你可以向ViewBag。正多边形中添加几乎任何复杂的数据,并在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>

它允许使用默认JavascriptSerializer序列化任何普通的旧式CLR对象 (POCOs)。

那些像我一样没有Json.Encode可用的人可以试试这个。

<script type="text/javascript">
var model = @Html.Raw(Json.Serialize(Model))
</script>