如何仅调用一次绑定函数,为动态生成的<li>绑定点击事件
setupItemOnClick for Every Dynamically Created <li> Great question! The issue with your current approach is that you're attaching separate click handlers to every .saveAs and .copy element as you create each <li>. This leads to redundant function calls and unnecessary event listeners cluttering the DOM.
The cleanest solution here is to use event delegation—a technique where you attach a single event listener to a parent element (like your .itemsUl <ul>) instead of each individual child. This listener will catch clicks from all matching child elements (even dynamically added ones) as the event bubbles up the DOM tree.
Step-by-Step Fix
Update your template (optional but recommended)
Add adata-idattribute to your<li>element. This makes retrieving the item ID more straightforward and avoids potential conflicts with the element'sidproperty:<script type="text/html" id="itemTemplate"> <li id="{{id}}" data-id="{{id}}"> <div class="name" title="{{name}}">{{name}}</div> <div class="saveAs"></div> <div class="copy"></div> </li> </script>Refactor your
myViewfunction
Remove the per-itemsetupItemOnClickcall and replace it with a one-time event delegation setup on the parent<ul>:function myView() { const self = {}; self.itemTemplate = null; self.myArrayOfObjects = null; self.itemsUl = null; self.mainContainer = null; self.initItemsUl = () => { self.itemsUl = self.mainContainer.find('.itemsUl'); // Set up event delegation ONCE when initializing the list self.setupItemEventDelegation(); self.myArrayOfObjects.forEach(self.initItemLi); }; self.initItemLi = (item) => { const viewObj = { id: item.Id, name: item.Name }; const itemLi = $(Mustache.render(self.itemTemplate, viewObj)); // Append directly to the <ul> to maintain proper structure self.itemsUl.append(itemLi[0]); // No more per-item setup call needed here! }; self.setupItemEventDelegation = () => { // Single listener for all .saveAs clicks self.itemsUl.on('click', '.saveAs', (event) => { // Fetch the item ID from the parent <li>'s data attribute const itemId = $(event.target).closest('li').data('id'); do_something(itemId); }); // Single listener for all .copy clicks self.itemsUl.on('click', '.copy', (event) => { const itemId = $(event.target).closest('li').data('id'); do_something(itemId); }); }; return { init: (myArrayOfObjects, mainContainer) => { self.mainContainer = mainContainer; self.myArrayOfObjects = myArrayOfObjects; self.itemTemplate = $('#itemTemplate').html(); Mustache.parse(self.itemTemplate); self.initItemsUl(); } }; }
Key Benefits of This Approach
- One-time setup:
setupItemEventDelegationruns only once when initializing the list, not for every<li>you render. - Improved performance: Fewer event listeners mean lower memory usage, especially with large lists.
- Auto-handles new items: Any
<li>elements added after the initial render will automatically work with the existing click handlers—no extra code required.
内容的提问来源于stack exchange,提问作者Shahar Shokrani

