首次获取style属性时出现attributes.getNamedItem('style') is null错误的原因?
问题分析与解决方案
问题出在哪?
FileReader是异步操作,你操之过急了
FileReader.readAsDataURL()不会立刻完成,它要等文件读取完毕才会触发onload回调,给元素设置backgroundImage样式。但你在changeEvent里刚调用完thumbnail()就立刻去读取style属性,这时候回调还没执行,新创建的drop-area__thumb根本还没设置style,自然会报null。DOM节点选得不对,容易拿到空白文本节点
HTML里的换行、空格会被解析成文本节点,target.parentNode.firstChild很可能选中的是这些空白节点,而不是你刚创建的div。第二次上传时,目标节点是已经存在的drop-area__thumb,之前已经有style属性了,所以哪怕异步操作没完成,也能读到值。
怎么修?
1. 等异步操作完成后再读取style
把打印style的代码移到reader.onload回调里,确保样式已经设置完成:
function updateThumbnail(element, file) { if (file.type.startsWith("image/")) { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function() { element.style.backgroundImage = `url('${reader.result}')`; // 现在再打印,确保能拿到已设置的style console.log(element.style.cssText); }; } else { element.style.backgroundImage = null; console.log(element.style.cssText || "未设置style属性"); } }
2. 选DOM节点时避开文本节点
用firstElementChild代替firstChild,只选择元素节点;遍历子节点时用children而非childNodes,后者会包含文本节点:
function changeEvent(event) { const target = event.target; if (!target || !event.target.files.length) return; // 用children遍历,只处理元素节点 this.children.forEach(function(node) { if (node.children[1] === target) { thumbnail(node, event.target.files[0]); } }); // 用firstElementChild获取第一个元素节点,跳过空白文本 const firstElement = target.parentNode.firstElementChild; console.log(firstElement?.style.cssText || "style属性尚未设置或节点错误"); }
完整修复后的JavaScript代码
function clickEvent(event) { const target = event.target; if (!target) return; this.children.forEach(node => { if (node === target) node.children[1].click(); }); } function changeEvent(event) { const target = event.target; if (!target || !event.target.files.length) return; this.children.forEach(node => { if (node.children[1] === target) { thumbnail(node, event.target.files[0]); } }); const firstElement = target.parentNode.firstElementChild; console.log(firstElement?.style.cssText || "style属性未设置"); } function thumbnail(element, file) { const firstChild = element.children[0]; if (!firstChild) return; firstChild.nodeName === 'SPAN' ? createThumbnail(element, file) : updateThumbnail(firstChild, file); } function createThumbnail(element, file) { element.children[0].remove(); const thumbnail = document.createElement("div"); thumbnail.classList.add("drop-area__thumb"); element.prepend(thumbnail); updateThumbnail(thumbnail, file); thumbnail.dataset.label = file.name; return element; } function updateThumbnail(element, file) { if (file.type.startsWith("image/")) { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => { element.style.backgroundImage = `url('${reader.result}')`; console.log("异步加载完成后的style:", element.style.cssText); }; } else { element.style.backgroundImage = null; console.log("非图片文件,已清空style:", element.style.cssText); } } function eventHandler(element, eventType, callback) { document.getElementById(element).addEventListener(eventType, callback, false); } eventHandler('app', 'click', clickEvent); eventHandler('app', 'change', changeEvent);
总结
- 核心问题是异步时序错误:在FileReader未完成文件读取、未设置样式时就尝试读取style属性,导致获取不到值。
- 次要问题是DOM节点选择不准确:误选文本节点引发报错。
- 解决思路就是等待异步操作完成后再处理样式读取,同时用更精准的方法选择DOM元素,避开文本节点干扰。
内容的提问来源于stack exchange,提问作者Anas Radi
相关产品推荐
相关产品推荐

