Skip to content

判断html渲染出来的内容为空 #29

@leno23

Description

@leno23
<title>HTML 空白内容判断示例</title> <script src="https://cdn.tailwindcss.com"></script> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <style> /* 伪元素样式需要保留在 style 标签中 */ .pseudo-content::before { content: "伪元素内容"; display: block; } </style>

HTML 空白内容判断工具

    <!-- 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>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions