Javascript nội tuyến (trong HTML) hoạt động như thế nào?


129

Tôi biết đây là thực hành xấu. Đừng viết mã như thế này nếu có thể.

Tất nhiên, chúng tôi sẽ luôn thấy mình trong các tình huống trong đó một đoạn mã Javascript thông minh có thể giải quyết vấn đề nhanh chóng.

Tôi đang theo đuổi truy vấn này vì muốn hiểu đầy đủ về những gì xảy ra (và những cạm bẫy tiềm ẩn) khi một cái gì đó như thế này được viết:

<a href="#" onclick="alert('Hi')">Click Me</a>

Theo như tôi có thể nói đây là chức năng giống như

<script type="text/javascript">
   $(function(){ // I use jQuery in this example
       document.getElementById('click_me').onclick = 
           function () { alert('Hi'); };
   });
</script>
<a href="#" id="click_me">Click Me</a>

Ngoại suy từ điều này có vẻ như chuỗi được gán cho thuộc tính onclickđược chèn trong một hàm ẩn danh được gán cho trình xử lý nhấp chuột của phần tử. Đây thực sự là trường hợp?

Bởi vì tôi đang bắt đầu làm những việc như thế này:

<a href="#" onclick="$(this).next().fadeIn(); return false;">Display my next sibling</a> <!-- Return false in handler so as not to scroll to top of page! --> 

Mà hoạt động. Nhưng tôi không biết số tiền này là bao nhiêu. Có vẻ đáng ngờ vì không có chức năng rõ ràng đang được trả lại từ!

Bạn có thể hỏi, tại sao bạn làm điều này, Steve? Inline JS là thực hành xấu!

Thành thật mà nói, tôi mệt mỏi khi chỉnh sửa ba phần mã khác nhau chỉ để sửa đổi một phần của trang, đặc biệt là khi tôi chỉ tạo mẫu một cái gì đó để xem liệu nó có hoạt động không. Thật dễ dàng hơn nhiều và đôi khi còn có ý nghĩa đối với mã liên quan cụ thể đến phần tử HTML này được xác định ngay trong phần tử: Khi tôi quyết định 2 phút sau đó, đây là một ý tưởng tồi tệ, khủng khiếp tôi có thể nuke toàn bộ div (hoặc bất cứ điều gì ) và tôi không có một loạt các hành trình JS và CSS bí ẩn treo xung quanh trong phần còn lại của trang, làm chậm quá trình kết xuất một chút. Điều này tương tự như khái niệm về địa phương của tham chiếu nhưng thay vì nhớ cache, chúng tôi đang xem xét các lỗi và sự phình to mã.


3
Bạn đã đúng, đó là một chức năng ẩn danh.
bhamlin

1
Bạn sẽ cần móc truy vấn cho #click_mesự kiện DOM đã có hoặc đặt tập lệnh sau nút.
Bergi

1
Trong một giao diện điều khiển, làm document.getElementById("click_me").onclick;. Hoặc cảnh báo nó. Bạn sẽ thấy rằng nó là trong một chức năng.
D. Strout

Câu trả lời:


96

Bạn đã hiểu đúng, nhưng bạn chưa tính đến thisgiá trị được cung cấp cho mã nội tuyến.

<a href="#" onclick="alert(this)">Click Me</a>

thực sự gần hơn với:

<a href="#" id="click_me">Click Me</a>
<script type="text/javascript">
document.getElementById('click_me').addEventListener("click", function(event) {
    (function(event) {
        alert(this);
    }).call(document.getElementById('click_me'), event);
});
</script>

Trình xử lý sự kiện nội tuyến được đặt thisbằng với mục tiêu của sự kiện. Bạn cũng có thể sử dụng chức năng ẩn danh trong tập lệnh nội tuyến

<a href="#" onclick="(function(){alert(this);})()">Click Me</a>

7
Tập lệnh phải xuất hiện sau thẻ, nếu không, thẻ không tồn tại khi được thực thi - Tôi khuyên bạn nên thay đổi câu trả lời của mình để phản ánh điều này.
không xác định

Làm thế nào để tôi tuyên truyền eventvới một nội tuyến onclick='myFunction(event)'??
oldboy

9

Trình duyệt làm gì khi bạn có

<a onclick="alert('Hi');" ... >

là đặt giá trị thực của "onclick" thành một cái gì đó hiệu quả như:

new Function("event", "alert('Hi');");

Đó là, nó tạo ra một hàm mong đợi một tham số "sự kiện". (Chà, IE thì không, nó giống một hàm ẩn danh đơn giản hơn.)


2
Ah. Vì vậy, tôi thực sự có thể sử dụng biến eventđể truy xuất sự kiện (và phần tử khởi tạo từ nó thông qua event.target), từ đoạn mã JS nội tuyến của tôi! Mát mẻ.
Steven Lu

1
IE thực sự không vượt qua được eventtham số, nhưng nếu bạn sử dụng eventbên trong hàm ẩn danh này thì IE sẽ hiểu nó là Đối tượng sự kiện thực tế. Vì hàm ẩn danh được đặt làm thuộc tính của windowđối tượng trong IE, nên nó sẽ thấy điều này là window.event.
rdleal

8

Dường như có rất nhiều thực hành xấu được ném xung quanh các thuộc tính Event Handler. Thực tiễn xấu là không biết và sử dụng các tính năng có sẵn ở nơi phù hợp nhất. Các thuộc tính sự kiện có đầy đủ các tiêu chuẩn Tài liệu W3C và không có gì xấu về chúng. Không khác gì đặt kiểu nội tuyến, cũng là Tài liệu W3C và có thể hữu ích theo thời gian. Cho dù bạn đặt nó được bọc trong các thẻ script hay không, nó sẽ được hiểu theo cùng một cách.

https://www.w3.org/TR/html5/webappapis.html#event-handler-idl-attribut


2
Vâng, tôi có khuynh hướng đồng ý và thậm chí tôi đã cung cấp "lý do" hợp lý cho lý do tại sao loại sử dụng mã nội tuyến cụ thể này có thể được biện minh trong một số tình huống. Nhưng thực tế là khi một ứng dụng (ứng dụng web hay nói cách khác) trở nên phức tạp nhất định (và điều này thậm chí thường không mất nhiều thời gian hoặc công sức để tiếp cận) có rất ít đoạn được bố trí về bố cục HTML có khả năng được kiến ​​trúc không chắc chắn từ góc độ bảo trì. Ví dụ, ngay cả khi bắt đầu trực tiếp mã hóa JS trong một tệp HTML, người ta đang cám dỗ độ dốc trơn trượt của spaghettization.
Steven Lu

1
Và đó là một lý lẽ hợp lệ chống lại, một lý lẽ mà tôi đồng ý. Tôi thường không thêm kịch bản nội tuyến, cũng không tạo kiểu cho phương tiện đó. Nhưng mọi người có thị hiếu khác nhau. Ví dụ, nhiều người muốn thêm các thẻ script và kiểu trong phần thân, tôi không thể chịu đựng được. Nhưng nó hợp lệ và một số người thích nó. Những gì đường nối như bad practice/spaghettificationđối với một số, là good practice/structurecho những người khác.
Daniel B

Tôi đã xem github.com/styled-components/styled-components và nếu bạn kết hợp điều này với phản ứng, chẳng hạn, giờ đây chúng ta có mọi thứ liên quan đến một thành phần của ứng dụng của bạn thực sự sống cùng nhau (hy vọng là hòa bình) ở một nơi. Và nó thực sự trông cũng không tệ. Cảm thấy như tiến bộ. Trong trường hợp này, việc gây nhiễu các kiểu nội tuyến và mã thành HTML không phải là cách đúng đắn (cho đến nay dường như việc gây nhiễu HTML và các kiểu vào mã JS).
Steven Lu

5

Cách tốt nhất để trả lời câu hỏi của bạn là xem nó trong hành động.

<a id="test" onclick="alert('test')"> test </a> 

Trong js

var test = document.getElementById('test');
console.log( test.onclick ); 

Như bạn thấy trong console, nếu bạn đang sử dụng chrome, nó sẽ in một hàm ẩn danh với đối tượng sự kiện được truyền vào, mặc dù nó có một chút khác biệt trong IE.

function onclick(event) {
   alert('test')
}

Tôi đồng ý với một số điểm của bạn về xử lý sự kiện nội tuyến. Có, chúng rất dễ viết, nhưng tôi không đồng ý với quan điểm của bạn về việc phải thay đổi mã ở nhiều nơi, nếu bạn cấu trúc mã tốt, bạn không cần phải làm điều này.


Tôi nghĩ rằng một cái gì đó như <button onclick="login()"> test login </button>là hoàn toàn tốt cho tạo mẫu. Bạn muốn kiểm tra một cái gì đó yêu cầu tương tác người dùng ngay bây giờ và dù sao bạn cũng sẽ xóa nó sau. Tại sao phải viết thêm mã ở khắp nơi?
Dagg Nợi

Đó không phải là mã bổ sung, chỉ là một chức năng ẩn danh bổ sung. Và nó không phải ở khắp mọi nơi, nó thực sự nằm ở một nơi, trong các thẻ script.
aziz trừng phạt

Tôi không chắc chúng tôi có chung ý tưởng "cấu trúc mã của bạn tốt". Nếu bạn liên kết UI với "các chức năng cốt lõi" của mình ở nơi mà các chức năng cốt lõi của bạn thực sự sống, thì điều này đối với tôi giống như một sự sắp xếp khớp nối tồi tệ hơn là chỉ ràng buộc chúng trong UI. Tôi thường giữ tất cả các công cụ ràng buộc UI tách biệt với các công cụ cốt lõi và tôi có cảm giác OP cũng có thể ...
Dagg Nợi

3

Có vẻ đáng ngờ vì không có chức năng rõ ràng đang được trả lại từ!

Nó là một hàm ẩn danh đã được gắn vào sự kiện nhấp chuột của đối tượng.

Tại sao bạn làm điều này, Steve?

Tại sao bạn lại làm thế ..... Ah, đừng bận tâm, như bạn đã đề cập, nó thực sự được áp dụng rộng rãi trong thực tiễn xấu :)


3

Hãy thử điều này trong bảng điều khiển:

var div = document.createElement('div');

div.setAttribute('onclick', 'alert(event)');

div.onclick

Trong Chrome, nó hiển thị điều này:

function onclick(event) {
  alert(event)
}

... và tài sản phi tiêu chuẩn namecủa div.onclick"onclick".

Vì vậy, việc này có ẩn danh hay không phụ thuộc vào định nghĩa của bạn về "ẩn danh". So sánh với một cái gì đó như var foo = new Function(), nơi foo.namelà một chuỗi rỗng và foo.toString()sẽ tạo ra một cái gì đó như

function anonymous() {

}

Điều này bắt đầu như một nhận xét về câu trả lời của Pointy, nhưng thực sự không hoạt động như một bình luận. Anh ấy thực sự là câu trả lời tốt nhất ở đây, tôi nghĩ vậy.
Dagg Nợi
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.