Vấn đề chọn phần tử trong mẫu đặt phòng iframe


8

Tôi đang cố gắng chọn trường email trong mẫu đặt phòng iframe này. Cuối cùng tôi muốn làm một cái gì đó khác với trường nhưng bây giờ là một thử nghiệm tôi chỉ muốn chọn phần tử và thay đổi trình giữ chỗ.

Nhận được lỗi này vì vậy tôi không chọn đúng: Uncaught TypeError: Không thể đặt thuộc tính 'giữ chỗ' của null tại HTMLButtonEuity.changeCopy

Bạn có thể xem phiên bản trực tiếp của mã của tôi tại đây và thấy lỗi trong bảng điều khiển khi bạn nhấp vào nút ở trên cùng: https://finnpegler.github.io/cart_recover/

Tôi cũng đã bao gồm mã dưới dạng đoạn trích bên dưới nhưng nó đưa ra một lỗi khác với các khung gốc.

var iframe = document.getElementById("booking-widget-iframe");
var field = iframe.contentWindow.document.querySelector("booking[email]");

function changeCopy() {
field.placeholder = "hello";
}

document.getElementById("button").addEventListener("click", changeCopy)
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test site for Cart Recover Tool</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" media="screen" href="stylesheet.css" />
<link href="https://fonts.googleapis.com/css?family=Bree+Serif|Open+Sans&display=swap" rel="stylesheet">
<link rel="icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">  
</head>
<body>
Clicking this button should change the placeholder text in the email field below
<button id = "button">Click</button>
</body>

<script src="https://bettercleans.launch27.com/jsbundle"></script><iframe id="booking-widget-iframe" src="https://bettercleans.launch27.com/?w_cleaning" style="border:none;width:100%;min-height:2739px;overflow:hidden" scrolling="no"></iframe>
<script src="script.js"></script>


1
Các trình duyệt sẽ chặn các nỗ lực theo khung cha mẹ để thao tác nội dung hoặc cấu trúc của khung con, nếu chúng không cùng nguồn gốc, tức là không cùng tên miền. Trong trường hợp của bạn, nguồn gốc khung cha là finnpegler.github.io nhưng nguồn gốc khung con là bettercleans.launch27.com. Nếu bạn có quyền truy cập vào mã nguồn js của bettercleans.launch27.com, bạn có thể thử và xử lý nó bằng cách đăng một tin nhắn lên khung con. Xem bài đăng SO này có giúp bạn stackoverflow.com/questions/25098021/ không
Nivi M

Câu trả lời:


6

Lý do tại sao trường là null là vì khi biến được đặt, giá trị bị chặn. Hãy thử mở bảng điều khiển JavaScript của bạn trên trang và dán vào

var iframe = document.getElementById("booking-widget-iframe");

Giống như trong nguồn, sẽ hoạt động, nhưng sau đó xem điều gì sẽ xảy ra khi bạn nhập:

var field = iframe.contentWindow.document.querySelector("booking[email]");

Bạn sẽ nhận được một cái gì đó như lỗi sau:

Uncaught DOMException: Blocked a frame with origin "https://finnpegler.github.io" from accessing a cross-origin frame.
    at <anonymous>:1:34

Vì vậy, vấn đề không phải field.placeholder = "hello";là null, đó là trường không bao giờ được đặt vì nó bị chặn từ nguồn có nguồn gốc chéo.

Cách khắc phục điều này: Nếu bạn có quyền truy cập vào https://bettercleans.launch27.com/?w_cleaning&iframe_id=j8szoz0b4 , sau đó ở đâu đó trên nguồn của trang đó, hãy nhập đoạn mã sau:

<script>
addEventListener("message", function(e) {
    console.log(e.data);
    if(e.data["setIt"]) {
        document.querySelector("booking[email]").placeholder = e.data["setIt"];
         e.source.postMessage({
             hi:"I did it" 
         });
    }

});


</script>

Sau đó, trên https://finnpegler.github.io/cart_recover/ nguồn trang của bạn ở đâu đó, nhập mã:

<script>
var iframe;
addEventListener("load", function() {
    iframe = document.getElementById("booking-widget-iframe");
    iframe.contentWindow.postMessage({
        setIt: "hello"
    });

});
addEventListener("message", function(e) {
    console.log(e);
})
</script>

Cảnh báo: mã chưa được kiểm tra, nhưng đây là ý tưởng cơ bản: với JavaScript phía máy khách, bạn không thể chỉnh sửa trực tiếp các thành phần của iframe, vì vậy cách để giao tiếp với nó là gửi tin nhắn đến iframe bằng iframe.contentWindow.postMessage. Về phía iframe, bạn có thể đọc tin nhắn đi kèm với "tin nhắn" của người nghe sự kiện (hoặc bạn có thể thực hiện window.onmessage). Sau đó, bạn có thể gửi dữ liệu hoặc văn bản JSON dưới dạng tin nhắn đến iframe và đọc nó với e.data. Vì vậy, trong ví dụ trên (chưa được kiểm tra), khi trang github chính muốn thay đổi giá trị của trình giữ chỗ thành một số tiền cụ thể, nó chỉ cần gửi một đối tượng JSON chứa dữ liệu giữ chỗ đến iframe, và sau đó ở phía nguồn iframe, nó đọc thông báo đến đó, kiểm tra JSON nếu nó có khóa được đặt để đặt giữ chỗ và nếu nó có khóa đó, thì

Hãy cho tôi biết nếu bạn có bất kỳ câu hỏi nhiều hơn nữa.

Dưới đây là một số tài liệu tham khảo:

https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage https://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage https://javascript.info/ giao tiếp chéo cửa sổ https://bl.ocks.org/pbojinov/8965299 https://www.ilearnjavascript.com/plainjs-postmessage-and-iframes/ https://medium.com/@Farzad_YZ/cross-domain -iframe-cha mẹ-truyền thông-403912fff692


0

Trước tiên, hãy mang lại sự rõ ràng về những gì đang thực sự xảy ra. Để hỗ trợ phân tích, tôi đã sửa đổi tập lệnh của mình mà không đưa ra bất kỳ tác dụng phụ nào như sau:

var iframe = document.getElementById( "booking-widget-iframe" );

console.log( `iframe: ${ iframe }` );
console.log( `iframe.contentWindow: ${ iframe.contentWindow }` );
console.log( `iframe.contentWindow.document: ${ iframe.contentWindow.document }` );
console.log( `iframe.contentWindow.document.querySelector("booking[email]"): ${ iframe.contentWindow.document.querySelector( "booking[email]" ) }` );

function changeCopy() {
    console.log( "-------------------------------------------------------------------------------" );
    console.log( "changeCopy: started" );
    console.log( "-------------------------------------------------------------------------------" );

    var iframe = document.getElementById( "booking-widget-iframe" );

    console.log( `iframe: ${ iframe }` );
    console.log( `iframe.contentWindow: ${ iframe.contentWindow }` );
    console.log( `iframe.contentWindow.document: ${ iframe.contentWindow.document }` );
    console.log( `iframe.contentWindow.document.querySelector("booking[email]"): ${ iframe.contentWindow.document.querySelector( "booking[email]" ) }` );

    var field = iframe.contentWindow.document.querySelector( "booking[email]" );
    field.placeholder = "hello";

    console.log( "-------------------------------------------------------------------------------" );
    console.log( "changeCopy: finished" );
    console.log( "-------------------------------------------------------------------------------" );
}

document.getElementById( "button" ).addEventListener( "click", changeCopy )

Tải tài liệu với tập lệnh trên đã chứng minh kết quả sau: Chạy đầu ra của tập lệnh

Chúng ta đã học được gì từ đầu ra?

  1. Trước khi nhấp vào nút, hãy iframe.contentWindow.document.querySelector( "booking[email]" )đánh giá null. Do đó, biến fieldcơ bản là null.

  2. Tại sao iframe.contentWindow.document.querySelector( "booking[email]" )đánh giá null trước khi nhấp vào nút ?

    • iframetài liệu không được tải, trình duyệt (Safari) đã xem xét nó dưới mức tối ưu để chạy các chính sách bảo mật giữa khung chính và khung con.
  3. Do thời gian tôi ép vào Bấm nút, documentcủa #booking-widget-iframe(khung con) đã được nạp hoàn toàn, và thực thi các chính sách bảo mật giữa các khung phụ huynh và đứa trẻ được kích hoạt. Do đó, nỗ lực truy cập iframe.contentWindowđã bị chặn ngay lập tức do không tuân thủ chính sách khung có nguồn gốc chéo.

Nghị quyết có thể:

  • Để các tập lệnh trong khung chính được phép truy cập vào các đối tượng trong khung con, cả hai khung cha và khung con phải được tải từ cùng domain(ví dụ: https://bettercleans.launch27.com ) và port(không liên quan đến trường hợp được xem xét ).
  • Ngoài ra, sử dụng tin nhắn bài để tương tác giữa cả hai khung như được ghi trong Window.postMessage () .

Giả sử bạn có thể áp dụng độ phân giải, có một vấn đề khác sẽ xuất hiện. iframe.contentWindow.document.querySelector("booking[email]")nhưng sẽ null. Nguyên nhân sâu xa của vấn đề tiếp theo là do không bookingtìm thấy yếu tố nào trong tài liệu được nhắm mục tiêu. Nói cách khác, bộ chọn "booking[email]"là sai.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.