<!-- HTML 输入和判断区域 -->
<div class="bg-white p-5 my-2.5 border border-gray-300 rounded">
<h2 class="text-xl font-semibold mb-4">输入 HTML 进行判断</h2>
<div class="my-4">
<label for="htmlInput" class="block mb-1.5 font-bold text-gray-800">输入 HTML 代码:</label>
<textarea
id="htmlInput"
v-model="htmlInput"
@keydown.ctrl.enter="checkInputHTML"
placeholder='例如: <div>这是内容</div> 或 <div></div> 或 <div class="test"> </div>'
class="w-full min-h-[120px] p-2.5 border border-gray-300 rounded font-mono text-sm resize-y box-border">
</textarea>
<button
@click="checkInputHTML"
class="px-5 py-2.5 bg-green-500 text-white border-none rounded cursor-pointer text-base mt-2.5 hover:bg-green-600">
判断是否空白
</button>
</div>
<div class="mt-4 p-4 bg-gray-50 border border-gray-300 rounded min-h-[100px]">
<h4 class="mt-0 text-gray-600 mb-2">渲染预览:</h4>
<div
class="p-2.5 bg-white border border-dashed border-gray-300 rounded min-h-[50px]"
ref="previewContent"
v-html="previewHTML">
</div>
</div>
<div
v-if="result.show"
:class="result.className"
class="mt-4 p-4 rounded text-base font-bold">
<div v-html="result.text"></div>
</div>
</div>
<div class="bg-white p-5 my-2.5 border border-gray-300 rounded">
<h2 class="text-xl font-semibold mb-4">测试场景</h2>
<div
v-for="(test, index) in tests"
:key="index"
:class="getTestItemClass(test.isEmpty)"
class="my-2.5 p-2.5 bg-gray-50 border-l-[3px]">
<strong class="font-semibold">{{ test.title }}</strong>
<div :id="test.id" v-html="test.html"></div>
<div
:class="getResultClass(test.isEmpty)"
class="mt-1.5 p-1.5 bg-blue-50 rounded text-xs">
{{ test.isEmpty !== null ? getResultText(test.isEmpty) : '计算中...' }}
</div>
</div>
</div>
</div>
<script>
const { createApp, ref, reactive, nextTick, onMounted } = Vue;
// 判断元素是否为空白的函数
function isEmptyElement(element) {
if (!element) return true;
// 检查 display: none
const style = window.getComputedStyle(element);
if (style.display === 'none') return true;
// 检查尺寸
const rect = element.getBoundingClientRect();
if (rect.width === 0 && rect.height === 0) return true;
// 检查文本内容
const text = element.textContent || element.innerText || '';
const trimmedText = text.trim();
if (trimmedText.length > 0) return false;
// 检查伪元素(::before 和 ::after)的内容
const beforeContent = style.getPropertyValue('content') ||
window.getComputedStyle(element, '::before').content;
const afterContent = window.getComputedStyle(element, '::after').content;
// 如果伪元素有内容(不是 none 或空字符串),则视为有内容
if (beforeContent && beforeContent !== 'none' && beforeContent !== '""' && beforeContent !== "''") {
return false;
}
if (afterContent && afterContent !== 'none' && afterContent !== '""' && afterContent !== "''") {
return false;
}
// 检查子元素
const children = element.children;
for (let i = 0; i < children.length; i++) {
if (!isEmptyElement(children[i])) {
return false;
}
}
// 检查是否有背景色、边框等可见样式
const bgColor = style.backgroundColor;
const bgImage = style.backgroundImage;
const borderWidth = parseInt(style.borderWidth) || 0;
if (bgColor && bgColor !== 'rgba(0, 0, 0, 0)' && bgColor !== 'transparent') {
return false;
}
if (bgImage && bgImage !== 'none') {
return false;
}
if (borderWidth > 0) {
return false;
}
return true;
}
createApp({
setup() {
const htmlInput = ref('');
const previewHTML = ref('');
const previewContent = ref(null);
const result = reactive({
show: false,
className: '',
text: ''
});
// 测试场景数据
const tests = ref([
{
id: 'empty1',
title: '场景1: 完全空白的 div',
html: '',
isEmpty: null
},
{
id: 'empty2',
title: '场景2: 只有空白字符(空格、换行、制表符)',
html: ' ',
isEmpty: null
},
{
id: 'not-empty1',
title: '场景3: 有文本内容',
html: '这是有内容的文本',
isEmpty: null
},
{
id: 'empty3',
title: '场景4: 有子元素但子元素为空',
html: '<span></span><p></p>',
isEmpty: null
},
{
id: 'not-empty2',
title: '场景5: 有子元素且有内容',
html: '<span>子元素内容</span>',
isEmpty: null
},
{
id: 'hidden1',
title: '场景6: display: none 的元素',
html: '<div class="hidden">这个元素被隐藏了</div>',
isEmpty: null
},
{
id: 'invisible1',
title: '场景7: visibility: hidden 的元素(占据空间)',
html: '<div class="invisible">这个元素不可见但占据空间</div>',
isEmpty: null
},
{
id: 'transparent1',
title: '场景8: opacity: 0 的元素(占据空间)',
html: '<div class="opacity-0">这个元素透明但占据空间</div>',
isEmpty: null
},
{
id: 'zero-size1',
title: '场景9: 宽高为 0 的元素',
html: '<div class="w-0 h-0 overflow-hidden">这个元素宽高为0</div>',
isEmpty: null
},
{
id: 'pseudo1',
title: '场景10: 只有伪元素内容的元素',
html: '<div class="pseudo-content"></div>',
isEmpty: null
},
{
id: 'bg1',
title: '场景11: 有背景色但无文本内容',
html: '<div class="bg-yellow-400 w-[100px] h-[50px]"></div>',
isEmpty: null
},
{
id: 'img1',
title: '场景12: 只有图片但图片加载失败',
html: '<img src="nonexistent.jpg" alt="" onerror="this.style.display=\'none\'">',
isEmpty: null
}
]);
// 检查输入的HTML
const checkInputHTML = async () => {
const html = htmlInput.value.trim();
if (!html) {
alert('请输入HTML代码');
return;
}
// 清空预览区域和结果
previewHTML.value = '';
result.show = false;
try {
// 设置预览HTML
previewHTML.value = html;
// 等待DOM更新
await nextTick();
// 等待渲染完成后再判断
setTimeout(() => {
if (!previewContent.value) return;
// 判断预览区域内的内容
let isEmpty = true;
let targetElement = previewContent.value;
if (previewContent.value.children.length === 0) {
// 没有子元素,检查文本内容
const text = previewContent.value.textContent || previewContent.value.innerText || '';
isEmpty = text.trim().length === 0;
} else if (previewContent.value.children.length === 1) {
// 只有一个子元素,判断该子元素
targetElement = previewContent.value.children[0];
isEmpty = isEmptyElement(targetElement);
} else {
// 多个子元素,如果所有子元素都为空,则整体为空
isEmpty = true;
for (let i = 0; i < previewContent.value.children.length; i++) {
if (!isEmptyElement(previewContent.value.children[i])) {
isEmpty = false;
break;
}
}
if (previewContent.value.children.length > 0) {
targetElement = previewContent.value.children[0];
}
}
// 显示结果
result.show = true;
result.className = isEmpty
? 'bg-red-100 text-red-700 border-2 border-red-500'
: 'bg-green-100 text-green-700 border-2 border-green-500';
const resultText = isEmpty ? '✓ 判断结果:空白' : '✗ 判断结果:非空白(有内容)';
// 添加详细信息
const style = window.getComputedStyle(targetElement);
const rect = targetElement.getBoundingClientRect();
const text = targetElement.textContent || '';
const children = targetElement.children.length;
let infoText = '<div class="mt-2.5 p-2.5 bg-blue-50 rounded text-xs font-normal text-gray-800">';
infoText += `<strong>详细信息:</strong><br>`;
infoText += `• 文本内容: "${text.trim() || '(无)'}"<br>`;
infoText += `• 文本长度: ${text.trim().length} 字符<br>`;
infoText += `• 子元素数量: ${children}<br>`;
infoText += `• 元素尺寸: ${rect.width.toFixed(2)} × ${rect.height.toFixed(2)} px<br>`;
infoText += `• Display: ${style.display}<br>`;
infoText += `• Visibility: ${style.visibility}<br>`;
infoText += `• Opacity: ${style.opacity}`;
infoText += '</div>';
result.text = resultText + infoText;
}, 50);
} catch (error) {
previewHTML.value = `<span class="text-red-600">HTML解析错误: ${error.message}</span>`;
result.show = true;
result.className = 'bg-red-100 text-red-700 border-2 border-red-500';
result.text = '✗ 错误:无法解析HTML代码';
}
};
// 获取测试项样式类
const getTestItemClass = (isEmpty) => {
if (isEmpty === null) return 'border-gray-300';
return isEmpty ? 'border-red-500' : 'border-green-500';
};
// 获取结果样式类
const getResultClass = (isEmpty) => {
if (isEmpty === null) return 'bg-blue-50';
return isEmpty ? 'bg-red-100' : 'bg-green-100';
};
// 获取结果文本
const getResultText = (isEmpty) => {
return `判断结果: ${isEmpty ? '空白 ✓' : '非空白 ✗'}`;
};
// 初始化测试场景
onMounted(async () => {
await nextTick();
setTimeout(() => {
tests.value.forEach(test => {
const element = document.getElementById(test.id);
if (element) {
test.isEmpty = isEmptyElement(element);
}
});
}, 100);
});
return {
htmlInput,
previewHTML,
previewContent,
result,
tests,
checkInputHTML,
getTestItemClass,
getResultClass,
getResultText
};
}
}).mount('#app');
</script>
HTML 空白内容判断工具