在JavaScript中使用Razor


435

是否可以解决在视图(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>

3
您可能对我有关@:语法的更新感兴趣。
StriplingWarrior

@anyone考虑这样做,至少将数据放在单独的脚本标签中,该脚本标签仅定义一些JSON,然后在JS中使用。在许多情况下,前端上的后端耦合JS对我来说都是旧版PITA。不必使用代码编写代码。而是交出数据。
Erik Reppen '17

Answers:


637

使用<text>伪元素,如所描述这里,迫使剃刀编译器返回到内容模式:

<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最近发布了有关@: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#代码,Razor也会强制返回文本模式。然后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);
});

3
我不明白您的更新示例。addmarker函数正确吗?
NVM

2
@NVM:建议不要创建一个javascript函数(可以将其保存在缓存的.js文件中),而不是多次输出相同的javascript代码,并输出对该函数的多个调用。我不知道该功能是否正确:我只是将其基于OP的代码。
StriplingWarrior

1
为什么在foreach中使用“ @ Model.Latitude”。为什么不是item.Latitude?
NVM

5
您的C#变量需要转义。如果@item.Title包含单引号,则此代码将爆炸。
mpen 2014年

7
@Mark:好的观察。事实上,我通常不结合JavaScript和剃须刀在我自己的代码:我更喜欢用剃刀与生成HTML data-属性,然后用静态的,不显眼的JavaScript来搜集从DOM这一信息。但是整个讨论超出了问题的范围。
StriplingWarrior 2014年

39

我刚刚编写了此辅助函数。放入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);

请注意,我如何不加引号。如果标题已经包含引号,则不会爆炸。似乎也可以很好地处理字典和匿名对象!


19
如果您尝试在视图中对对象进行编码,则无需创建帮助程序代码,该代码已经存在。我们一直都在使用@Html.Raw(Json.Encode(Model))
PJH 2014年

2
您可以扩展答案PJH吗?如果仅编码“模型”,如何指定标题?
obesechicken15年

2
另外,当我用Model.Title尝试这种方法时,我在编码的javascript周围得到了一些额外的报价。即使将其连接到其他内容,也无法摆脱引号。这些引号成为您的js的一部分。
obesechicken15年

1
PJH的评论很棒。您可以通过某种方式将服务器端模型反序列化为javascript块。
netfed

24

您正在尝试将方形钉卡在圆孔中。

Razor旨在作为HTML生成模板语言。您可能会很高兴获得它来生成JavaScript代码,但这并不是为此而设计的。

例如:如果Model.Title包含撇号怎么办?那会破坏您的JavaScript代码,并且Razor默认情况下不会正确地对其进行转义。

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


17

您看到什么具体错误?

这样的事情可能会更好地工作:

<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应该切换到标记模式。


1
迭代模型(通过foreach)并标记为@ Model.Latidue?迭代的功能是什么?我认为那错过了一些东西。它可能是@ item.Latitude等
Nuri

12

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

Razor模板引擎不在乎它的输出,也不区分<script>其他标签。

但是,您需要对字符串进行编码以防止XSS攻击。


2
我已经更新了我的问题,它对我不起作用-任何想法出了什么问题?谢谢
raklos 2011年

3
@raklos:您需要转义字符串。致电HTML.Raw(Server.JavaScriptStringEncode(...))
SLaks 2011年

1
HTML.Raw(HttpUtility.JavaScriptStringEncode(...))- 服务器属性现在没有此方法。HttpUtility可以。
it3xl

1
The Razor template engine doesn't care what it's outputting and does not differentiate between <script> or other tags.您确定吗?stackoverflow.com/questions/33666065/…–
HMR

2
@HMR:我编写此答案时不存在该功能。
Slaks 2015年

11

我更喜欢“ <!-”“->”像“ text>”

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

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

</script>

这很奇怪,这是一个对我有用的解决方案,因为我需要包含的文本包含Razor不喜欢使用@:<text>方法的一些定界符
BuddyZ

8

要添加的一件事-我发现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

一个简单而简单的例子:

<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(服务器端变量)提取了该值,并将其放入了写入脚本标签的代码中。


6

对于我来说,以下解决方案似乎比将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>

它允许使用default序列化任何普通的旧CLR对象(POCO)JavascriptSerializer


5

除了@:和,还有一个选项<text></text>

使用<script>块本身。

当您需要根据Razor代码编写大量JavaScript时,可以这样做:

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

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

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


4

以前的解决方案都无法正常工作...我已经尝试了所有方法,但是并没有给我预期的结果...最后,我发现代码中存在一些错误...并且给出了完整的代码下面。

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

4

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

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

    /* String */
    var str = '@stringvariable';
    alert(str);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.