亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Vue使用pdf-lib實(shí)現(xiàn)為文件流添加水印并預(yù)覽

 更新時(shí)間:2023年03月15日 16:29:51   作者:會(huì)說法語(yǔ)的豬  
這篇文章主要為大家詳細(xì)介紹了Vue如何使用pdf-lib實(shí)現(xiàn)為文件流添加水印并預(yù)覽的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下

之前也寫過兩篇預(yù)覽pdf的,但是沒有加水印,這是鏈接:Vue使用vue-pdf實(shí)現(xiàn)PDF文件預(yù)覽使用pdfobject預(yù)覽pdf。這次項(xiàng)目中又要預(yù)覽pdf了,要求還要加水印,做的時(shí)候又發(fā)現(xiàn)了一種預(yù)覽pdf的方式,這種方式我覺的更好一些,并且還有個(gè)要求就是添加水印,當(dāng)然水印后端也是可以加的,但是后端說了一堆...反正就是要讓前端做,在我看來就是借口、不想做,最近也不忙,那我就給他搞出來好了。下面來介紹一下 

首先預(yù)覽pdf就很簡(jiǎn)單了,我們只需要通過window.URL.createObjectURL(new Blob(file))轉(zhuǎn)為一個(gè)路徑fileSrc后,再通過window.open(fileSrc)就可以了,window.open方法第二個(gè)參數(shù)默認(rèn)就是打開一個(gè)新頁(yè)簽,這樣就可以直接預(yù)覽了,很方便!就是下面這樣子:

并且右上角自動(dòng)給我們提供了下載、打印等功能。 

但是要加上水印的話,可能會(huì)稍微復(fù)雜一點(diǎn)點(diǎn),我也百度找了好多,發(fā)現(xiàn)好多都是在項(xiàng)目里直接預(yù)覽的,也就是在當(dāng)前頁(yè)面或者一個(gè)div有個(gè)容器用來專門預(yù)覽pdf的,然后水印的話也是appendChild到容器div中進(jìn)行的。這不是我想要的,并且也跟我現(xiàn)在預(yù)覽的方式不一樣,所以我的思路就是如何給文件的那個(gè)二進(jìn)制blob流上加上水印,這樣預(yù)覽的時(shí)候也是用這個(gè)文件流,以后不想預(yù)覽了、直接下載也要水印也是很方便的。找來找去找到了pdf-lib庫(kù),然后就去https://www.npmjs.com/package/pdf-lib這里去看了下使用示例,看了兩個(gè)例子,發(fā)現(xiàn)好像這個(gè)很合適哦,終于一波操作拿下了,這就是我想要的。

我這里添加水印共三種方式,第一種就是可以直接傳入文本,將文本添加進(jìn)去作為水印 ;第二種是將圖片的ArrayBuffer傳遞進(jìn)去,將圖片作為水印;因?yàn)榈谝环N方式直接傳文本只能傳英文,我傳入漢字就報(bào)錯(cuò)了,npm官網(wǎng)好像也有寫,這是不可避免的,所以才有了第三種方式,就是也是傳入文本,不過我們通過canvas畫出來,然后通過toDataURL轉(zhuǎn)為base64路徑,然后再通過XHR去加載該圖片拿到圖片的Blob,再調(diào)用Blob的arrayBuffer方法拿到buffer傳遞進(jìn)去作為水印,其實(shí)第三種和第二種都是圖片的形式,第三種會(huì)更靈活一些。下面上代碼

1. 安裝 

npm i pdf-lib

2. 引入 

//我的需求里只用到這么多就夠了,其他的按需引入
import { degrees, PDFDocument, rgb, StandardFonts } from 'pdf-lib';

3. 添加水印使用 

3.1 添加文本水印

import { degrees, PDFDocument, rgb, StandardFonts } from 'pdf-lib';
 
// This should be a Uint8Array or ArrayBuffer
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const existingPdfBytes = ...
 
// Load a PDFDocument from the existing PDF bytes
const pdfDoc = await PDFDocument.load(existingPdfBytes)
 
// Embed the Helvetica font
const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica)
 
// Get the first page of the document
const pages = pdfDoc.getPages()
const firstPage = pages[0]
 
// Get the width and height of the first page
const { width, height } = firstPage.getSize()
 
// Draw a string of text diagonally across the first page
firstPage.drawText('This text was added with JavaScript!', {
  x: 5,
  y: height / 2 + 300,
  size: 50,
  font: helveticaFont,
  color: rgb(0.95, 0.1, 0.1),
  rotate: degrees(-45),
})
 
 
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc.save()
 
// For example, `pdfBytes` can be:
//   ? Written to a file in Node
//   ? Downloaded from the browser
//   ? Rendered in an <iframe>

3.2 添加圖片文本

import { PDFDocument } from 'pdf-lib'
 
// These should be Uint8Arrays or ArrayBuffers
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const jpgImageBytes = ...
const pngImageBytes = ...
 
// Create a new PDFDocument
const pdfDoc = await PDFDocument.create()
 
// Embed the JPG image bytes and PNG image bytes
const jpgImage = await pdfDoc.embedJpg(jpgImageBytes)
const pngImage = await pdfDoc.embedPng(pngImageBytes)
 
// Get the width/height of the JPG image scaled down to 25% of its original size
const jpgDims = jpgImage.scale(0.25)
 
// Get the width/height of the PNG image scaled down to 50% of its original size
const pngDims = pngImage.scale(0.5)
 
// Add a blank page to the document
const page = pdfDoc.addPage()
 
// Draw the JPG image in the center of the page
page.drawImage(jpgImage, {
  x: page.getWidth() / 2 - jpgDims.width / 2,
  y: page.getHeight() / 2 - jpgDims.height / 2,
  width: jpgDims.width,
  height: jpgDims.height,
})
 
// Draw the PNG image near the lower right corner of the JPG image
page.drawImage(pngImage, {
  x: page.getWidth() / 2 - pngDims.width / 2 + 75,
  y: page.getHeight() / 2 - pngDims.height,
  width: pngDims.width,
  height: pngDims.height,
})
 
// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc.save()
 
// For example, `pdfBytes` can be:
//   ? Written to a file in Node
//   ? Downloaded from the browser
//   ? Rendered in an <iframe>

canvas那個(gè)也是用的這個(gè)這個(gè)通過圖片添加水印 

上面這些都是官網(wǎng)上給的一些示例,我當(dāng)時(shí)看到上面這兩個(gè)例子,靈感瞬間就來了,然后測(cè)試,測(cè)試成功沒問題,就開始整理代碼,封裝。結(jié)合自己的業(yè)務(wù)需求和可以復(fù)用通用的思想進(jìn)行封裝。下面貼一下最終的成功

3.3 封裝previewPdf.js

import { degrees, PDFDocument, rgb, StandardFonts } from 'pdf-lib';
/**
 * 瀏覽器打開新頁(yè)簽預(yù)覽pdf
 * blob(必選): pdf文件信息(Blob對(duì)象)【Blob】
 * docTitle(可選): 瀏覽器打開新頁(yè)簽的title  【String】
 * isAddWatermark(可選,默認(rèn)為false): 是否需要添加水印 【Boolean】
 * watermark(必選):水印信息 【Object: { type: string, text: string, image:{ bytes: ArrayBuffer, imageType: string } }】
 * watermark.type(可選):類型 可選值:text、image、canvas
 * watermark.text(watermark.type為image時(shí)不填,否則必填):水印文本。注意:如果watermark.type值為text,text取值僅支持拉丁字母中的218個(gè)字符。詳見:https://www.npmjs.com/package/pdf-lib
 * watermark.image(watermark.type為image時(shí)必填,否則不填):水印圖片
 * watermark.image.bytes:圖片ArrayBuffer
 * watermark.image.imageType:圖片類型??蛇x值:png、jpg
 * Edit By WFT
 */
export default class PreviewPdf {
  constructor({ blob, docTitle, isAddWatermark = false, watermark: { type = 'text', text = 'WFT', image } }) {
    const _self = this
    if(!blob) {
      return console.error('[PDF Blob Is a required parameter]')
    }
    if(!isAddWatermark) { // 不添加水印
      _self.preView(blob, docTitle)
    } else {
      let bytes,imageType
      if(type == 'image') {
        if(!image) {
          return console.error('["image" Is a required parameter]')
        }
        bytes = image.bytes
        imageType = image.imageType
      }
      const map = {
        'text': _self.addTextWatermark.bind(_self),
        'image': _self.addImageWatermark.bind(_self),
        'canvas': _self.addCanvasWatermark.bind(_self)
      }
      blob.arrayBuffer().then(async buffer => {
        const existingPdfBytes = buffer
        const pdfDoc = await PDFDocument.load(existingPdfBytes)
        let params
        if(type == 'text') params = { pdfDoc, text, docTitle }
        if(type == 'image') params = { pdfDoc, bytes, imageType, docTitle }
        if(type == 'canvas') params = { pdfDoc, text, docTitle }
        map[type](params)
      }).catch(e => console.error('[Preview Pdf Error]:', e))
    }
  }
 
  // 添加 Text 水印
  async addTextWatermark({ pdfDoc, text, docTitle }) {
    // console.log(StandardFonts, 'StandardFonts-->>') // 字體
    const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica)
    const pages = pdfDoc.getPages()
    for(let i = 0; i < pages.length; i++) {
      let page = pages[i]
      let { width, height } = page.getSize()
      for(let i = 0; i < 6; i++) {
        for(let j = 0; j < 6; j++) {
          page.drawText(text, {
            x: j * 100,
            y: height / 5 + i * 100,
            size: 30,
            font: helveticaFont,
            color: rgb(0.95, 0.1, 0.1),
            opacity: 0.2,
            rotate: degrees(-35),
          })
        }
      }
    }
    // 序列化為字節(jié)
    const pdfBytes = await pdfDoc.save()
    this.preView(pdfBytes, docTitle)
  }
 
  // 添加 image 水印
  async addImageWatermark({ pdfDoc, bytes, imageType, docTitle }) {
    // 嵌入JPG圖像字節(jié)和PNG圖像字節(jié)
    let image
    const maps = {
      'jpg': pdfDoc.embedJpg.bind(pdfDoc),
      'png': pdfDoc.embedPng.bind(pdfDoc)
    }
    image = await maps[imageType](bytes)
    // 將JPG圖像的寬度/高度縮小到原始大小的50%
    const dims = image.scale(0.5)
    const pages = pdfDoc.getPages()
    for(let i = 0; i < pages.length; i++) {
      let page = pages[i]
      let { width, height } = page.getSize()
      for(let i = 0; i < 6; i++) {
        for(let j = 0; j < 6; j++) {
          page.drawImage(image, {
            x: width / 5 - dims.width / 2 + j * 100,
            y: height / 5 - dims.height / 2 + i * 100,
            width: dims.width,
            height: dims.height,
            rotate: degrees(-35)
          })
        }
      }
    }
    // 序列化為字節(jié)
    const pdfBytes = await pdfDoc.save()
    this.preView(pdfBytes, docTitle)
  }
 
  // 添加 canvas 水印
  addCanvasWatermark({ pdfDoc, text, docTitle }) {
    // 旋轉(zhuǎn)角度大小
    const rotateAngle = Math.PI / 6;
 
    // labels是要顯示的水印文字,垂直排列
    let labels = new Array();
    labels.push(text);
 
    const pages = pdfDoc.getPages()
 
    const size = pages[0].getSize()
 
    let pageWidth = size.width
    let pageHeight = size.height
 
    let canvas = document.createElement('canvas');
    let canvasWidth = canvas.width = pageWidth;
    let canvasHeight = canvas.height = pageHeight;
 
    const context = canvas.getContext('2d');
    context.font = "15px Arial";
 
    // 先平移到畫布中心
    context.translate(pageWidth / 2, pageHeight / 2 - 250);
    // 在繞畫布逆方向旋轉(zhuǎn)30度
    context.rotate(-rotateAngle);
    // 在還原畫布的坐標(biāo)中心
    context.translate(-pageWidth / 2, -pageHeight / 2);
 
    // 獲取文本的最大長(zhǎng)度
    let textWidth = Math.max(...labels.map(item => context.measureText(item).width));
 
    let lineHeight = 15, fontHeight = 12, positionY, i
    i = 0, positionY = 0
    while (positionY <= pageHeight) {
      positionY = positionY + lineHeight * 5
      i++
    }
    canvasWidth += Math.sin(rotateAngle) * (positionY + i * fontHeight) // 給canvas加上畫布向左偏移的最大距離
    canvasHeight = 2 * canvasHeight
    for (positionY = 0, i = 0; positionY <= canvasHeight; positionY = positionY + lineHeight * 5) {
      // 進(jìn)行畫布偏移是為了讓畫布旋轉(zhuǎn)之后水印能夠左對(duì)齊;
      context.translate(-(Math.sin(rotateAngle) * (positionY + i * fontHeight)), 0);
      for (let positionX = 0; positionX < canvasWidth; positionX += 2 * textWidth) {
        let spacing = 0;
        labels.forEach(item => {
          context.fillText(item, positionX, positionY + spacing);        
          context.fillStyle = 'rgba(187, 187, 187, .8)'; // 字體顏色
          spacing = spacing + lineHeight;
        })
      }
      context.translate(Math.sin(rotateAngle) * (positionY + i * fontHeight), 0);
      context.restore();
      i++
    }
    // 圖片的base64編碼路徑
    let dataUrl = canvas.toDataURL('image/png');
    // 使用Xhr請(qǐng)求獲取圖片Blob
    let xhr = new XMLHttpRequest();
    xhr.open("get", dataUrl, true);
    xhr.responseType = "blob";
    xhr.onload = res => {
      const imgBlob = res.target.response
      // 獲取Blob圖片Buffer
      imgBlob.arrayBuffer().then(async buffer => {
        const pngImage = await pdfDoc.embedPng(buffer)
        for(let i = 0; i < pages.length; i++) {
          pages[i].drawImage(pngImage)
        }
        // 序列化為字節(jié)
        const pdfBytes = await pdfDoc.save()
        this.preView(pdfBytes, docTitle)
      })
    }
    xhr.send();
  }
 
  // 預(yù)覽
  preView(stream, docTitle) {
    const URL = window.URL || window.webkitURL;
    const href = URL.createObjectURL(new Blob([stream], { type: 'application/pdf;charset=utf-8' }))
    const wo = window.open(href)
    // 設(shè)置新打開的頁(yè)簽 document title
    let timer = setInterval(() => {
      if(wo.closed) {
        clearInterval(timer)
      } else {
        wo.document.title = docTitle
      }
    }, 500)
  }
}

3.4 調(diào)用使用 

我這里將上面文件放在src/utils下 

3.4.1  預(yù)覽(添加文本水?。?/strong>

代碼: 

// 引入
import PreviewPdf from '@/utils/previewPdf'
 
// script
// 實(shí)例化進(jìn)行添加水印 并預(yù)覽
// file.raw 是要預(yù)覽的pdf文件流 Blob
new PreviewPdf({
  blob: file.raw,
  docTitle: 'window.open docTitle',
  isAddWatermark: true, // 是否需要添加水印
  watermark: { // watermark必填 里面可以不填
    type: 'text',
    text: 'WFT'
  }
})

效果:

3.4.2 預(yù)覽(添加圖片水?。?nbsp;

代碼:

// 引入
import PreviewPdf from '@/utils/previewPdf'
 
// script
const watermarkImage = require('@/assets/img/watermark.png') // 水印圖片
let xhr = new XMLHttpRequest();
xhr.open("get", watermarkImage, true);
xhr.responseType = "blob";
xhr.onload = function (res) {
  const imgBlob = res.target.response // 水印圖片的Blob流
  imgBlob.arrayBuffer().then(buffer => { //get arraybuffer
    // 添加水印 預(yù)覽
    new PreviewPdf({
      blob: file.raw,
      docTitle: file.name,
      isAddWatermark: true,
      watermark: {
        type: 'image',
        image: {
          bytes: buffer,
          imageType: 'png'
        }
      }
    })
  })
}
xhr.send();

效果:

3.4.3 預(yù)覽(添加文本canvas繪制水?。?nbsp;

代碼:

// 引入
import PreviewPdf from '@/utils/previewPdf'
 
// script
new PreviewPdf({
  blob: file.raw,
  docTitle: file.name,
  isAddWatermark: true,
  watermark: {
    type: 'canvas',
    text: 'WFT-CANVAS'
  }
})

效果:

因?yàn)橛行邮秸{(diào)的不太好,就我目前寫的我更偏向使用canvas這個(gè),當(dāng)然都是可以使用的,樣式都是可以調(diào)整的。 

注意:里面的屬性 isAddWatermark 設(shè)置為false或者不傳該字段將不添加水印,還有watermark這個(gè)字段是必須的,穿個(gè)空對(duì)象也行像watermark:{}這樣,因?yàn)槲疑厦骖愔袠?gòu)造方法將參數(shù)結(jié)構(gòu)了,可以按需調(diào)整。

整體的封裝使用就是上面這樣子了, 希望可以幫到有需要的伙伴~~~

再給大家一個(gè)直接往某個(gè)dom元素里面添加水印的方法 

不傳參數(shù)默認(rèn)為整個(gè)body添加水印 

function waterMark(text = 'WFT', dom = document.body) {
  if (document.getElementById('waterMark')) return
  // 旋轉(zhuǎn)角度大小
  var rotateAngle = Math.PI / 6;
 
  // labels是要顯示的水印文字,垂直排列
  var labels = new Array();
  labels.push(text);
 
  let pageWidth = dom.clientWidth
  let pageHeight = dom.clientHeight
 
  let canvas = document.createElement('canvas');
  let canvasWidth = canvas.width = pageWidth;
  let canvasHeight = canvas.height = pageHeight;
 
  var context = canvas.getContext('2d');
  context.font = "15px Arial";
 
  // 先平移到畫布中心
  context.translate(pageWidth / 2, pageHeight / 2 - 250);
  // 在繞畫布逆方向旋轉(zhuǎn)30度
  context.rotate(-rotateAngle);
  // 在還原畫布的坐標(biāo)中心
  context.translate(-pageWidth / 2, -pageHeight / 2);
 
  // 獲取文本的最大長(zhǎng)度
  let textWidth = Math.max(...labels.map(item => context.measureText(item).width));
 
  let lineHeight = 15, fontHeight = 12, positionY, i
  i = 0, positionY = 0
  while (positionY <= pageHeight) {
    positionY = positionY + lineHeight * 5
    i++
  }
  canvasWidth += Math.sin(rotateAngle) * (positionY + i * fontHeight) // 給canvas加上畫布向左偏移的最大距離
  canvasHeight = 2 * canvasHeight
  for (positionY = 0, i = 0; positionY <= canvasHeight; positionY = positionY + lineHeight * 5) {
    // 進(jìn)行畫布偏移是為了讓畫布旋轉(zhuǎn)之后水印能夠左對(duì)齊;
    context.translate(-(Math.sin(rotateAngle) * (positionY + i * fontHeight)), 0);
    for (let positionX = 0; positionX < canvasWidth; positionX += 2 * textWidth) {
      let spacing = 0;
      labels.forEach(item => {
        context.fillText(item, positionX, positionY + spacing);
        spacing = spacing + lineHeight;
      })
    }
    context.translate(Math.sin(rotateAngle) * (positionY + i * fontHeight), 0);
    context.restore();
    i++
  }
  let dataUrl = canvas.toDataURL('image/png');
  let waterMarkPage = document.createElement('div');
  waterMarkPage.id = "waterMark"
  let style = waterMarkPage.style;
  style.position = 'fixed';
  style.overflow = "hidden";
  style.left = 0;
  style.top = 0;
  style.opacity = '0.4';
  style.background = "url(" + dataUrl + ")";
  style.zIndex = 999;
  style.pointerEvents = "none";
 
  style.width = '100%';
  style.height = '100vh';
  dom.appendChild(waterMarkPage);
}

以上就是Vue使用pdf-lib實(shí)現(xiàn)為文件流添加水印并預(yù)覽的詳細(xì)內(nèi)容,更多關(guān)于Vue文件流添加水印的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue3?使用defineExpose的實(shí)例詳解

    vue3?使用defineExpose的實(shí)例詳解

    這篇文章主要介紹了vue3?使用defineExpose的相關(guān)知識(shí),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • vue中template模板編譯的過程全面剖析

    vue中template模板編譯的過程全面剖析

    這篇文章主要介紹了vue中template模板編譯的過程全面剖析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • 關(guān)于uniapp的高級(jí)表單組件mosowe-form

    關(guān)于uniapp的高級(jí)表單組件mosowe-form

    這篇文章主要介紹了關(guān)于uniapp的高級(jí)表單組件mosowe-form,由于一些表單標(biāo)簽改來改去比較繁瑣,重復(fù)性很多,且樣式布局啥的幾乎萬(wàn)變不離其中,為了偷懶,開發(fā)了mosowe-form及mosowe-table兩款高級(jí)組件,需要的朋友可以參考下
    2023-04-04
  • Vue-Router實(shí)現(xiàn)頁(yè)面正在加載特效方法示例

    Vue-Router實(shí)現(xiàn)頁(yè)面正在加載特效方法示例

    這篇文章主要給大家介紹了利用Vue-Router實(shí)現(xiàn)頁(yè)面正在加載特效方法示例,文中給出了詳細(xì)的示例代碼,相信對(duì)大家具有一定的參考價(jià)值,有需要的朋友們下面來一起看看吧。
    2017-02-02
  • vue等兩個(gè)接口都返回結(jié)果再執(zhí)行下一步的實(shí)例

    vue等兩個(gè)接口都返回結(jié)果再執(zhí)行下一步的實(shí)例

    這篇文章主要介紹了vue等兩個(gè)接口都返回結(jié)果再執(zhí)行下一步的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • element-plus中el-upload組件限制上傳文件類型的方法

    element-plus中el-upload組件限制上傳文件類型的方法

    ?Element Plus 中,el-upload 組件可以通過設(shè)置 accept 屬性來限制上傳文件的格式,這篇文章主要介紹了element-plus中el-upload組件限制上傳文件類型,需要的朋友可以參考下
    2024-02-02
  • vue引用echarts餅圖不顯示圖例的解決

    vue引用echarts餅圖不顯示圖例的解決

    這篇文章主要介紹了vue引用echarts餅圖不顯示圖例的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • vue響應(yīng)式系統(tǒng)之observe、watcher、dep的源碼解析

    vue響應(yīng)式系統(tǒng)之observe、watcher、dep的源碼解析

    這篇文章主要介紹了vue響應(yīng)式系統(tǒng)之observe、watcher、dep的源碼解析,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-04-04
  • Vue3.0手寫輪播圖效果

    Vue3.0手寫輪播圖效果

    這篇文章主要為大家詳細(xì)介紹了Vue3.0手寫輪播圖效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • vue2.0實(shí)現(xiàn)音樂/視頻播放進(jìn)度條組件

    vue2.0實(shí)現(xiàn)音樂/視頻播放進(jìn)度條組件

    這篇文章主要為大家詳細(xì)介紹了vue2.0實(shí)現(xiàn)音樂和視頻播放進(jìn)度條組件的思路及具體實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-06-06

最新評(píng)論