14

UPDATE:(recap, fiddle và tiền thưởng)JavaScript: Làm thế nào để mô phỏng sự kiện thay đổi trong internet explorer (đoàn)

Câu hỏi này chưa được nhận được quá nhiều sự chú ý, vì vậy tôi sẽ dành một số đại diện cho nó. Tôi biết tôi có xu hướng quá chi tiết trong cả câu trả lời và câu hỏi của mình. Đó là lý do tại sao tôi đã đi trước và thiết lập this fiddle, theo quan điểm của tôi, một biểu diễn phong nha về loại mã mà tôi hiện đang phải sử dụng để đến gần sự kiện sôi nổi change. Một vài vấn đề tôi đang cố gắng giải quyết:

  1. Sự kiện pseudo-change không kích hoạt trên phần tử đã chọn, trừ khi nó không tập trung. Trong một số trường hợp, khách hàng sẽ được chuyển hướng khi chọn một giá trị mới. Làm thế nào để đạt được điều này?
  2. Trình xử lý được gọi là cả khi nhãn được nhấp, cũng như hộp kiểm. Bản thân nó là những gì bạn mong đợi, nhưng do sự kiện sủi bọt nó (AFAIK) không thể xác định yếu tố nào được nhấp vào. Đối tượng sự kiện của IE không có thuộc tính realTarget.
  3. Khi thay đổi checked -trường hộp kiểm trong IE bằng cách nhấp vào nhãn, tất cả đều tốt (mặc dù nó yêu cầu một số giải pháp khó chịu), nhưng khi nhấp vào hộp kiểm trực tiếp, trình xử lý được gọi, nhưng trạng thái đã chọn vẫn không thay đổi, cho đến khi tôi nhấp lần thứ hai. Sau đó, giá trị thay đổi, nhưng trình xử lý không được gọi.
  4. Khi tôi chuyển sang một tab khác và ngược lại, trình xử lý được gọi nhiều lần. Ba lần nếu trạng thái đã chọn thực sự thay đổi, hai lần nếu tôi nhấp trực tiếp vào checbox một lần.

Mọi thông tin có thể giúp tôi giải quyết một hoặc nhiều vấn đề ở trên sẽ được đánh giá cao. Xin vui lòng, tôi không quên thêm một thẻ jQuery, tôi thích JS thuần túy, vì vậy tôi đang tìm kiếm một câu trả lời JS thuần túy.


Tôi có một trang web với hơn 250 phần tử được chọn trên đó và 20 ~ 30 hộp kiểm. Tôi cũng phải theo dõi hành động của người dùng và thực hiện các hành động thích hợp. Do đó, tôi rất tự nhiên khi đại diện cho sự kiện thay đổi, thay vì sau đó thêm hàng trăm người nghe, IMHO.

Tất nhiên, chính sách của IE: IE8 phải được hỗ trợ - không kích hoạt sự kiện trao đổi khi tôi cần. Vì vậy, tôi đang cố gắng giả mạo một sự kiện onchange. Những gì tôi có cho đến nay là làm việc hợp lý tốt ngoài 1 điều mà thực sự lỗi tôi.
Tôi đang sử dụng onfocusinonfocusout để đăng ký sự kiện. Trong một số trường hợp, khi người dùng chọn một giá trị mới từ phần tử chọn, tập lệnh sẽ phản hồi ngay lập tức. Tuy nhiên, miễn là lựa chọn không bị mất tiêu điểm, điều này sẽ không xảy ra.

Đây là những gì tôi đã đưa ra cho đến nay:

i = document.getElementById('content'); 
if (!i.addEventListener) 
{ 
    i.attachEvent('onfocusin',(function(self) 
    { 
     return function(e) 
     { 
      e = e || window.event; 
      var target = e.target || e.srcElement; 
      switch (target.tagName.toLowerCase()) 
      { 
       case 'input': 
        if (target.getAttribute('type') !== 'checkbox') 
        { 
         return true; 
        } 
        return changeDelegator.apply(self,[e]);//(as is 
       case 'select': 
        self.attachEvent('onfocusout',(function(self,current) 
        { 
         return function(e) 
         { 
          e = e || window.event; 
          var target = e.target || e.srcElement; 
          if (target !== current) 
          { 
           return; 
          } 
          self.detachEvent('onfocusout',arguments.callee);//(remove closure 
          return changeDelegator.apply(self,[e]); 
         } 
        })(self,target)); 
       default: return; 
      } 
     } 
    })(i));//(fake change event, buggy 
} 
else 
{//(to put things into perspective: all major browsers: 
    i.addEventListener('change',changeDelegator,false); 
} 

Tôi đã thử gắn một sự kiện nghe bên trong handler onfocusin, ràng buộc với sự kiện onclick. Nó kích hoạt sự kiện onfocusout của bất kỳ lựa chọn nào có tiêu điểm ATM. Vấn đề duy nhất là, 99,9% người dùng sẽ nhấp vào một lựa chọn, do đó, sự kiện focusin cũng kích hoạt tính năng onclick.

Để làm tròn điều đó, tôi đã tạo bao đóng và chuyển tiêu chí chọn lọc hiện tại và giá trị ban đầu của nó thành đối số.Nhưng một số người dùng làm sử dụng bàn phím của họ và những người dùng này thường tab đến hộp chọn tiếp theo mà không thay đổi giá trị. Mỗi lần ràng buộc một người nghe onclick mới ... Tôi tin rằng có HAS là một cách dễ dàng hơn để kiểm tra tất cả e.type và xử lý chúng một cách riêng biệt.
Cũng như một ví dụ: mã với một phụ onclick nghe: tất cả các mã cũng giống như đoạn đầu tiên, vì vậy tôi chỉ dán case 'select': khối

   case 'select': 
        self.attachEvent('onfocusout',(function(self,current) 
        { 
         return function(e) 
         { 
          e = e || window.event;//(IE... 
          var target = e.target || e.srcElement; 
          if (!(target === current)) 
          { 
           return; 
          } 
          self.detachEvent('onfocusout',arguments.callee);//(remove closure 
          return changeDelegator.apply(self,[e]); 
         }; 
        })(self,target)); 
        self.attachEvent('onclick',(function(self,current,oldVal) 
        { 
         return function(e) 
         { 
          e = e || window.event; 
          var target = e.target || e.srcElement; 
          if (target.tagName.toLowerCase() === 'option') 
          { 
           while(target.tagName.toLowerCase() !== 'select') 
           { 
            target = target.parentNode; 
           } 
          } 
          if (target !== current) 
          {//focus lost, onfocusout triggered anyway: 
           self.detachEvent('onclick',arguments.callee); 
           return; 
          } 
          var val = target.options[target.selectedIndex].innerHTML;//works best in all browsers 
          if (oldVal !== target.options[target.selectedIndex].innerHTML) 
          { 
           self.detachEvent('onclick',arguments.callee); 
           return target.fireEvent('onfocusout'); 
          } 
         }; 
        })(self,target,target.options[target.selectedIndex].innerHTML)); 
       default: return; 

Trả lời

2

Vâng, tôi đã có một vết nứt khác, và tôi đã đưa ra một cách tiếp cận khá phong nha (tại nơi làm việc nó đã lừa - tôi đã cố gắng sao chép mã tôi đã viết nhưng sau một vài loại bia nó có thể chứa một số lỗi nhưng tinh thần vẫn giữ nguyên)

window.attachEvent('onload',function ieLoad() 
{ 
    var mainDiv = document.getElementById('main');//main div, from here events will be delegated 
    var checks = mainDiv.getElementsByTagName('input');//node list of all inputs 
    var checkStates = {}; 
    for (var i=0;i<checks.length;i++) 
    { 
     if (checks[i].type === 'checkbox') 
     {//get their checked states on load, this object serves as a reference 
      checkStates[checks[i].id] = checks[i].checked; 
     } 
    } 
    mainDiv.attachEvent('onfocusin',(function(initState) 
    {//initState holds a reference to the checkStates object 
     return function(e) 
     { 
      e = e || window.event; 
      var target = e.target || e.srcElement; 
      //id of checkboxes used as key, so no checking for tagName or type required 
      if (!initState.hasOwnProperty(target.id) || target.checked === initState[target.id]) 
      {//don't call method if checkstate is unchanged, either. I'll explain in a minute 
       return e; 
      } 
      initState[target.id] = target.checked;//set new checked-state 
      changeDelegator.apply(target,[e]);//delegate 
     }; 
    })(checkStates)); 
    window.detachEvent('onload',ieLoad);//avoid mem-leak with onload handler! 
}); 

tôi đã phát hiện ra rằng các sự kiện focusin lửa hai lần trong một số trường hợp cho đài phát thanh và hộp kiểm. Sử dụng một đối tượng chứa trạng thái được kiểm tra thực tế của tất cả các hộp kiểm là ít tốn kém hơn các trình xử lý cá nhân và nó cho phép tôi chỉ ủy quyền sự kiện sau khi giá trị của phần tử đã thay đổi.

Chức năng changeDelegator chỉ được gọi khi cần, nhưng hàm anon mà tôi đăng ở đây vẫn được gọi là Waaaay nhiều hơn tôi muốn, nhưng cách tiếp cận này vẫn hoạt động tốt hơn các trình xử lý riêng lẻ.

tôi rời ra lựa chọn, nhưng tôi đã nhận họ làm việc, quá (mất tương tự, trong phiên bản đầy đủ của mã của tôi đóng cửa có 2 đối tượng, và tôi đã làm cho nó, vì vậy tôi có thể cờ một id, bắn sự kiện mờ khi cần và khách hàng được chuyển hướng).
Vào cuối cuộc chạy, mặc dù tôi đã học được một số thủ đoạn mới, điều chính tôi lấy đi từ bài tập này là một sự căm ghét sâu sắc hơn nữa của con golem khủng khiếp, ghê tởm của một thứ gọi là IE ... Nhưng nếu có ai khác có thể muốn ủy quyền sự kiện thay đổi trong IE, biết rằng đó là (gần như) có thể

3

khi tôi đồng ý rằng nó sẽ có tốt hơn chỉ một người nghe sự kiện trên toàn bộ biểu mẫu thay vì nhiều người nghe, một cho mỗi phần tử, bạn phải đánh giá chi phí và lợi ích của quyết định của mình. Lợi ích của một người nghe là giảm bộ nhớ. Nhược điểm là bạn phải thực hiện các thủ thuật mã phức tạp để thực hiện các sự kiện không chính xác của trình duyệt, tăng thời gian thực thi, lạm dụng các loại sự kiện, đăng ký và hủy đăng ký người nghe sự kiện nhiều lần, có thể gây nhầm lẫn cho một số người dùng.

Quay lại lợi ích, dấu chân bộ nhớ không quá lớn nếu bạn chỉ đính kèm cùng chức năng với tư cách người nghe cho tất cả các phần tử. Và bộ nhớ là thứ mà máy tính hiện tại không thiếu.

Ngay cả khi điều này không trả lời câu hỏi của bạn, tôi khuyên bạn nên ngừng cố gắng thực hiện tác phẩm này và thay vào đó hãy đính kèm người nghe vào từng yếu tố biểu mẫu.

Để giải quyết điểm của bạn một chút:

  1. Bạn có chắc chắn về điều đó? Tôi đã thử the basic example from Microsoft's documentation và cả IE7 và IE8 đều kích hoạt trình nghe onchange sau khi tôi nhấp vào tùy chọn từ trình đơn thả xuống. Nó thậm chí còn cháy khi thay đổi lựa chọn bằng các phím lên/xuống.

  2. Mặc dù bạn không thể dễ dàng kết nối sự kiện trên nhãn với hộp kiểm bị ảnh hưởng, tại sao bạn muốn thực hiện điều đó? Sự kiện change sẽ được kích hoạt trên hộp kiểm, và bạn chỉ nên quan tâm đến sự kiện đó. Tuy nhiên, nếu bạn phải vào hộp kiểm từ một sự kiện trên nhãn, thì bạn có thể làm điều đó theo cách thủ công. Nếu sự kiện nhắm mục tiêu nhãn, thì bạn biết rằng nhãn bằng cách nào đó có liên quan đến đầu vào. Tùy thuộc vào cách bạn sử dụng nhãn, bạn có thể chọn phần tử input được lồng bên trong label hoặc nhận phần tử có ID được tìm thấy trong thuộc tính for của label.

  3. Một cách để sửa chữa các hộp kiểm trả về giá trị trước đây về sự thay đổi lỗi là để làm một this.blur() trên focus sự kiện trên hộp kiểm.

  4. Khi bạn nói "trình xử lý", bạn có nghĩa là trình xử lý sự kiện onfocusin hoặc changeDelegator? Việc xem sự kiện cháy focusin là điều bình thường khi kích hoạt lại tab. Tôi không biết chắc chắn tại sao sự kiện lại bị sa thải nhiều lần, vì vậy tôi chỉ đoán: một người có thể là trọng tâm mà đầu vào hoạt động nhận được; thứ hai có thể là trọng tâm mà bản thân tài liệu nhận được; Tôi không biết tại sao một cuộc gọi thứ ba lại xảy ra. Tôi không hiểu ý bạn là gì nếu "nếu trạng thái đã chọn thực sự thay đổi, [...] nếu tôi chỉ nhấp vào hộp kiểm một cách trực tiếp".

+0

1. Có, tôi chắc chắn về điều đó: sự kiện thay đổi được kích hoạt trong IE8, nhưng nó không bị bong bóng. Đó là [một vấn đề đã biết] (http://stackoverflow.com/questions/5146784/make-form-elements-onchange-bubble-in-internet-explorer) 2. trình xử lý thay đổi được gọi trong cả hai trường hợp, đó không phải là vấn đề. Tuy nhiên, khi nhấp vào nhãn, trình xử lý được gọi sau khi trạng thái đã chọn đã thay đổi, trong khi trạng thái đã chọn sắp thay đổi khi hộp kiểm được nhấp trực tiếp. Vì vậy, nếu 'target.checked === true', nó đã được kiểm tra chưa, hoặc nó có bị bỏ chọn không? Không có cách nào để kể. Chạy ra khỏi ký tự –

+0

3. Thêm mờ và tiêu điểm khiến IE bị lỗi: lưu ý rằng, vì 'onchange' không tạo bọt tôi đang sử dụng các sự kiện' onfocusin' và 'onfocusout'. Nếu trình xử lý làm mờ, và tập trung, nó sẽ chỉ tiếp tục gọi chính nó là vô hạn 4. Và bằng cách xử lý, tôi có nghĩa là cả hai: nghiêm chỉnh nói 'changeDelegator' chỉ là một hàm, nhưng tôi gọi trong ngữ cảnh của trình xử lý (' changeDelegator. áp dụng (điều này, [e]); '), vì vậy tôi coi nó là một sự kéo dài/tiếp tục của trình xử lý thực tế. Tôi biết 'focusin' được kích hoạt khi tab được _revived_, nhưng nó được kích hoạt cho mỗi sự kiện được xử lý bởi hàm đại biểu. chars .... –

+0

Ý tôi là điều cuối cùng đơn giản là: tôi bấm vào một hộp kiểm (trình xử lý được kích hoạt, nhưng trạng thái đã chọn không thay đổi!), Nếu tôi nhấp vào hộp kiểm đó lần thứ hai, thì trình xử lý là không không được gọi, nhưng trạng thái đã kiểm tra thay đổi như nhau. Nếu tôi không nhấp vào nó lần thứ hai, nhưng chuyển đổi tab và ngược lại, sự kiện 'focusin' sẽ xuất hiện _not_ để được gọi cho hộp kiểm đó tôi đã nhấp một lần. Thật kỳ lạ. Về mặt hiệu suất: có sự khác biệt lớn, đặc biệt là khi _not_ chạy trên V8. gắn nó vào mỗi phần tử trên toàn bộ trang sẽ thêm đến 333 (chỉ cần đếm tất cả) elems! chars ... –

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