Làm cách nào tôi có thể gọi sự kiện onclick () theo cách lập trình từ thẻ liên kết trong khi vẫn giữ tham chiếu 'this' trong hàm onclick?


83

Cách sau không hoạt động ... (ít nhất không phải trong Firefox: document.getElementById('linkid').click()không phải là một hàm)

<script type="text/javascript">
    function doOnClick() {
        document.getElementById('linkid').click();
        //Should alert('/testlocation');
    }
</script>
<a id="linkid" href="/testlocation" onclick="alert(this.href);">Testlink</a>

Câu trả lời:


110

Bạn cần applytrình xử lý sự kiện trong ngữ cảnh của phần tử đó:

var elem = document.getElementById("linkid");
if (typeof elem.onclick == "function") {
    elem.onclick.apply(elem);
}

Nếu không thissẽ tham chiếu đến ngữ cảnh mà đoạn mã trên được thực thi.


3
Tôi nghĩ bạn là người duy nhất không coi tôi là một kẻ ngốc (vì không đề cập đến ký hiệu ngoặc / sự không tương thích của trình duyệt onclick | click). Tại chỗ trên!
Ropstah

3
hãy xem xét điều này: howtocreate.co.uk/tutorials/javascript/domevents - việc gọi hàm onclick có gọi tất cả các trình xử lý sự kiện đã đăng ký không? Ngoài ra, việc gọi sai một sự kiện sẽ không tạo ra hành động mặc định được liên kết với sự kiện đó (ví dụ: gửi biểu mẫu).
jrharshath

Gumbo, vì mã này tạo ra các kết quả-khác nhau-, nó vẫn không hoạt động với các thư viện Microsoft.Ajax và Microsoft.AjaxMvc ....
Ropstah

1
Tại sao sử dụng apply()ở đây? Bạn chỉ có thể làm elem.onclick();, và elemsẽ là tham chiếu 'this' trong hàm - đơn giản!
Doin

18

Cách tốt nhất để giải quyết vấn đề này là sử dụng Vanilla JS, nhưng nếu bạn đang sử dụng jQuery, có một giải pháp rất dễ dàng:

<script type="text/javascript">
    function doOnClick() {
        $('#linkid').click();
    }
</script>
<a id="linkid" href="/testlocation" onclick="alert(this.href);">Testlink</a>

Đã thử nghiệm trên IE8-10, Chrome, Firefox.


3
tại sao lại ủng hộ? Vui lòng bình luận lý do, vì vậy tôi có thể cải thiện câu hỏi của mình nếu bạn tin rằng có điều gì đó không ổn.
luschn

1
nó được nêu trên stackoverflow rằng bạn không nên cung cấp câu trả lời phụ thuộc vào tài nguyên bên ngoài (chẳng hạn như thư viện như jQuery) nếu OP không đề cập rõ ràng về nó trong câu hỏi, tôi nghĩ chính điều đó đã thúc đẩy downvote
vhoyer

trở lại năm 2013, mọi người đều sử dụng jquery - nhưng ngày nay, tôi đồng ý :) - tôi sẽ giữ câu trả lời để tham khảo trong tương lai.
luschn

15

Để kích hoạt một sự kiện, về cơ bản bạn chỉ cần gọi trình xử lý sự kiện cho phần tử đó. Thay đổi nhẹ từ mã của bạn.

var a = document.getElementById("element");
var evnt = a["onclick"];

if (typeof(evnt) == "function") {
    evnt.call(a);
}

1
+1. Ngoài ra, một chút googling cho thấy foo.click () là IE chỉ, tất nhiên tôi có thể là sai ...
karim79

1
Bạn nên sử dụng ký hiệu dấu chấm (.onclick) thay vì sử dụng ký hiệu dấu ngoặc (["onclick"]).
Rudd Zwolinski

.onclick () hoặc .click () đều không hoạt động như mong đợi. Trong Firefox .click (hoặc bracked ['click']), nó "KHÔNG PHẢI LÀ MỘT CHỨC NĂNG". Nhưng khi gọi .onclick (), bạn sẽ mất tham chiếu "this" (tôi cần tham chiếu này trong ASP.NET MVC vì thông tin từ thẻ <a> cần thiết trong chức năng thực thi)
Ropstah

5
$("#linkid").trigger("click");

2
Chào mừng đến với SO. Bạn có thể giải thích thêm về lý do tại sao điều này hoạt động (chính xác nó làm gì, v.v.) và điều gì làm cho điều này khác biệt với các giải pháp khác?
m00am

2
tại sao đánh dấu câu trả lời này xuống? đây là giải pháp tốt nhất trên trang này nếu bạn sử dụng jquery ... một lớp lót - không thể đánh bại điều đó!
PodTech.io

Câu trả lời không nên yêu cầu jQuery
Greg Perham

5

Đúng là OP đã tuyên bố tương tự rằng điều này không hoạt động, nhưng nó đã làm cho tôi. Dựa trên các ghi chú trong nguồn của tôi, có vẻ như nó đã được thực hiện vào khoảng thời gian hoặc sau bài đăng của OP. Có lẽ bây giờ nó chuẩn hơn.

document.getElementsByName('MyElementsName')[0].click();

Trong trường hợp của tôi, nút của tôi không có ID. Nếu phần tử của bạn có id, tốt hơn là sử dụng phần sau (chưa được kiểm tra).

document.getElementById('MyElementsId').click();

Ban đầu tôi đã thử phương pháp này và nó không hoạt động. Sau khi sử dụng Google, tôi quay lại và nhận ra rằng phần tử của tôi là theo tên và không có ID. Kiểm tra kỹ xem bạn đang gọi đúng thuộc tính.

Nguồn: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click


1

Hãy xem phương thức handleEvent
https://developer.mozilla.org/en-US/docs/Web/API/EventListener

Javascript "thô":

function MyObj() {
   this.abc = "ABC";
}
MyObj.prototype.handleEvent = function(e) {
   console.log("caught event: "+e.type);
   console.log(this.abc);
}

var myObj = new MyObj();

document.querySelector("#myElement").addEventListener('click', myObj);

Bây giờ hãy nhấp vào phần tử của bạn (với id "myElement") và nó sẽ in nội dung sau trong bảng điều khiển:

sự kiện bắt gặp: nhấp vào
ABC

Điều này cho phép bạn có một phương thức đối tượng làm trình xử lý sự kiện và có quyền truy cập vào tất cả các thuộc tính đối tượng trong phương thức đó.

Bạn không thể chỉ truyền trực tiếp một phương thức của một đối tượng đến addEventListener (như thế element.addEventListener('click',myObj.myMethod);:) và mong đợimyMethod hoạt động như thể tôi thường được gọi trên đối tượng. Tôi đoán rằng bất kỳ hàm nào được chuyển đến addEventListener bằng cách nào đó được sao chép thay vì được tham chiếu. Ví dụ: nếu bạn chuyển một tham chiếu hàm trình xử lý sự kiện tới addEventListener (ở dạng một biến) thì hủy đặt tham chiếu này, trình xử lý sự kiện vẫn được thực thi khi các sự kiện được bắt.

Một cách giải quyết khác (kém thanh lịch hơn) để chuyển một phương thức làm bộ nghe sự kiện thisvà vẫn có quyền truy cập vào các thuộc tính đối tượng bên trong bộ nghe sự kiện sẽ là một cái gì đó như sau:

// see above for definition of MyObj

var myObj = new MyObj();

document.querySelector("#myElement").addEventListener('click', myObj.handleEvent.bind(myObj));

1

Chủ đề cũ, nhưng câu hỏi vẫn còn liên quan, vì vậy ...

(1) Ví dụ trong câu hỏi của bạn bây giờ KHÔNG hoạt động trên Firefox. Tuy nhiên, ngoài việc gọi trình xử lý sự kiện (hiển thị cảnh báo), nó CŨNG nhấp vào liên kết, gây ra điều hướng (sau khi cảnh báo bị loại bỏ).

(2) Để CHỈ gọi trình xử lý sự kiện (không kích hoạt điều hướng) chỉ cần thay thế:

document.getElementById('linkid').click();

với

document.getElementById('linkid').onclick();

0

Nếu bạn đang sử dụng điều này hoàn toàn để tham chiếu hàm trong thuộc tính onclick, thì đây có vẻ là một ý tưởng rất tồi. Các sự kiện nội tuyến nói chung là một ý tưởng tồi.

Tôi sẽ đề xuất những điều sau:

function addEvent(elm, evType, fn, useCapture) {
    if (elm.addEventListener) {
        elm.addEventListener(evType, fn, useCapture);
        return true;
    }
    else if (elm.attachEvent) {
        var r = elm.attachEvent('on' + evType, fn);
        return r;
    }
    else {
        elm['on' + evType] = fn;
    }
}

handler = function(){
   showHref(el);
}

showHref = function(el) {
   alert(el.href);
}

var el = document.getElementById('linkid');

addEvent(el, 'click', handler);

Nếu bạn muốn gọi hàm tương tự từ mã javascript khác, giả lập một cú nhấp chuột để gọi hàm không phải là cách tốt nhất. Xem xét:

function doOnClick() {
   showHref(document.getElementById('linkid'));
}

nó là về việc giữ tham chiếu đến 'this'. Tôi không thể chỉ tạo phần onclick trong neo (.NET MVC). Tôi cần tạo một thẻ liên kết hoàn chỉnh. Thẻ này được yêu cầu hoàn toàn bởi hàm onclick (ví dụ: nó sử dụng thuộc tính href).
Ropstah

-1

Nói chung, tôi khuyên bạn không nên gọi trình xử lý sự kiện 'theo cách thủ công'.

  • Không rõ điều gì được thực thi vì nhiều người nghe đã đăng ký
  • Nguy cơ mắc phải vòng lặp sự kiện đệ quy và vô hạn (nhấp vào A kích hoạt Nhấp chuột B, kích hoạt nhấp chuột A, v.v.)
  • Cập nhật dự phòng cho DOM
  • Khó phân biệt những thay đổi thực tế trong chế độ xem do người dùng gây ra với những thay đổi được thực hiện dưới dạng mã khởi tạo (chỉ nên chạy một lần).

Tốt hơn là tìm ra chính xác những gì bạn muốn xảy ra, đặt nó vào một hàm và gọi hàm đó theo cách thủ công VÀ đăng ký nó làm trình nghe sự kiện.


OP hỏi làm thế nào để làm điều gì đó, không phải cách tốt nhất để làm điều gì đó. Đây không phải là CodeReview. Nếu bạn đã trả lời câu hỏi của anh ấy và sau đó đưa ra tuyên bố từ chối trách nhiệm, điều đó sẽ khác.
Tyler Montney
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.