前端在線預覽PDF文件


前言

這里用到了vue-pdf插件,預覽PDF相關的操作基本都有實現;

我們需要做的就是各種布局(因為需兼容已有的布局,有的地方可能需要修改),比如翻頁按鈕,頁碼展示等等;

vue-pdf的GitHub地址:FranckFreiburger/vue-pdf: vue.js pdf viewer (github.com)

目錄

  1. 入門例子
  2. 展示所有頁碼
  3. 翻頁操作
  4. 封裝組件
  5. 完整代碼

正文

1. 入門例子

安裝命令:yarn add vue-pdf

最簡單的入門例子,如下所示:

<template>
  <pdf src="/pdf/1.pdf"></pdf>
</template>

<script>
import pdf from 'vue-pdf'

export default {
  components: {
    pdf
  }
}

關於本地文件的路徑問題:

這里需要注意一下,要把pdf放在public目錄下,然后通過/進行引用;

比如你的pdf路徑為:public/pdf/1.pdf,那么src就要寫成:/pdf/1.pdf

如果是遠程路徑,則直接賦值;

2. 展示所有頁碼

上面的入門例子只是展示了第一頁的內容,其他內容沒有展示,如果需要展示其他頁,則需要添加翻頁功能;

但是現在我們先簡化,不添加翻頁功能,而是用v-for直接展示所有的頁碼;

<template>
	<div>
		<pdf
			v-for="i in numPages"
			:key="i"
			:src="src"
			:page="i"
			style="display: inline-block; width: 25%"
		></pdf>
	</div>
</template>

<script>

import pdf from 'vue-pdf'

var loadingTask = pdf.createLoadingTask('/pdf/1.pdf');

export default {
	components: {
		pdf
	},
	data() {
		return {
			src: loadingTask,
			numPages: undefined,
		}
	},
	mounted() {

		this.src.promise.then(pdf => {

			this.numPages = pdf.numPages;
		});
	}
}

</script>

展示效果如下所示:

image-20220211170832197

當我們的頁碼不是很多時,可以采用這種簡單粗暴的方式進行展示,很方便;

但是如果頁碼過多,則不僅看起來很費勁,而且加載也會很慢,這時就需要用到翻頁功能;

3. 翻頁操作

這里主要增加兩個按鈕,以及相關屬性,下面是部分代碼:

<a-list-item>
    <div @click="changePdfPage('pre')"
         :style="currentPage===1?'cursor: not-allowed;':''">
        上一頁
    </div>
</a-list-item>
<a-list-item>
    <div @click="changePdfPage('next')"
         :style="currentPage===pageCount?'cursor: not-allowed;':''">
        下一頁
    </div>
</a-list-item>
<pdf :src="srcPdf"
     :page="currentPage"
     @num-pages="pageCount=$event"
     style="display: inline-block;width:100%"></pdf>
  • @num-pages 事件:獲取pdf的總頁數,這里獲取到之后傳給了pageCount
  • page 屬性:就是當前頁碼,這里通過點擊上一頁和下一頁來修改來更新頁碼

效果如下所示:

image-20220211172837536

完整代碼見下面;

4. 封裝組件

為了方便使用,我們可以將上面的預覽代碼封裝成功一個單文件組件,然后在需要的地方進行引入即可;

封裝后的組件代碼貼到文末了,因為有點長:

我們在展示pdf文件時,可以通過跳轉到新標簽頁的方式進行展示,這樣組件內的布局不會有太大的變化;

跳轉代碼如下所示:

let routeUrl = this.$router.resolve({
              path: '/preview-pdf',
              query:{pdfPath}
          })
window.open(routeUrl.href, '_blank')
  • /preview-pdf:這個路徑就是配置在路由里面的,預覽pdf的路徑

  • pdfPath:這里我們是通過query的方式進行傳參,然后在預覽組件內通過 this.srcPdf = decodeURIComponent(this.$route.query.pdfPath)進行獲取;

    • 因為存在編碼問題,所以這里需要加上解碼操作;

      如果pdf路徑是http遠程路徑,則不需要解碼

5. 完整代碼

完整的封裝組件如下,這里是參考網上的例子,做了一些修改

<template>
    <div id="container">
        <!-- 上一頁、下一頁 -->
        <div class="right-btn">
            <a-space>
                <a-list>
                    <a-list-item>
                        <div >
                            <input v-model.number="currentPage"
                                   type="number"
                                   class="inputNumber"
                                   @input="inputEvent()"> / {{pageCount}}
                        </div>
                    </a-list-item>
                    <a-list-item>
                        <div @click="changePdfPage('first')"
                        >
                            首頁
                        </div>
                    </a-list-item>
                    <a-list-item>
                        <!-- 在按鈕不符合條件時禁用 -->
                        <div @click="changePdfPage('pre')"
                             :style="currentPage===1?'cursor: not-allowed;':''">
                            上一頁
                        </div>
                    </a-list-item>
                    <a-list-item>
                        <div @click="changePdfPage('next')"
                             :style="currentPage===pageCount?'cursor: not-allowed;':''">
                            下一頁
                        </div>
                    </a-list-item>
                    <a-list-item>
                        <div @click="changePdfPage('last')"
                        >
                            尾頁
                        </div>
                    </a-list-item>
                </a-list>
            </a-space>
        </div>

        <div class="pdfArea">
            <pdf :src="srcPdf"
                 ref="pdf"
                 :page="currentPage"
                 @num-pages="pageCount=$event"
                 @page-loaded="currentPage=$event"
                 @loaded="loadPdfHandler"
                 @link-clicked="currentPage = $event"
                 style="display: inline-block;width:100%"></pdf>
        </div>
    </div>
</template>

<script>
import pdf from 'vue-pdf'

export default {
    components: {
        pdf
    },
    computed: {
    },
    created () {
        console.log('query:', this.$route.query)
        this.srcPdf = decodeURIComponent(this.$route.query.pdfPath)
    },
    destroyed () {
    },
    mounted () {

    },
    data () {
        return {
            // ----- vuepdf -----
            // src靜態路徑: /static/xxx.pdf
            // src服務器路徑: 'http://.../xxx.pdf'
            // src: srcPdf,
            // 當前頁數
            currentPage: 0,
            // 總頁數
            pageCount: 0,
            // 加載進度
            loadedRatio: 0
        }
    },
    methods: {
        // 頁面回到頂部
        toTop () {
            document.getElementById('container').scrollTop = 0
        },
        // 輸入頁碼時校驗
        inputEvent () {
            if (this.currentPage > this.pageCount) {
                // 1. 大於max
                this.currentPage = this.pageCount
            } else if (this.currentPage < 1) {
                // 2. 小於min
                this.currentPage = 1
            }
        },
        // 切換頁數
        changePdfPage (val) {
            if (val === 'pre' && this.currentPage > 1) {
                // 切換后頁面回到頂部
                this.currentPage--
                this.toTop()
            } else if (val === 'next' && this.currentPage < this.pageCount) {
                this.currentPage++
                this.toTop()
            } else if (val === 'first') {
                this.currentPage = 1
                this.toTop()
            } else if (val === 'last' && this.currentPage < this.pageCount) {
                this.currentPage = this.pageCount
                this.toTop()
            }
        },

        // pdf加載時
        loadPdfHandler (e) {
            // 加載的時候先加載第一頁
            this.currentPage = 1
        },

    }
}
</script>

<style scoped>
#container {
    overflow: auto;
    font-family: PingFang SC;
    width: 100%;
    display: flex;
    position: relative;
}

/* 功能按鈕區 */
.right-btn {
    right:4rem;
    position: fixed;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    z-index: 99;
}

.pdfArea {
    width: 80%;
}

/*在谷歌下移除input[number]的上下箭頭*/
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
    -webkit-appearance: none !important;
    margin: 0;
}
/*在firefox下移除input[number]的上下箭頭*/
input[type='number'] {
    -moz-appearance: textfield;
}

.inputNumber {
    border-radius: 8px;
    border: 1px solid #999999;
    font-size: 18px;
    width: 2rem;
    text-align: center;
}
.inputNumber:focus {
    border: 1px solid #00aeff;
    background-color: rgba(18, 163, 230, 0.096);
    outline: none;
    transition: 0.2s;
}

</style>

如何使用?

先注冊路由:src/router/index.js

import MyPdf from '../components/MyPdf'

export default new VueRouter({
    routes: [
            {
                path: '/apply-contract-pdf',
                name: 'apply-contract-pdf',
                component: MyPdf
            },
]})

再通過如下方法進行預覽:

previewPdf(pdfPath){
    let routeUrl = this.$router.resolve({
        path: '/preview-pdf',
        query:{pdfPath}
    })
    window.open(routeUrl.href, '_blank')
},

總結

本篇介紹了vue-pdf的一些簡單使用,包括首頁展示、分頁展示等;

其實還有一些進度條展示這里沒列出來,感興趣的可以配合a-progress組件和progress 屬性進行體驗


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM