在视图 (cshtml
) 中的 JavaScript 中使用 Razor 语法是否可能或是否有解决方法?
我正在尝试将标记添加到 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>
@:
语法的更新感兴趣。
如 here 所述,使用 <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>
更新:
Scott Guthrie recently posted 关于 Razor 中的 @:
语法,如果您只需要添加一两行 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
值得注意的是,View 代码确实不是放置 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);
});
我刚刚写了这个辅助函数。将其放入 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);
注意我是如何不在它周围加上引号的。如果标题已经包含引号,则不会爆炸。似乎也能很好地处理字典和匿名对象!
@Html.Raw(Json.Encode(Model))
您正试图将方形钉子卡在圆孔中。
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>
请注意,您需要在 foreach
之后使用神奇的 <text>
标记来指示 Razor 应该切换到标记模式。
只要它位于 CSHTML 页面而不是外部 JavaScript 文件中,它就可以正常工作。
Razor 模板引擎不关心它输出什么,也不区分 <script>
或其他标记。
但是,您需要对字符串进行编码以防止 XSS 攻击。
HTML.Raw(Server.JavaScriptStringEncode(...))
HTML.Raw(HttpUtility.JavaScriptStringEncode(...))
- Server 属性现在没有此方法。 HttpUtility 可以。
The Razor template engine doesn't care what it's outputting and does not differentiate between <script> or other tags.
您确定要这样做吗? stackoverflow.com/questions/33666065/…
我更喜欢 "" 就像 "text>"
<script type="text/javascript">
//some javascript here
@foreach (var item in itens)
{
<!--
var title = @(item.name)
...
-->
</script>
@:
和 <text>
方法的分隔符
要添加的一件事 - 我发现 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>
现在您有一个名为 razorUserName
的全局 JavaScript 变量,您可以在客户端上访问和使用它。 Razor 引擎显然已经从 @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>
它允许任何可以使用默认 JavascriptSerializer
序列化的 plain old CLR objects (POCO)。
除了 @: 和 <text></text>
之外,还有一个选项。
使用 <script>
块本身。
当您需要根据 Razor 代码执行大量 JavaScript 时,您可以这样做:
@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);
}
像我一样没有 Json.Encode
的人可以试试这个。
<script type="text/javascript">
var model = @Html.Raw(Json.Serialize(Model))
</script>
@item.Title
包含单引号,则此代码将爆炸。data-
属性的 HTML,然后使用静态、不显眼的 javascript 来收集它来自 DOM 的信息。但整个讨论有点超出了问题的范围。