欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

原生JS實(shí)現(xiàn)HTML轉(zhuǎn)Markdown功能

 更新時(shí)間:2025年04月18日 09:15:25   作者:獨(dú)元?dú)? 
這篇文章主要為大家詳細(xì)介紹了如何使用原生JS實(shí)現(xiàn)簡單的HTML轉(zhuǎn)Markdown功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

之前因?yàn)橐恍┬枰?,需要轉(zhuǎn)換部分 HTML 標(biāo)簽成 markdown 格式,但是不知不覺就完善到一個(gè)相對(duì)完整的函數(shù)。

然后我就封裝成了一個(gè)文件放在了 github ,也簡單做了兩個(gè)示例網(wǎng)頁。

代碼地址在 html2md

其實(shí)這類函數(shù)在 github 上有很多,但是或多或少都對(duì) HTML 的還原支持的不夠完善,比如 turndown.js 是最熱門的,但卻不支持表格的恢復(fù),索性就自己做了一個(gè)。

其實(shí)之間的轉(zhuǎn)換還挺復(fù)雜,需要考慮各個(gè)標(biāo)簽的優(yōu)先級(jí),做完又花了兩天才完善到一定程度。

(不過需要提醒的是,Safari 和 iOS 上的瀏覽器不支持這個(gè),因?yàn)樗鼈儗?duì)正則支持的不夠完整。不過對(duì)于前者,可以使用Chrome,對(duì)于后者,又壓根無法復(fù)制出已封裝了 HTML 的內(nèi)容,所以也不需要考慮。)

代碼的實(shí)現(xiàn)邏輯如下:

其中,最開始聲明了一些數(shù)組變量,用于將一些轉(zhuǎn)換過程中的中間產(chǎn)物進(jìn)行儲(chǔ)存。

然后 pureHtml 這個(gè)變量就是整個(gè)加工過程中的原料,一直到最后。

首先,函數(shù)處理的入口是從 112 行 開始的。

第一步,刪除 <style> 和 <script> 這兩個(gè)標(biāo)簽及其內(nèi)容。

第二步,將 pre 里的內(nèi)容先存到數(shù)組里,然后用 ‘#preContent#’ 這個(gè)字符替換原來 pre 標(biāo)簽里的內(nèi)容,我稱這個(gè)操作為保護(hù)。因?yàn)楹罄m(xù)會(huì)有很多復(fù)雜的內(nèi)容,把 pre 保護(hù)了,就能保證它的原汁原味,因?yàn)?pre 本身就是代碼,不能動(dòng)。

第三步,和 pre 一樣的 code ,為什么先 pre 再 code 呢?因?yàn)檫@兩樣?xùn)|西有這樣的包含關(guān)系,一般 pre 里可以有 code ,但 code 卻沒有 pre ,所以在考慮這樣的邏輯后,決定這樣儲(chǔ)存。

第四步,就是在沒有 pre 和 code 的干擾下,放心刪除標(biāo)簽中其他沒有用的屬性,并將 a 和 img 的標(biāo)簽內(nèi)容進(jìn)行 “保護(hù)” ,以方便一會(huì)兒恢復(fù)。

第五步,就是替換一些簡單的標(biāo)簽,什么標(biāo)題啊,斜體啊,橫線啊等等(還有將一些亂七八糟的標(biāo)簽直接刪除).....最后依次處理表格和列表。

第六步,按照一定的規(guī)范,依次將上面 “保護(hù)” 的內(nèi)容,進(jìn)行恢復(fù)。

第七步,將最頭部的空行刪去。(我記得中間也曾檢查多余的空行刪去,不知道為什么沒有了),然后轉(zhuǎn)換完畢,將結(jié)果返回。

源碼如下:

/**
 * 把 html 內(nèi)容轉(zhuǎn)化為 markdown 格式 V1.0
 * 
 * @author kohunglee
 * @param {string} htmlData 轉(zhuǎn)換前的 html 
 * @return {string} 轉(zhuǎn)化后的 markdown 源碼
 */
function html2md(htmlData){
    codeContent     = new Array  // code標(biāo)簽數(shù)據(jù)
    preContent      = new Array  // pre標(biāo)簽數(shù)據(jù)
    tableContent    = new Array  // table標(biāo)簽數(shù)據(jù)
    olContent       = new Array  // ol標(biāo)簽數(shù)據(jù)
    imgContent      = new Array  // img標(biāo)簽數(shù)據(jù)
    aContent        = new Array  // a標(biāo)簽數(shù)據(jù)
    let pureHtml    = htmlData
 
    // 源代碼
    console.log("轉(zhuǎn)換前的源碼:" + pureHtml)
 
    // 函數(shù):刪去html標(biāo)簽
    function clearHtmlTag(sourceData = ''){  
        return sourceData.replace(/\<[\s\S]*?\>/g,'')
    }
 
    // 復(fù)原ol標(biāo)簽
    function olRecover(olData = ''){  
        let result = olData
        let num = olData.match(/\<li\>/ig).length
        for(let i = 1; i <= num; i++){
            let line = '[~wrap]'
            if(i == 1) line = '[~wrap][~wrap]'
            result = result.replace(/\<li\>/i, line + i + '. ')
        }
        result = result.replace(/\<\/li\>/, '')
        return result
    }
 
    // 函數(shù):復(fù)原img標(biāo)簽
    function imgRecover(imgHtml = ''){  
        let imgSrc,imgTit,imgAlt,result
        imgSrc     = imgHtml.match(/(?<=src=['"])[\s\S]*?(?=['"])/i)
        imgTit     = imgHtml.match(/(?<=title=['"])[\s\S]*?(?=['"])/i)
        imgAlt     = imgHtml.match(/(?<=alt=['"])[\s\S]*?(?=['"])/i)
 
        imgTit = (imgTit != null) ? ` "${imgTit}"` : ' '
        imgAlt = (imgAlt != 'null') ? imgAlt : " "
        result = `![${imgAlt}](${imgSrc}${imgTit})`
        return result
    }
 
    // 函數(shù):復(fù)原a標(biāo)簽
    function aRecover(aData = ''){  
        let aHref = '' + aData.match(/(?<=href=['"])[\s\S]*?(?=['"])/i)
        let aTit  = '' + aData.match(/(?<=title=['"])[\s\S]*?(?=['"])/i)
        let aText = '' + aData.match(/(?<=\<a\s*[^\>]*?\>)[\s\S]*?(?=<\/a>)/i)
 
        let aImg = aData.match(/<img\s*[^\>]*?\>[^]*?(<\/img>)?/i)
        let aImgSrc,aImgTit,aImgAlt
 
        aTit = (aTit != 'null') ? ` "${aTit}"` : ' '
        aText = clearHtmlTag(aText)
        let result = `[${aText}](${aHref}${aTit})`
        
        if(aImg != null){  // 函數(shù):如果發(fā)現(xiàn)圖片,則更換為圖片顯示模式
            aImgSrc     = aImg[0].match(/(?<=src=['"])[\s\S]*?(?=['"])/i)
            aImgTit     = aImg[0].match(/(?<=title=['"])[\s\S]*?(?=['"])/i)
            aImgAlt     = aImg[0].match(/(?<=alt=['"])[\s\S]*?(?=['"])/i)
 
            aImgTit = (aImgTit != null) ? ` "${aImgTit}"` : ' '
            aImgAlt = (aImgAlt != 'null') ? aImgAlt : " "
            result = `[![${aImgAlt}](${aImgSrc}${aImgTit})](${aHref}${aTit})`
        }
        return result
    }
 
    // 函數(shù):復(fù)原table標(biāo)簽
    function tableRecover(tableData = null){  
        if(tableData[0] == null){  // 如果不存在 th 標(biāo)簽,則默認(rèn)表格為一層
            let result = ''
            let colNum = tableData[1].length
 
            for(let i = 0; i < colNum; i++){
            result += `|${clearHtmlTag(tableData[1][i])}`
            }
            result += `|[~wrap]`
            for(let j = 0; j < colNum; j++){
                result += `| :------------: `
            }
            result += `|[~wrap]`
            return result
        }
        let colNum = tableData[0].length  // 如果存在 th 標(biāo)簽,則按 th 的格數(shù)來構(gòu)建整個(gè)表格
        let result = ''
 
        for(let i = 0; i < colNum; i++){
            result += `|${clearHtmlTag(tableData[0][i])}`
        }
        result += `|[~wrap]`
        for(let j = 0; j < colNum; j++){
            result += `| :------------: `
        }
        result += `|[~wrap]`
        for(let k = 0; k < tableData[1].length;){
            for(let z = 0; z < colNum; z++,k++){
                result += `|${clearHtmlTag(tableData[1][k])}`
            }
            result += `|[~wrap]`
        }
        return result+`[~wrap]`
    }
    // 去掉樣式和腳本極其內(nèi)容
    pureHtml = pureHtml.replace(/<style\s*[^\>]*?\>[^]*?<\/style>/ig,'').replace(/<script\s*[^\>]*?\>[^]*?<\/script>/ig,'')
 
    // 儲(chǔ)存pre的內(nèi)容,并替換<pre>中的內(nèi)容
    preContent = pureHtml.match(/<pre\s*[^\>]*?\>[^]*?<\/pre>/ig)
    pureHtml = pureHtml.replace(/(?<=\<pre\s*[^\>]*?\>)[\s\S]*?(?=<\/pre>)/ig,'`#preContent#`')
 
    // 儲(chǔ)存code的內(nèi)容,并替換<code>中的內(nèi)容
    codeContent = pureHtml.match(/(?<=\<code\s*[^\>]*?\>)[\s\S]*?(?=<\/code>)/ig)
    pureHtml = pureHtml.replace(/(?<=\<code\s*[^\>]*?\>)[\s\S]*?(?=<\/code>)/ig,'`#codeContent#`')
 
    // 儲(chǔ)存a的內(nèi)容,并替換<a>中的內(nèi)容
    aContent = pureHtml.match(/<a\s*[^\>]*?\>[^]*?<\/a>/ig)
    pureHtml = pureHtml.replace(/<a\s*[^\>]*?\>[^]*?<\/a>/ig,'`#aContent#`')
 
    // 儲(chǔ)存img的內(nèi)容,并替換<img>中的內(nèi)容
    imgContent = pureHtml.match(/<img\s*[^\>]*?\>[^]*?(<\/img>)?/ig)
    pureHtml = pureHtml.replace(/<img\s*[^\>]*?\>[^]*?(<\/img>)?/ig,'`#imgContent#`')
 
    // 獲取純凈(無屬性)的 html
    pureHtml = pureHtml.replace(/(?<=\<[a-zA-Z0-9]*)\s.*?(?=\>)/g,'')  
 
    // 標(biāo)題:標(biāo)獲取<h1><h2>...數(shù)據(jù),并替換
    pureHtml = pureHtml.replace(/<h1>/ig,'[~wrap]# ').replace(/<\/h1>/ig,'[~wrap][~wrap]')
                        .replace(/<h2>/ig,'[~wrap]## ').replace(/<\/h2>/ig,'[~wrap][~wrap]')
                        .replace(/<h3>/ig,'[~wrap]### ').replace(/<\/h3>/ig,'[~wrap][~wrap]')
                        .replace(/<h4>/ig,'[~wrap]#### ').replace(/<\/h4>/ig,'[~wrap][~wrap]')
                        .replace(/<h5>/ig,'[~wrap]##### ').replace(/<\/h5>/ig,'[~wrap][~wrap]')
                        .replace(/<h6>/ig,'[~wrap]###### ').replace(/<\/h6>/ig,'[~wrap][~wrap]')
 
    // 段落:處理一些常用的結(jié)構(gòu)標(biāo)簽
    pureHtml = pureHtml.replace(/(<br>)/ig,'[~wrap]').replace(/(<\/p>)|(<br\/>)|(<\/div>)/ig,'[~wrap][~wrap]')
                       .replace(/(<meta>)|(<span>)|(<p>)|(<div>)/ig,'').replace(/<\/span>/ig,'')
 
    // 粗體:替換<b><strong>
    pureHtml = pureHtml.replace(/(<b>)|(<strong>)/ig,'**').replace(/(<\/b>)|(<\/strong>)/ig,'**')
 
    // 斜體:替換<i><em><abbr><dfn><cite><address>
    pureHtml = pureHtml.replace(/(<i>)|(<em>)|(<abbr>)|(<dfn>)|(<cite>)|(<address>)/ig,'*').replace(/(<\/i>)|(<\/em>)|(<\/abbr>)|(<\/dfn>)|(<\/cite>)|(<\/address>)/ig,'*')
 
    // 刪除線:替換<del>
    pureHtml = pureHtml.replace(/\<del\>/ig,'~~').replace(/\<\/del\>/ig,'~~')
 
    // 引用:替換<blockquote>
    pureHtml = pureHtml.replace(/\<blockquote\>/ig,'[~wrap][~wrap]> ').replace(/\<\/blockquote\>/ig,'[~wrap][~wrap]')
 
    // 水平線:替換<hr>
    pureHtml = pureHtml.replace(/\<hr\>/ig,'[~wrap][~wrap]------[~wrap][~wrap]')
 
    // 表格 <table>,得到數(shù)據(jù),刪除標(biāo)簽,然后逐層分析儲(chǔ)存,最終根據(jù)結(jié)果生成
    tableContent = pureHtml.match(/(?<=\<table\s*[^\>]*?\>)[\s\S]*?(?=<\/table>)/ig)
    pureHtml = pureHtml.replace(/<table\s*[^\>]*?\>[^]*?<\/table>/ig,'`#tableContent#`')
    if(tableContent !== null){  // 分析儲(chǔ)存
        tbodyContent = new Array
        for(let i = 0; i < tableContent.length; i++){
            tbodyContent[i] = new Array  // tbodyContent[i]的第一個(gè)數(shù)據(jù)是thead數(shù)據(jù),第二個(gè)是tbody的數(shù)據(jù)
            tbodyContent[i].push(tableContent[i].match(/(?<=\<th>)[\s\S]*?(?=<\/th?>)/ig))
            tbodyContent[i].push(tableContent[i].match(/(?<=\<td>)[\s\S]*?(?=<\/td?>)/ig))
        }
    }
    if(typeof tbodyContent !== "undefined"){  // 替換
        for(let i = 0; i < tbodyContent.length; i++){
            let tableText = tableRecover(tbodyContent[i])
            pureHtml = pureHtml.replace(/\`\#tableContent\#\`/i,tableText)
        }
    }
    
    // 有序列表<ol>的<li>,儲(chǔ)存ol的內(nèi)容,并循環(huán)恢復(fù)ol中的內(nèi)容
    olContent = pureHtml.match(/(?<=\<ol\s*[^\>]*?\>)[\s\S]*?(?=<\/ol>)/ig)
    pureHtml = pureHtml.replace(/(?<=\<ol\s*[^\>]*?\>)[\s\S]*?(?=<\/ol>)/ig,'`#olContent#`')
    if(olContent !== null){
        for(let k = 0; k < olContent.length; k++){
            let olText = olRecover(olContent[k])
            pureHtml = pureHtml.replace(/\`\#olContent\#\`/i,clearHtmlTag(olText))
        }
    }
 
    // 無序列表<ul>的<li>,以及<dd>,直接替換
    pureHtml = pureHtml.replace(/(<li>)|(<dd>)/ig,'[~wrap] - ').replace(/(<\/li>)|(<\/dd>)/ig,'[~wrap][~wrap]')
 
    // 處理完列表后,將 <lu>、<\lu>、<ol>、<\ol> 處理
    pureHtml = pureHtml.replace(/(<ul>)|(<ol>)/ig,'').replace(/(<\/ul>)|(<\/ol>)/ig,'[~wrap][~wrap]')
 
    // 先恢復(fù) img ,再恢復(fù) a
    if(imgContent !== null){
        for(let i = 0; i < imgContent.length; i++){
            let imgText = imgRecover(imgContent[i])
            pureHtml = pureHtml.replace(/\`\#imgContent\#\`/i,imgText)
        }
    }
 
    // 恢復(fù) a
    if(aContent !== null){
        for(let k = 0; k < aContent.length; k++){
            let aText = aRecover(aContent[k])
            pureHtml = pureHtml.replace(/\`\#aContent\#\`/i,aText)
        }
    }
 
    // 換行處理,1.替換 [~wrap] 為 ‘\n'   2.首行換行刪去。   3.將其他過長的換行刪去。
    pureHtml = pureHtml.replace(/\\[\~wrap\\]/ig,'\n')
                       .replace(/\n{3,}/g,'\n\n')
 
    // 代碼 <code> ,根據(jù)上面的數(shù)組恢復(fù)code,然后將code替換
    if(codeContent !== null){
        for(let i = 0; i < codeContent.length; i++){
            pureHtml = pureHtml.replace(/\`\#codeContent\#\`/i,clearHtmlTag(codeContent[i]))
        }
    }
    pureHtml = pureHtml.replace(/\<code\>/ig,' ` ').replace(/\<\/code\>/ig,' ` ')
 
    // 代碼 <pre> ,恢復(fù)pre,然后將pre替換
    if(preContent !== null){
        for(let k = 0; k < preContent.length; k++){
            let preLanguage = preContent[k].match(/(?<=language-).*?(?=[\s'"])/i)
            let preText = clearHtmlTag(preContent[k])
            preText = preText.replace(/^1\n2\n(\d+\n)*/,'')  // 去掉行數(shù)
 
            preLanguage = (preLanguage != null && preLanguage[0] != 'undefined') ? preLanguage[0] + '\n' : '\n'
            pureHtml = pureHtml.replace(/\`\#preContent\#\`/i,preLanguage + preText)
        }
    }
    pureHtml = pureHtml.replace(/\<pre\>/ig,'```').replace(/\<\/pre\>/ig,'\n```\n')
 
    // 刪去其余的html標(biāo)簽,還原預(yù)文本代碼中的 '<' 和 '>'
    pureHtml = clearHtmlTag(pureHtml)
    pureHtml = pureHtml.replace(/\&lt\;/ig,'<').replace(/\&gt\;/ig,'>')
 
    // 刪去頭部的空行
    pureHtml = pureHtml.replace(/^\n{1,}/i,'')
 
    return pureHtml
}

到此這篇關(guān)于原生JS實(shí)現(xiàn)HTML轉(zhuǎn)Markdown功能的文章就介紹到這了,更多相關(guān)JS HTML轉(zhuǎn)Markdown內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • js 中的console使用示例詳解

    js 中的console使用示例詳解

    console 是 JavaScript 提供的一個(gè)全局對(duì)象,常用于調(diào)試和日志記錄,它包含一組方法,用于在控制臺(tái)中打印消息、顯示數(shù)據(jù)以及調(diào)試程序,本文介紹js 中的console使用示例,感興趣的朋友一起看看吧
    2024-12-12
  • ES6中Math對(duì)象新增的方法實(shí)例詳解

    ES6中Math對(duì)象新增的方法實(shí)例詳解

    這篇文章主要介紹了ES6中Math對(duì)象新增的方法,結(jié)合實(shí)例形式詳細(xì)分析了ES6中Math對(duì)象的各種常用數(shù)學(xué)函數(shù)與新增方法相關(guān)使用技巧,需要的朋友可以參考下
    2017-04-04
  • 在Z-Blog中運(yùn)行代碼[html][/html](純JS版)

    在Z-Blog中運(yùn)行代碼[html][/html](純JS版)

    在Z-Blog中運(yùn)行代碼[html][/html](純JS版)...
    2007-03-03
  • JavaScript事件冒泡與事件捕獲實(shí)例分析

    JavaScript事件冒泡與事件捕獲實(shí)例分析

    這篇文章主要介紹了JavaScript事件冒泡與事件捕獲,結(jié)合實(shí)例形式分析了事件冒泡、阻止冒泡以及事件捕獲的相關(guān)原理、操作技巧與注意事項(xiàng),需要的朋友可以參考下
    2018-08-08
  • Three?cannon-es?基礎(chǔ)使用示例詳解

    Three?cannon-es?基礎(chǔ)使用示例詳解

    Cannon.js可以在多種瀏覽器上運(yùn)行,并且支持移動(dòng)設(shè)備和桌面設(shè)備,這使得開發(fā)者可以輕松地在各種平臺(tái)上開發(fā)和運(yùn)行物理模擬應(yīng)用程序,這篇文章主要介紹了Three?cannon-es?基礎(chǔ)使用,需要的朋友可以參考下
    2024-05-05
  • js實(shí)現(xiàn)煙花特效

    js實(shí)現(xiàn)煙花特效

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)煙花效果,實(shí)現(xiàn)鼠標(biāo)點(diǎn)擊出現(xiàn)模擬煙花爆炸的特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • NodeJs中的非阻塞方法介紹

    NodeJs中的非阻塞方法介紹

    NodeJs中的非阻塞方法介紹,需要的朋友可以參考下
    2012-06-06
  • 在頁面中引入js的兩種方法(推薦)

    在頁面中引入js的兩種方法(推薦)

    下面小編就為大家?guī)硪黄陧撁嬷幸雑s的兩種方法(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • js判斷滾動(dòng)條是否已到頁面最底部或頂部實(shí)例

    js判斷滾動(dòng)條是否已到頁面最底部或頂部實(shí)例

    這篇文章主要介紹了js判斷滾動(dòng)條是否已到頁面最底部或頂部的原理與方法,以實(shí)例的形式詳細(xì)分析了js實(shí)現(xiàn)返回頂部功能所涉及的各種技巧,并對(duì)相關(guān)知識(shí)點(diǎn)進(jìn)行了總結(jié)歸納,需要的朋友可以參考下
    2014-11-11
  • ECharts柱狀圖關(guān)閉鼠標(biāo)hover時(shí)的高亮樣式詳解

    ECharts柱狀圖關(guān)閉鼠標(biāo)hover時(shí)的高亮樣式詳解

    為了方便使用,echarts的餅圖中給加入了默認(rèn)的hover高亮效果,下面這篇文章主要給大家介紹了關(guān)于ECharts柱狀圖關(guān)閉鼠標(biāo)hover時(shí)的高亮樣式的相關(guān)資料,需要的朋友可以參考下
    2023-04-04

最新評(píng)論