jQuery 寫了十幾年,自以為各種網頁 DOM 操作我都能信手拈來,今天硬是卡了一下,又一次體認到「沒學到的事還多著呢」

這回要處理的情境是將 div 裡多餘的 span 拆掉,將 span 內容在 div 展開到。例如:

<div>
    <span>
    First Line 
    <br />
    Sencond Line
    </span>
    <br />
    Third Line
</div>

要變成:

<div>
    First Line 
    <br />
    Sencond Line
    <br />
    Third Line
</div>

jQuery 要取出元素內容物,過去我只知道 .children(),再來就是 .html()。前者只取元素不含文字,在本例只會抓到 <br />;取 HTML 的話,怎麼跟 div 的 HTML 串接會是好問題。

爬文學到我錯過的 jQuery 方法 - .contents(),概念與 .children() 相似,但差別在 .contents() 包含文字節點(Text Node)、註解(<!-- Comment -->)... 等非元素項目。學會 .contents(),配上 .unwrap(),手到擒來:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>Unwrap SPAN</title>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>

<body>
    <div>
        <span>
            First Line
            <br />
            Sencond Line
        </span>
        <br />
        Third Line
    </div>
    <button type="button">Unwrap SPAN</button>
    <script>
        $('button').click(function () {
            $('span').contents().unwrap();
        });
    </script>
</body>

</html>

用一個小範例結束這回合。程式先用原生 API .childNodes 取得包含文字節點的所有子節點,由 .nodeType 判別節點類別,元素為 1,文字為 3,註解為 8。順便練習 console.log('%c ...', 'color: orange') 改變顏色,console.table() 以表格方式顯示物件陣列。jQuery 部分對照了 .children() 與 .contents() 的區別,並用 .contents() 產生與 .childNodes 相同的結果。

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>Text Node</title>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>

<body>
    <div id="d">
        First Line
        <br />
        Second Line
        <!-- Comment -->
    </div>
    <script>
        //https://developer.mozilla.org/zh-TW/docs/Web/API/Node/nodeType
        let nodeTypes = {
            '1': 'ELEMENT_NODE',
            '2': 'ATTRIBUTE_NODE',
            '3': 'TEXT_NODE',
            '4': 'CDATA_SECTION_NODE',
            //'5': 'ENTITY_REFERENCE_NODE',
            //'6': 'ENTITY_NODE',
            '7': 'PROCESSING_INSTRUCTION_NODE',
            '8': 'COMMENT_NODE',
            '9': 'DOCUMENT_NODE',
            '10': 'DOCUMENT_TYPE_NODE',
            //'11': 'DOCUMENT_FRAGMENT_NODE',
            //'12': 'NOTATION_NODE'
        };

        console.log('%c childNodes test', 'color: orange');
        let d = document.getElementById("d");
        let list = [];
        d.childNodes.forEach(node => {
            list.push({
                type: nodeTypes[node.nodeType],
                name: node.nodeName,
                value: JSON.stringify(node.nodeValue)
            });
        });
        console.table(list);

        console.log('%c jQuery test', 'color: yellow');
        jqd = $('#d');
        console.log(`\$('#d').children().length = ${jqd.children().length}`);
        console.log(`\$('#d').contents().length = ${jqd.contents().length}`);
        list.length = 0;
        jqd.contents().each(function (i, node) {
            list.push({
                type: nodeTypes[node.nodeType],
                name: node.nodeName,
                value: JSON.stringify(node.nodeValue)
            });
        });
        console.table(list);
    </script>
</body>

</html>


Comments

Be the first to post a comment

Post a comment