Firebase模块化API下按钮调用模块函数未定义问题及解决
问题:ES模块化脚本中内联onclick调用函数提示“未定义”
问题场景
通过ES模块化Web API完成Firebase安装与配置,业务代码放在type="module"的script标签中,基础功能运行正常,但页面中添加任务的按钮调用newElement()函数时,浏览器提示「函数未定义」,无法触发添加功能。
相关代码
HTML按钮代码
<div id="myDIV" class="todoheader"> <h2 style="margin:5px">My To Do List</h2> <input type="text" id="myInput" placeholder="Task..."> <span onclick="newElement()" class="addBtn">Add</span> </div>
JavaScript模块化代码
<script type="module"> import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.7.2/firebase-app.js' import { getFirestore, collection, doc, setDoc, query, where, getDocs } from 'https://www.gstatic.com/firebasejs/10.7.2/firebase-firestore.js' const firebaseApp = initializeApp({ apiKey: "AIzaSyDx6xuNnelTuWLQVoJQQ_13_q3u2kULpCE", authDomain: "tododatabase-8cc76.firebaseapp.com", projectId: "tododatabase-8cc76", storageBucket: "tododatabase-8cc76.appspot.com", messagingSenderId: "342835299624", appId: "1:342835299624:web:2864e35382d74599ef7c1d", measurementId: "G-NVT04Z3FYN" }); const db = getFirestore(firebaseApp); const todolist = [] // 指定要读取的集合 const collectionName = "tododata"; // 获取集合引用 const collectionRef = collection(db, collectionName); const q = query(collectionRef); // 获取集合中所有文档 const querySnapshot = await getDocs(q); querySnapshot.forEach((doc) => { todolist.push(doc.data()) console.log(doc.id, " => ", doc.data()); }); console.log(todolist) // 创建关闭按钮并添加到每个列表项 var list = document.querySelector('list-ul'); // 选择<ul>元素 for( var i =0; i < todolist.length; i++) { const liElement = document.createElement("li"); liElement.textContent = todolist[i]['Name']; if (todolist[i]['Crossed'] === true) { liElement.classList.add("checked"); } console.log(liElement) list.appendChild(liElement); } // 创建关闭按钮并添加到每个列表项 var list = document.querySelector('list-ul'); // 选择<ul>元素 var myNodelist = list.querySelectorAll('LI'); var i; for (i = 0; i < myNodelist.length; i++) { var span = document.createElement("SPAN"); var txt = document.createTextNode("\u00D7"); span.className = "close"; span.appendChild(txt); myNodelist[i].appendChild(span); } // 点击关闭按钮隐藏当前列表项 var close = document.getElementsByClassName("close"); var i; for (i = 0; i < close.length; i++) { close[i].onclick = function() { var div = this.parentElement; div.style.display = "none"; console.log(i) } } // 点击列表项添加/移除已完成标记 var list = document.querySelector('list-ul'); list.addEventListener('click', function(ev) { if (ev.target.tagName === 'LI') { ev.target.classList.toggle('checked'); let name = ev.target.textContent } }, false); // 原函数定义(无法被内联onclick调用) // function newElement() { // ... // } </script>
解决方法
将newElement()函数挂载到全局window对象上,修改后的函数定义如下:
window.newElement = function() { var li = document.createElement("li"); var inputValue = document.getElementById("myInput").value; var t = document.createTextNode(inputValue); li.appendChild(t); if (inputValue === '') { alert("You must write something!"); } else { document.getElementById("myUL").appendChild(li); } document.getElementById("myInput").value = ""; var span = document.createElement("SPAN"); var txt = document.createTextNode("\u00D7"); span.className = "close"; span.appendChild(txt); li.appendChild(span); for (i = 0; i < close.length; i++) { close[i].onclick = function() { var div = this.parentElement; div.style.display = "none"; } } }
原因说明
ES模块拥有独立的模块作用域,模块内部定义的变量和函数默认不会暴露到全局作用域中。而HTML内联事件处理器(如onclick="newElement()")只能访问全局作用域中的标识符,因此直接在模块内定义的newElement()无法被内联调用。将函数挂载到window对象后,函数就成为全局作用域的一部分,内联事件处理器就能正常调用它。
内容的提问来源于stack exchange,提问作者Bread
相关产品推荐
相关产品推荐

