最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

前端將html導出為word文件的功能實現(xiàn)

 更新時間:2025年11月04日 08:26:51   作者:用戶67784715062  
本文介紹了如何將包含Echarts圖表、文字和表格的HTML報告導出到Word格式的需求實現(xiàn),通過使用html-docx-js插件,結(jié)合自定義函數(shù)處理樣式和圖表導出,最終成功實現(xiàn)了這一功能,需要的朋友可以參考下

介紹

需求:在開發(fā)過程中,遇到了產(chǎn)品要求將展示的可視化報告直接導出到word格式的需求,導出的html包括Echarts圖、文字、表格。經(jīng)過一番查找,找到一個插件html-docx-js。

功能實現(xiàn)

exportWord函數(shù):主函數(shù)接受一個dom元素,通過a標簽導出文件

import htmlDocx from 'html-docx-js/dist/html-docx'

export async function exportWord(ele) {
  let htmlContent = await wordStyleProcess(ele)
  const docxBlob = htmlDocx.asBlob(htmlContent)
  const URL = window.URL || window.webkitURL
  let a = document.createElement('a')
  a.download = 'name'
  a.rel = 'noopener'
  a.target = '_blank'
  a.href = URL.createObjectURL(docxBlob)
  a.click()
  URL.revokeObjectURL(a.href) // 20
}

wordStyleProcess函數(shù):對元素進行樣式處理。首先,復制元素,防止修改樣式影響頁面樣式。使用shortId標記元素,通過id找到頁面渲染的原始元素,對樣式進行調(diào)整。

export async function wordStyleProcess(ele) {
  if (!ele) return console.warn('未傳入元素')
  // 設置標記, 方便復制樣式,通過data-export-file-id標記,用于后續(xù)找到頁面的真實渲染樣式的元素
  Array.from(ele.querySelectorAll('*')).forEach((item) => {
    item.setAttribute('data-export-file-id', 'str' + stortId.generate())
  })
  //不影響頁面樣式,復制dom
  let exportFileEle = ele.cloneNode(true)

  // 遍歷iframe中的元素,將類樣式設置行內(nèi)樣式
  Array.from(exportFileEle.querySelectorAll('*')).forEach((item) => {
    let dataExportFileId = item.getAttribute('data-export-file-id')
    let originDom = ele.querySelector('[data-export-file-id="' + dataExportFileId + '"]') //原始dom才能獲取真實樣式
    if (originDom) {
      let originSty = getComputedStyle(originDom) //利用getComputedStyle獲取真實頁面dom的樣式
      if (originSty.display === 'none' || originSty.opacity === '0') return item.remove()
      setStyle(item, originSty)
    }
    //處理table類型的元素
    if (item.getAttribute('data-transform-table')) {
      const wordTable = convertElTableToHtmlTableWord(item, ele)
      const table = document.createElement('div')
      const parent = item.parentNode
      parent.style.height = 'auto'
      table.innerHTML = wordTable
      if (item.nextSibling) {
        parent.insertBefore(table, item.nextSibling)
      } else {
        parent.appendChild(table)
      }
      item.remove()
    }
  })

  // 處理echarts類型元素:遍歷真實頁面中的元素,帶有自定義屬性data-transform-image的元素為需要轉(zhuǎn)換的元素,真實頁面的canvas轉(zhuǎn)換為圖片,替換到iframe中對應位置
    await convertHTMLToImage(Array.from(ele.querySelectorAll('[data-transform-image="true"]')), exportFileEle)  
  //
  const htmlContent = exportFileEle.innerHTML
  if (exportFileEle) {
    exportFileEle.remove()
  }
  return htmlContent
}

setStyle函數(shù):獲取到的元素沒有類樣式,通過getComputedStyle獲取的頁面真實樣式賦值到導出的元素中。

/**
 * 把元素類樣式設置行內(nèi)樣式
 *
 * @param ele DOM元素
 * @param sty 包含樣式屬性的對象
 */
export function setStyle(ele, sty) {
  if (ele.nodeName.toLowerCase() !== 'img') {
    ele.setAttribute(
      'style',
      (ele.getAttribute('style') || '') +
        `;font-size: ${sty.fontSize};color: ${sty.color};font-style: ${sty.fontStyle};line-height: ${sty.lineHeight};font-weight: ${sty.fontWeight};
      font-family: ${sty.fontFamily};text-align: ${sty.textAlign};text-indent: ${sty.textIndent}; margin: ${sty.margin}; padding: ${sty.padding};width: ${sty.width}; height: ${sty.height};
      white-space:${sty.whiteSpace};word-break:${sty.wordBreak};display:${sty.display}; flex-direction:${sty.flexDirection};align-items: ${sty.alignItems}; `
    )
  }
}

convertHTMLToImage:對echarts圖表元素導出的問題,一開始我使用的html2canvas,網(wǎng)上的資料的很多也是用的這個插件,但是這個插件實在的太太太太慢了?。。?!,幾個echarts圖,居然十幾秒。 后面我翻了一下資料,echarts實例是支持導出base64的,然后嘗試了一下,直接秒導出,快太多了。 html2canvas版本:

export async function convertHTMLToImage(elements, exportFileEle, canvasWidth) {
  // 使用html2canvas捕捉DOM元素
  for (let element of elements) {
    const option = {
      // 使用html2Canvas進行截圖
      logging: false,
      allowTaint: true, // 允許跨域圖片渲染
      useCORS: true, // 使用跨域資源
      imageTimeout: 0, // 圖片加載延遲,默認延遲為0,單位毫秒
      scale: 1.2, // 設置縮放比例
      willReadFrequently: true,
    }
    const canvas = await html2canvas(element, option)
    canvas.setAttribute('data-export-file-id', element.getAttribute('data-export-file-id'))
    const url = canvas.toDataURL('image/jpg', 1.0)
    let img = new Image()
    img.src = url
    canvasWidth ? (img.width = canvasWidth) : (img.style.width = '100%')
    //移除原來的圖表元素,替換為圖片
    let canvasEle = exportFileEle.querySelector(`[data-export-file-id=${element.getAttribute('data-export-file-id')}]`)
    if (canvasEle) {
      const parent = canvasEle.parentNode
      if (canvasEle.nextSibling) {
        parent.insertBefore(img, canvasEle.nextSibling)
      } else {
        parent.appendChild(img)
      }
      canvasEle.remove()
    }
  }
}

使用echart的版本:從這里看好像也差不多,但是element有個data-url的自定義屬性,這個需要在外部配合,將獲取到的base64賦值給元素的自定義屬性。

export async function convertHTMLToImage(elements, exportFileEle, canvasWidth) {
  // 使用html2canvas捕捉DOM元素
  for (let element of elements) {
    const option = {
      // 使用html2Canvas進行截圖
      logging: false,
      allowTaint: true, // 允許跨域圖片渲染
      useCORS: true, // 使用跨域資源
      imageTimeout: 0, // 圖片加載延遲,默認延遲為0,單位毫秒
      scale: 1.2, // 設置縮放比例
      willReadFrequently: true,
    }
    const url = element.getAttribute('data-url')   
    let img = new Image()
    img.src = url
    canvasWidth ? (img.width = canvasWidth) : (img.style.width = '100%')
    //移除原來的圖表元素,替換為圖片
    let canvasEle = exportFileEle.querySelector(`[data-export-file-id=${element.getAttribute('data-export-file-id')}]`)
    if (canvasEle) {
      const parent = canvasEle.parentNode
      if (canvasEle.nextSibling) {
        parent.insertBefore(img, canvasEle.nextSibling)
      } else {
        parent.appendChild(img)
      }
      canvasEle.remove()
    }
  }
}

echart組件核心代碼:這里只簡單寫了一下,主要核心意思就是,在echarts渲染完成之后,生成base64,然后賦值到元素的自定義屬性上。

<div ref="refEchartsContainer" class="echarts-container" :style="cardStyle" data-transform-image="true" :data-url="url"/>

this.chartInstance.on('finished', () => {
            this.url = this.chartInstance.getDataURL({ type: 'png' })
        })

convertElTableToHtmlTableWord:處理el-table表格

export function convertElTableToHtmlTableWord(elTable, renderEle) {
  if (!elTable) return ''
  const tableEmptyBlockStyHeight = '100%'
  // 獲取 el-table 的表頭數(shù)據(jù),包括多級表頭
  const tableOptions = {
    tableStyle: 'border-collapse: collapse; width:100%',
    headerStyle: 'border: 1px solid black; width: 60px;height: 50px;',
    rowStyle: 'mso-yfti-irow:0; mso-yfti-firstrow:yes; mso-yfti-lastrow:yes; page-break-inside:avoid;height: 20px;',
    cellStyle: 'border: 1px solid black; min-width: 50px;max-width: 100px;height: 20px;',
  }
  const theadRows = elTable.querySelectorAll('thead tr') || []
  // 獲取 el-table 的數(shù)據(jù)行
  const tbodyRows = elTable.querySelectorAll('tbody tr') || []

  // 開始構(gòu)建 HTML 表格的字符串,設置表格整體樣式和邊框樣式
  let htmlTable = `<table style="${tableOptions.tableStyle}"><thead>`
  let columnsNum = 0
  // 處理表頭
  theadRows.forEach((row) => {
    htmlTable += `<tr style="${tableOptions.rowStyle}">`
    const columns = row.querySelectorAll('th') || []
    // 獲取表頭列數(shù),用于后面暫無數(shù)據(jù)的colspan屬性
    columnsNum = columns.length || 0
    columns.forEach((column) => {
      if (column.style.display !== 'none') {
        const colspan = column.getAttribute('colspan') || '1'
        const rowspan = column.getAttribute('rowspan') || '1'
        htmlTable += `<th colspan="${colspan}" rowspan="${rowspan}" style="${tableOptions.headerStyle}">${column.innerText}</th>`
      }
    })
    htmlTable += '</tr>'
  })
  htmlTable += '</thead><tbody>'

  // 構(gòu)建數(shù)據(jù)
  if (tbodyRows && tbodyRows.length > 0) {
    tbodyRows.forEach((row) => {
      htmlTable += `<tr style="${tableOptions.rowStyle}">`

      const cells = row.querySelectorAll('td') || []
      cells.forEach((cell) => {
        if (cell.querySelector('div')) {
          htmlTable += `<td style="${tableOptions.cellStyle}">${cell.querySelector('div').innerHTML}</td>`
        } else {
          htmlTable += `<td style="${tableOptions.cellStyle}">${cell.innerText}</td>`
        }
      })
      htmlTable += '</tr>'
    })
  } else {
    htmlTable += `<tr style="${tableOptions.rowStyle}"><td colspan="${columnsNum}" style="width: 100%; border: 1px solid black; height: ${tableEmptyBlockStyHeight};"><div style="display: inline-block;width: 100%; text-align: center;">暫無數(shù)據(jù)</div></td></tr>`
  }
  htmlTable += '</tbody></table>'

  return htmlTable
}

以上就是前端將html導出為word文件的功能實現(xiàn)的詳細內(nèi)容,更多關于前端html導出為word文件的資料請關注腳本之家其它相關文章!

相關文章

最新評論

乐山市| 滁州市| 扎鲁特旗| 安仁县| 察雅县| 公主岭市| 山阳县| 巴楚县| 花垣县| 苏尼特右旗| 灌阳县| 城市| 青田县| 介休市| 尼木县| 岑溪市| 汤原县| 中山市| 云阳县| 临泉县| 阿勒泰市| 重庆市| 西华县| 疏勒县| 顺昌县| 都江堰市| 贡觉县| 新密市| 枣阳市| 扎囊县| 兴城市| 沾化县| 罗山县| 得荣县| 杭锦后旗| 九寨沟县| 克拉玛依市| 南开区| 永康市| 陵水| 仁怀市|