2013-01-06 19 views
6

EDIT: Vui lòng đọc cẩn thận tất cả các cách thông qua câu hỏi trước khi bạn xem xét trả lời câu hỏi. Tôi là không phải là hỏi về khả năng sử dụng trình xử lý sự kiện nội tuyến trong mã sản xuất, cũng như tôi không hỏi về cách tốt nhất để đạt được kết quả được hứa hẹn bởi bài viết tôi tham chiếu. Đây là câu hỏi về ngữ nghĩa Javascript và chi tiết triển khai trình duyệt, không phải về các phương pháp mã hóa tốt nhất.kiểu đầu vào = "gửi", trình xử lý onclick gọi this.form.submit(), và trả về không có giá trị

Cảm ơn bạn.

Nghe như một cơn ác mộng, phải không?

Tuy nhiên, tôi tìm thấy một số online advice rằng chủ trương làm chỉ là một điều như vậy để ngăn chặn đúp nộp một hình thức:

<input type="submit" 
     onclick="this.disabled=true; 
       this.value='Sending, please wait...'; 
       this.form.submit();" /> 

Gác lại bất kỳ cuộc thảo luận về những điều xấu xa của các event handler inline, những vấn đề tôi thấy đây là :

  1. Loại thẻ là "submit", do đó gửi biểu mẫu chứa của nó là hành vi mặc định của nó;
  2. Trình xử lý onclickrõ ràng gửi biểu mẫu có chứa;
  3. Trình xử lý onclick không trả về false để ngăn chặn hành vi mặc định (xem 1).

trực giác, tôi sẽ nghĩ rằng một nhấp chuột vào mục này sẽ làm chính xác ngược về những gì những tuyên bố bài viết - tức là, gửi biểu mẫu hai lần, một lần như một kết quả của sự rõ ràng submit() cuộc gọi, và sau đó một lần nữa là hành vi mặc định không được nhấn mạnh của điều khiển loại "submit".

Mặt khác, tôi đã viết một kịch bản PHP nhỏ (bên dưới) và thử nó với cả Firefox và Safari (tại thời điểm này chỉ có các trình duyệt thuận tiện) và nó chỉ ghi một mục nhập cho mỗi lần nhấp chuột vào nút:

<html> 
<head></head> 
<body> 
<?php 
    if (isset($_GET['action']) && $_GET['action'] == 'submit') { 
    $s = 'Got form submission at ' . time(); 
    error_log($s); 
    echo $s; 
    } 
    else { 
?> 
    <form action="http://localhost/~hephaestus/phptests/submittest.php?action=submit" 
     method="post"> 
    <input type="submit" 
      onclick="this.disabled=true; 
        this.value='Sending, please wait...'; 
        this.form.submit();" /> 
    </form> 
<?php 
    } 
?> 
</body> 
</html> 

Vì vậy, hai trình duyệt này thực sự thực hiện điều "đúng" (nơi "đúng" được xác định trong một số tài liệu mà tôi chưa thấy hoặc chưa đọc đủ) - có nghĩa là phân tích của tôi về các vấn đề là không đầy đủ hay sai?

Hoặc, phân tích của tôi có đúng hay không - nghĩa là các lần gửi đơn được quan sát là kết quả của những người thực hiện trình duyệt đưa vào trường hợp đặc biệt, để lưu các lập trình viên ngây thơ?

UPDATE:

Trong một nỗ lực để thực nghiệm kiểm tra các yêu cầu bồi thường bởi @sourcecode rằng phương pháp form.submit() là một số loại "nút thứ hai submit" trên một hình thức, và vì thế tùy thuộc vào các quy tắc quy định tại phần 17.13.2 of the HTML4 spec mà chỉ có thể có một "thành công" nút gửi, tôi thực hiện một vài bổ sung vào kịch bản thử nghiệm PHP của tôi:

<?php 
    if (isset($_GET['action']) && $_GET['action'] == 'submit') { 
    $s = 'Got form submission at ' . time() . ', tellme = ' . $_POST['tellme']; 
    error_log($s); 
    echo $s; 
    } 
    else { 
?> 
    <form action="http://localhost/~hephaestus/phptests/submittest.php?action=submit" 
     method="post"> 
    <input type="hidden" id="tellme" name="tellme" value="0" /> 
    <input type="submit" 
      onclick="this.disabled=true; 
        this.value='Sending, please wait...'; 
        this.form.submit(); 
        document.getElementById('tellme')=1;" /> 
    </form> 
<?php 
    } 
?> 

Trong Firefox, mã này tạo ra single entry lỗi đăng nhập:

Got biểu mẫu gửi tại timestamp, tellme = 1

không gợi ý rằng phương pháp-gọi là bằng cách nào đó được thay thế bởi nội tại hành vi hướng sự kiện của điều khiển.

Hơn nữa, nếu tôi bao gồm thêm một return false; sau khi thiết lập giá trị của tellme-1 (do đó ngăn cản sự kiện nhấp chuột từ tuyên truyền, và do đó ngăn ngừa các hành vi nội tại của sự kiểm soát), single lỗi đăng nhập là:

hình thức trình Got tại timestamp, tellme = 0

nghĩa là trong trường hợp này, việc nộp là kết quả của những lời khẩn cầu this.form.submit().

Mặt khác, khi tôi thử hai biến thể tương tự trong Safari, mỗi trong số họ mang lại cho tôi cùng một đơn lỗi đăng nhập:

Got biểu mẫu gửi tại timestamp, tellme = 0

Vì vậy, trong trường hợp của Safari, lời gọi phương thức luôn được ưu tiên hơn việc gửi theo sự kiện - có lẽ vì điều đó xảy ra trước đó.

Đó là. Chỉ. Tuyệt vời. : -/

Cập nhật thêm: Tôi có cơ hội kiểm tra điều này trên IE 8.0 trên Windows NT 5.1.

IE 8 phản ánh hành vi của Safari, tức là phương pháp form.submit() luôn được ưu tiên hơn việc gửi theo định hướng.

Mặc dù ngày nay hầu như không liên quan, tôi cũng nhận ra rằng tôi có một phiên bản IE 5.22 cổ đại trên một chiếc iMac PowerPC thậm chí còn cổ hơn đang chạy OS X 10.4.11. Bit thú vị của đố lịch sử ở đây là IE5 làm việc chính xác đối diện đến cách IE8 hoạt động: sự kiện-driven nộp luôn thay thế các phương pháp form.submit() - ngay cả khi sự kiện click đã bị ức chế từ tuyên truyền bởi một return false; tại kết thúc xử lý onclick! (Tuy nhiên, tôi chưa từng biết liệu đây có phải là lỗi hay tính năng hay không.) Tôi chưa bao giờ - và có thể không bao giờ!- chạy một bài kiểm tra để xác định xem nó có làm hỏng sự kiện ức chế sự kiện hay cố gắng làm một điều gì đó "thông minh".)

Tuy nhiên, cả hai trình duyệt IE chỉ thực hiện một lần gửi đơn.

Kết luận tạm thời của tôi là kết nối chính xác giữa điều khiển "gửi" và phương thức DOM form.submit() không được xác định rõ ràng và người thực hiện trình duyệt, trong trường hợp không có của bất kỳ hướng dẫn rõ ràng nào, thường làm những gì họ nghĩ tốt nhất (xem ví dụ: @Boris Zbarsky's answer).

Ít nhất trong các trường hợp Firefox, Safari và IE, người triển khai của họ thấy trước khả năng cả sự kiện và cuộc gọi phương thức đều có thể cạnh tranh để gửi cùng một biểu mẫu và thực hiện các bước (mặc dù khác nhau) gamut) để đảm bảo rằng chỉ một trong số họ sẽ thành công.

(tôi muốn vẫn chào đón câu trả lời bổ sung từ folks người biết internals trình duyệt khác nhau cũng đủ để bình luận, hoặc những người đã nạp lệnh PHP đơn giản của tôi sử dụng các trình duyệt khác hơn những người tôi đã thử nghiệm.)

+0

Khi JavaScript nội tuyến trông giống như là thời gian để suy nghĩ về tách logic và đánh dấu ... – elclanrs

+0

Phải, nhưng bạn sẽ nhận thấy rằng tôi đã nói "Bỏ qua bất kỳ cuộc thảo luận nào về các tệ nạn của trình xử lý sự kiện nội tuyến ..." là về cái gì khác hoàn toàn, tức là ngữ nghĩa Javascript và triển khai trình duyệt. – Hephaestus

Trả lời

3

Gecko (Firefox) chắc chắn phát hiện nhiều đệ trình và hủy bỏ những cái cũ hơn khi những cái mới xảy ra. Xem các thành viên mPendingSubmisson trong http://hg.mozilla.org/mozilla-central/file/c4abfca219e5/content/html/content/src/nsHTMLFormElement.h và việc xử lý nó trong http://hg.mozilla.org/mozilla-central/file/c4abfca219e5/content/html/content/src/nsHTMLFormElement.cpp (ví dụ trong nsHTMLFormElement::SubmitnsHTMLFormElement::PostHandleEvent (sau này là những gì được gọi từ các công cụ hành động mặc định cho trình điều khiển).

Về những gì spec nói, nó không rõ ràng với tôi rằng spec là nhất thiết phải lành mạnh, nhưng nó sống ở http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#concept-form-submit và cho thấy rằng cả hai lần gửi sẽ xảy ra, nhưng sau đó có thể hủy bỏ sớm hơn vì các chi tiết nội bộ của thuật toán "điều hướng".Tôi đã nộp https://www.w3.org/Bugs/Public/show_bug.cgi?id=20580 để sắp xếp thông số.

+0

Thông tin tốt ở đây, cảm ơn. Nó có phần nói rằng trong phương thức 'nsHTMLFormElement :: Submit()', nơi chúng kiểm tra thành viên 'mPendingSubmission' và xóa nó nếu nó đã được thiết lập, chúng có một nhận xét cho biết" chúng ta thi đua IE ở đây "(một ý nghĩ khá đáng sợ! :-), thay vì một cái gì đó như "chúng tôi thực hiện yêu cầu X của spec Y ở đây." Cảm ơn cũng cho con trỏ đến spec; Tôi nghi ngờ tôi sẽ tự mình tìm thấy nó. Một đọc khá dày đặc, nhưng tốt để biết nó có khi tôi đã sẵn sàng cho một số thể dục dụng cụ tinh thần hơn. – Hephaestus

+1

Mã ngày trở lại trước khi bất kỳ thông số kỹ thuật nào xác định hành vi này, vì vậy câu hỏi có liên quan là những trang web hành vi dựa vào. Và đó là hành vi của IE, tất nhiên; chúng ta đang nói 10 năm trước đây. –

0

Tôi sẽ tưởng tượng bạn sẽ cần phải sử dụng phương pháp stopPropogation(). Lý tưởng nhất là bạn sẽ gọi một hàm từ handler onclick của bạn thay vì làm cho nó tất cả inline .. see this other stackoverflow answer for a thorough explanation

+0

Tuy nhiên, thử nghiệm đơn giản của tôi cho thấy rằng tôi nhận được kết quả chính xác (chỉ gửi một lần) * mà không * trả về 'false' hoặc gọi' stopPropagation() '- câu hỏi là: TẠI SAO? – Hephaestus

1

Đây là khuyến cáo org w3 rằng:

  • Nếu một hình thức có chứa hơn một nút, chỉ nộp nút gửi được kích hoạt thành công.

    Tương tự ở đó với Gửi Nhấp và biểu mẫu JS cục bộ. Chức năng gửi, chỉ có "gửi" được kích hoạt chứ không phải chức năng form.submit. Bởi vì gửi là tiểu học và chức năng JS chỉ là thứ yếu ..
    bạn có thể học thêm ở đây link
+0

Hmm ... Bạn có thể rất đúng về phương thức 'form.submit()' bị thay thế bởi hành động nội tại của nút gửi "thành công" - nhưng tài liệu W3C bạn đã trích dẫn không cung cấp một bê tông tuyên bố rằng đó là trường hợp. Nếu bạn có thể cung cấp tham chiếu đến tài liệu chỉ rõ mối quan hệ "chính/phụ" mà bạn đang đề cập đến giữa hành vi nội tại của điều khiển và phương thức phần tử DOM, tôi có thể chấp nhận câu trả lời của bạn. – Hephaestus

+0

sự kiện chính là những gì gọi trực tiếp mà không sử dụng bất kỳ JS, ví dụ mẫu gửi trên nhấp nút gửi, trong khi các sự kiện phụ được hình thành khi JS làm cho một cái gì đó để thực hiện như form.submit(), và tài liệu W3C đã cung cấp bê tông này tuyên bố - theo liên kết của tôi (điều khiển thành công - 2 pt) Và mối quan hệ chính/giây này được phát minh bởi tôi để chỉ giải thích u .... :) – sourcecode

+0

Xin lỗi, tôi vẫn không hoàn toàn mua nó. Phần 17.13.2 của tài liệu đó ** chỉ ** các điều khiển địa chỉ, chứ không phải các phương thức phần tử DOM. Dấu đầu dòng 2 của phần 17.13.2 ** chỉ ** các địa chỉ gửi * các nút *, không phải phương thức 'form.submit()'. Vì vậy, trong khi nó có thể hợp lý để * suy luận * rằng các phương thức phần tử DOM nằm trong cùng các quy tắc chung như các điều khiển, nó vẫn sẽ không có gì hơn là một suy luận * cho đến khi được sao lưu bằng một số câu lệnh rõ ràng giải quyết mối quan hệ giữa các điều khiển và phần tử DOM phương pháp head-on. – Hephaestus

1

KHÔNG BAO GIỜ thực thi kịch bản trong onclick của một đệ trình và chắc chắn KHÔNG gửi biểu mẫu !!! Ngoài ra nếu bạn vô hiệu hóa nút, việc gửi có thể bị dừng lại!

Nếu mã trong bài viết hoạt động, đó là do may mắn và tôi tưởng tượng nhiều trình duyệt tham gia vào tình trạng đua khi có nút gửi bị tắt và gửi sự kiện trong lần nhấp vào nút bị tắt này.

Dưới đây là một gợi ý inline của cái gì mà chuyện làm việc trong bất kỳ trình duyệt

<form action="..." method="post" 
onsubmit="document.getElementById('subbut').innerHTML='Sending, please wait...'"> 
    <span id="subbut"><input type="submit" /></span> 
</form> 

và cùng kín đáo:

<html> 
<head> 
<script> 
window.onload=function() { 
    document.getElementById("form1").onsubmit=function() { 
    document.getElementById('subbut').innerHTML='Sending, please wait...'; 
    } 
} 
</script> 
</head> 
<body> 
<form action="..." method="post" id="form1"> 
    <span id="subbut"><input type="submit" /></span> 
</form> 
</body> 
<html> 
+0

Một lần nữa, tôi phải chỉ ra rằng tôi không hỏi về sự khuyến khích làm những gì bài viết gợi ý. Tôi hỏi tại sao nó thực sự hoạt động theo cách thực hiện trên hai trình duyệt mà tôi đã thử nghiệm nó. – Hephaestus

+0

Tôi không thể cho bạn biết ngoại trừ tôi rùng mình với mã họ trình bày – mplungjan

+0

Tương tự như vậy! :-) Chắc chắn ví dụ về phong cách "không phô trương" của bạn là một cách tuyệt vời để * tổ chức * mã và tôi đặc biệt thích thay thế bán buôn của nút bằng văn bản "vui lòng chờ". – Hephaestus

Các vấn đề liên quan