การใช้มีดโกนภายใน JavaScript


435

เป็นไปได้หรือมีวิธีแก้ปัญหาในการใช้ไวยากรณ์ของมีดโกนใน 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>

3
คุณอาจสนใจอัพเดตของฉันเกี่ยวกับ@:ไวยากรณ์
StriplingWarrior

@anyone พิจารณาทำอย่างนี้อย่างน้อยใส่ข้อมูลในแท็กสคริปต์แยกต่างหากที่เพียงกำหนด JSON บางอย่างซึ่งจะใช้ใน JS Back-end-coupled JS ที่ส่วนหน้าได้รับมรดก PITA สำหรับฉันในหลายโอกาส อย่าเขียนรหัสด้วยรหัสหากคุณไม่จำเป็นต้อง แจกข้อมูลแทน
Erik Reppen

คำตอบ:


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 โพสต์เมื่อเร็ว ๆ นี้เกี่ยวกับ@:ไวยากรณ์ในมีดโกนซึ่งน้อยกว่า 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ถูกต้องมากขึ้น

เพื่อความกระจ่าง@:ชัดกองกำลังมีดโกนกลับเข้าสู่โหมดข้อความแม้ว่าการaddMarkerโทรจะดูเหมือนรหัส C # มาก มีดโกนจากนั้นหยิบ@item.Propertyไวยากรณ์เพื่อบอกว่ามันควรจะเอาท์พุทเนื้อหาของคุณสมบัติเหล่านั้นโดยตรง

อัปเดต 2

เป็นที่น่าสังเกตว่ารหัสการดูไม่ใช่เรื่องที่ดีที่จะใส่รหัส JavaScript ควรวางโค้ด JavaScript ใน.jsไฟล์สแตติกแล้วควรรับข้อมูลที่ต้องการจากการโทร Ajax หรือโดยการสแกนdata-แอตทริบิวต์จาก HTML นอกเหนือจากการทำให้เป็นไปได้ที่จะแคชโค้ด JavaScript ของคุณสิ่งนี้ยังช่วยหลีกเลี่ยงปัญหาการเข้ารหัสเนื่องจากมีดโกนถูกออกแบบมาเพื่อเข้ารหัสสำหรับ HTML แต่ไม่ใช่จาวาสคริปต์

ดูรหัส

@foreach(var item in Model)
{
    <div data-marker="@Json.Encode(item)"></div>
}

รหัสจาวาสคริปต์

$('[data-marker]').each(function() {
    var markerData = $(this).data('marker');
    addMarker(markerData.Latitude, markerData.Longitude,
              markerData.Description, markerData.Title);
});

3
ฉันไม่เข้าใจตัวอย่างที่อัปเดตของคุณ ฟังก์ชั่น addmarker นั้นถูกต้องหรือไม่?
NVM

2
@NVM: แทนที่จะส่งรหัสจาวาสคริปต์เดียวกันหลายครั้งฉันขอแนะนำให้สร้างฟังก์ชั่นจาวาสคริปต์เดียว (ซึ่งสามารถเก็บไว้ในไฟล์. js ที่แคช) และเอาท์พุทการโทรไปยังฟังก์ชันนั้นได้หลายครั้ง ฉันไม่รู้ว่าฟังก์ชั่นนั้นถูกต้องหรือไม่: ฉันเพิ่งจะอ้างอิงมันในโค้ดของ OP
StriplingWarrior

1
ทำไม '@ Model.Latitude' ในรุ่นก่อน ทำไมไม่มีรายการความโดดเด่น?
NVM

5
ตัวแปร C # ของคุณต้องได้รับการยกเว้น หาก@item.Titleมีใบเสนอราคาเดียวรหัสนี้จะระเบิด
mpen

7
@ Mark: สังเกตดี ที่จริงแล้วฉันมักจะไม่รวม javascript และมีดโกนไว้ในรหัสของตัวเอง: ฉันชอบที่จะใช้มีดโกนเพื่อสร้าง HTML ด้วยdata-คุณลักษณะจากนั้นใช้จาวาสคริปต์แบบคงที่และไม่สร้างความรำคาญเพื่อรวบรวมข้อมูลนี้จาก DOM แต่การสนทนาทั้งหมดนั้นอยู่นอกเหนือขอบเขตของคำถาม
StriplingWarrior

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

2
คุณสามารถขยายคำตอบของ PJH ได้หรือไม่? คุณจะระบุชื่อเรื่องได้อย่างไรหากคุณเพียงแค่เข้ารหัส "Model"?
obesechicken13

2
นอกจากนี้เมื่อฉันลองใช้วิธีนี้กับ Model.Title ฉันจะได้รับราคาพิเศษจากจาวาสคริปต์ที่เข้ารหัส ฉันไม่สามารถกำจัดคำพูดได้แม้ว่าฉันจะต่อมันกับสิ่งอื่น คำพูดเหล่านั้นกลายเป็นส่วนหนึ่งของ js ของคุณ
obesechicken13

1
ความคิดเห็นของ PJH นั้นยอดเยี่ยมมาก ในแบบที่คุณยกเลิกการจัดวางโมเดลฝั่งเซิร์ฟเวอร์ลงในบล็อก javascript
netfed

24

คุณกำลังพยายามจะตรึงหมุดสี่เหลี่ยมในรูกลม

มีดโกนตั้งใจให้เป็นภาษาแม่แบบสร้าง HTML คุณอาจได้รับมันเพื่อสร้างรหัส JavaScript แต่มันไม่ได้ถูกออกแบบมาเพื่อสิ่งนั้น

ตัวอย่างเช่น: จะเกิดอะไรขึ้นถ้าModel.Titleมีเครื่องหมายอะโพสโทรฟี? สิ่งนี้จะทำลายรหัส JavaScript ของคุณและมีดโกนจะไม่สามารถหลบหนีได้อย่างถูกต้องตามค่าเริ่มต้น

มันอาจจะเหมาะสมกว่าที่จะใช้ตัวสร้างสตริงในฟังก์ชันตัวช่วย มีแนวโน้มว่าจะมีผลที่ตามมาของวิธีการนั้นน้อยลง


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เพื่อระบุว่ามีดโกนควรเปลี่ยนเป็นโหมดมาร์กอัป


1
ย้ำ Model (โดย foreach) และทำเครื่องหมาย @ Model.Latidue? ฟังก์ชั่นของการทำซ้ำคืออะไร? ฉันคิดว่าพลาดบางสิ่ง มันอาจจะเป็น @ item.Latitude เป็นต้น
Nuri YILMAZ

12

สิ่งนี้จะใช้ได้ดีตราบใดที่อยู่ในหน้า CSHTML ไม่ใช่ไฟล์ JavaScript ภายนอก

เอ็นจิ้นเท็มเพลตมีดโกนไม่สนใจสิ่งที่กำลังแสดงผลและไม่แยกความแตกต่างระหว่าง<script>หรือแท็กอื่น ๆ

อย่างไรก็ตามคุณต้องเข้ารหัสสตริงเพื่อป้องกันการโจมตีXSS


2
ฉันได้อัปเดตคำถามของฉันแล้วมันไม่ได้ผลสำหรับฉัน - ความคิดใด ๆ ที่ผิดปกติ ขอบคุณ
raklos

3
@raklos: คุณต้องหลบหนีสายของคุณ โทรHTML.Raw(Server.JavaScriptStringEncode(...))
SLaks

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

11

ฉันชอบ "<! -" "->" ชอบ "text>"

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

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

</script>

นี้เป็นวิจิตรพิสดารทางออกหนึ่งที่ทำงานสำหรับฉันเพราะข้อความที่ฉันต้องการที่จะรวมถึงการมีตัวคั่นบางอย่างที่มีดโกนไม่ชอบด้วย@:และ<text>วิธีการ
BuddyZ

8

สิ่งหนึ่งที่ควรเพิ่ม - ฉันพบว่ามีดโกนซินแท็กซ์ของมีดโกน (และอาจเป็นคอมไพเลอร์) ตีความตำแหน่งของวงเล็บเปิดแตกต่างกัน:

<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ซึ่งคุณสามารถเข้าถึงและใช้งานบนไคลเอนต์ เอ็นจิ้นมีดโกนได้แยกค่าจาก@User.Identity.Name(ตัวแปรฝั่งเซิร์ฟเวอร์) และใส่ไว้ในรหัสที่เขียนไปยังแท็กสคริปต์ของคุณ


6

โซลูชันต่อไปนี้ดูเหมือนว่าจะแม่นยำกว่าฉันมากกว่ารวม JavaScript กับมีดโกน ลองใช้งานได้เลย: 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ที่สามารถต่อเนื่องโดยใช้ค่าเริ่มต้น


5

นอกจากนี้ยังมีอีกหนึ่งตัวเลือกที่ดีกว่า @ <text></text>และ

ใช้<script>บล็อกนั่นเอง

เมื่อคุณต้องทำจาวาสคริปต์ขนาดใหญ่ขึ้นอยู่กับรหัสมีดโกนคุณสามารถทำสิ่งนี้ได้:

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

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

ข้อดีของวิธีนี้คือมันไม่ผสม JavaScript กับมีดโกนมากเกินไปเพราะการผสมมันเข้าด้วยกันมาก ๆ จะทำให้เกิดปัญหาการอ่านได้ในที่สุด บล็อกข้อความขนาดใหญ่ก็อ่านไม่ได้เช่นกัน


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);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.