ChatGPT解决这个技术问题 Extra ChatGPT

在 JavaScript 中使用 Razor

在视图 (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>
您可能对我关于 @: 语法的更新感兴趣。
@任何考虑这样做的人,至少将数据放在一个单独的脚本标签中,该标签简单地定义了一些 JSON,然后在 JS 中使用。在很多情况下,前端的后端耦合 JS 对我来说都是遗留的 PITA。如果没有必要,不要用代码编写代码。而是交出数据。

C
Community

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);
});

我不明白你更新的例子。 addmarker 函数是否正确?
@NVM:我建议不要多次输出相同的 javascript 代码,而是创建一个 javascript 函数(可以保存在缓存的 .js 文件中),然后输出对该函数的多次调用。我不知道该功能是否正确:我只是基于 OP 的代码。
为什么在 foreach 中使用“@Model.Latitude”。为什么不是 item.Latitude?
您的 C# 变量需要转义。如果 @item.Title 包含单引号,则此代码将爆炸。
@Mark:很好的观察。事实上,我通常不会在我自己的代码中将 javascript 和 Razor 完全结合起来:我更喜欢使用 Razor 生成带有 data- 属性的 HTML,然后使用静态、不显眼的 javascript 来收集它来自 DOM 的信息。但整个讨论有点超出了问题的范围。
C
Community

我刚刚写了这个辅助函数。将其放入 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))
你能扩展你的答案 PJH 吗?如果您只是编码“模型”,您如何指定标题?
此外,当我使用 Model.Title 尝试这种方法时,我在编码的 javascript 周围得到了一些额外的引号。即使我将它连接到其他东西,我也无法摆脱引号。这些引号成为您的 js 的一部分。
PJH 的评论很棒。在某种程度上,您将服务器端模型反序列化到 javascript 块中。
P
Peter Mortensen

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

Razor 旨在作为一种 HTML 生成模板语言。您很可能会使用它来生成 JavaScript 代码,但它并不是为此而设计的。

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

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


m
marcind

你看到了什么具体的错误?

这样的事情可能会更好:

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


迭代模型(通过foreach)并标记@Model.Latitude?什么是迭代函数?我认为这遗漏了一些东西。它可能是@item.Latitude 等
P
Peter Mortensen

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

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

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


我已经更新了我的问题,它对我不起作用 - 任何想法有什么问题吗?谢谢
@raklos:您需要转义您的字符串。呼叫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/…
@HMR:当我写这个答案时,这个功能不存在。
F
Fernando JS

我更喜欢 "" 就像 "text>"

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

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

</script>

奇怪的是,这是对我有用的一种解决方案,因为我需要包含的文本有一些 Razor 不喜欢使用 @:<text> 方法的分隔符
A
Andy

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

P
Peter Mortensen

一个简单而直接的例子:

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


P
Peter Mortensen

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


P
Peter Mortensen

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

使用 <script> 块本身。

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

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

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

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


P
Peter Mortensen

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

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

P
Peter Mortensen

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

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

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

r
reubano

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

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