【vue系列之三】從一個vue-pdf-shower,說說vue組件和npm包


前言

從去年年初開始,自己便下決心要寫一個vue系列的博客,但時至今日,才寫系列的第三篇博客,想來甚是慚愧。

但是慢歸慢,每一篇都要保證質量,以及要寫出自己的心路歷程,防止自己工作中填的坑再讓讀者走一遍。

vue上手相對react來說是比較簡單的,對於vue的基本指令以及語法,應該沒有什么能比官網更詳細,更生動的了。仔細想來,vue值得一說的,在項目中會讓新手感到困惑的,是vue的組件,今天就最近工作中用到的一個pdf查看組件,和大家聊聊vue的組件。最后會講如何將自己的代碼封裝成一個npm包,發布到npm官網。

去年5月份的,寫了vue系列的第一篇使用vue-cli腳手架工具搭建vue-webpack項目,今天再次使用vue-cli初始化項目時,發現vue-cli已經升級到2.9.2。

多說一句,因為vue-cli的命令為vue,所以查看vue-cli的版本時,需要使用vue -V,而且是大寫的V。仔細看下vue-cli 2.9的官方模板,驚喜的發現多了一個pwa模板。

 

前一陣子,谷歌開發者大會在上海舉辦,會上主推pwa,在這在簡單說下PWA,大神可直接忽略。

簡述PWA

 PWA是Progressive Web App的縮寫,字面意思理解為漸進增強的網頁應用。一個 PWA 應用首先是一個網頁, 可以通過 Web 技術編寫出一個網頁應用. 隨后添加上 App Manifest 和 Service Worker 來實現 PWA 的安裝和離線等功能。

在一個正常的HTML中,添加一個link標簽,href為manifest.json,即可將你的網頁應用添加到主屏幕。

manifest.json中會包含你的圖標、名稱。背景色等信息。

{
  "name": "你的web app名稱",
  "short_name": "簡稱",
  "display": "standalone",
  "start_url": "/",
  "theme_color": "主體色(#ffffff)",
  "background_color": "背景色(#333333)",
  "icons": [
    {
      "src": "icon.png",
      "sizes": "256x256",
      "type": "image/png"
    }
  ]
}
引入manifest.json
<link rel="manifest" href="manifest.json" />

PWA應用能實現離線訪問的核心是Service Worker,Service Worker 在網頁已經關閉的情況下還可以運行, 用來實現頁面的緩存和離線, 后台通知等等功能。

為了讓應用離線工作,需要注冊一個 service worker,一段允許在后台運行的腳本,不需要 用戶打開 web 頁面,也不需要其他交互。在應用根目錄放置serviceworker.js,然后在瀏覽器注冊。

if('serviceWorker' in navigator) { 
  navigator.serviceWorker .register('/service-worker.js')
  .then(function() { console.log('Service Worker Registered');
}); }

  在serviceworker注冊后,瀏覽器首次訪問該應用時,會執行install方法,這個方法的callback中我們能夠緩存所有需要緩存的數據。具體過程為:
首先定義需要緩存的文件類型,以及緩存存放路徑;然后在網頁相應所有請求之前,會將請求統一處理,可以控制一部分請求從緩存里拿數據。緩存會通過字符串名稱,動態的更新。篇幅有限,這里大概簡述下。具體可以移步餓了么團隊知乎

vue組件vue-pdf-shower

下面言歸正傳,說說vue組件。

最近筆者在項目中遇到一個pdf預覽的需求,經過調研,最終決定用火狐的pdf.js封裝一個vue組件。

其實需求還是比較簡單的,就是后台給一個URL,前端將pdf加載到網頁中即可。chrome和Firefox是自帶pdf查看器的,簡單的做法是使用iframe嵌入,但該方案兼容性太差,而且不受我們控制,所以pass了。

總體思路如下:

1.通過pdf.js提供的api,我們傳入pdf的URL,在callback中會拿到所需的pdf對象。

2.通過傳入不同的頁碼,可以拿到指定頁面的page對象。

3.通過canvas,將page對象渲染到頁面中。

4.遍歷所有page,循環生成多個canvas對象,插入dom。

把思路縷清楚之后,開發就比較簡單了。

首先,確定dom結構。由於我們的canvas是動態插入dom的,所以只提供一個wraper即可。

dom結構如下

<template>
    <div class="pdf-wraper">
        <div id="cvsWraper">
            <div class="loading-pdf" v-if="isloading">{{loadingTxt}}</div>
        </div>
    </div>
</template>

 

vue-pdf-viewer組件js

該組件需要傳兩個參數,一個是URL,一個是縮放值scale。

vue組件需要顯式說明自身期望傳入哪些屬性,並且可以賦予默認值。調用組件時,傳入不同的屬性,可以實現父組件向子組件傳值。

props: {
        pdfurl: {
            default: ''
        },
        scale: {
            default: 1
        }
    }

  

子組件向父組件傳值

子組件向父組件通信時,需要使用vue.$emit事件。

$emit事件接受兩個參數,第一個為所要拋出的方法名,第二個為所拋出方法帶的參數。

在這個組件中,只暴露出一個onErr事件,即當pdf加載失敗時的回調函數。

PDFJS.getDocument(me.pdfurl).then(function (pafObj) {
            me.isloading = true;
            me.pdfDoc = pafObj;
            let totalNum = me.pdfDoc.numPages;

            // 循環渲染所有canvas
            for (let i = 1; i <= totalNum; i++) {
                let id = `canvas${i}`;
                let cvsNode = document.createElement('canvas');
                cvsNode.setAttribute('id', id);
                cvsNode.setAttribute('class', 'canvas-item');
                cvsWraper.appendChild(cvsNode);
                me.renderPage(i);

                if (totalNum === i) {
                    me.isloading = false;
                }
            }
        }).catch(function (err) {
            me.loadingTxt = '加載失敗,請稍后重試';
            me.$emit('onErr', err);
        });

  

調用組件

在調用組件時,需要傳入所需的屬性和方法。

<template>
    <div>
         <pdfshower 
            :pdfurl="pdfurls" 
            :scale="scale" 
            @onErr="onErr"
        ></pdfshower>
    </div>
</template>

  

非父子組件通信

兄弟組件通信也是比較常見的,比如說在一個頁面中,導航是一個組件,內容區域是一個組件;當導航切換時,需要通知內容組件發生變化,並告訴他導航的id。

處理兄弟組件通信的問題,一般有兩種方式:

1.兄弟組件都引入一個公共vue組件hub,通過hub拋出事件,和監聽事件,以達到兄弟組件通信。

2.使用vuex。

項目中比較常見的是第一種做法,我做的vue項目中只有一次使用到了vuex;我對vuex的理解是:

vuex類似於一個全局的存儲空間,你可以把他理解為將需要傳遞的東西綁在了window下,所以在任何地方都可以拿到,並做修改。

在項目中用到的hub.js

/**
 * @file 事件總線
 * @author yangtianjiao
/
import Vue from 'vue';
export default new Vue({});

  

假設是上面說的那種情況,在導航組件切換時,通過hub發射信息:

hub.$emit('changeTableData', {
       dateKey: this.curDateTab
});

  

內容區域監聽hub發射的方法:

hub.$on('changeTableData', item => {
                this.pageNum = 1;
                this.total = 0;
                this.dataList = [];
                this.orderFieldId = 1;
                this.orderType = 1;
                this.contenctDesc = '';
                this.emptyText = '數據加載中...';
                this.isLoading = false;
            });

  

在內容組件銷毀時,取消對hub事件的監聽

beforeDestroy() {
        hub.$off('changeTableData');
}

  

兄弟組件通信並不復雜,但要深刻理解,必須在項目中多運用、實踐。這塊應該是vue最難的部分了,這塊掌握了,vue項目做起來就會得心應手。

發布npm包

大家平時工作中,最常用的是npm,很多包、類庫都從npm安裝。其實我們很容易就會發布屬於自己的npm包,下面我會一步步講講如何將上述的vue-pdf-viewer組件發布到npm官網的。

1.執行npm init

執行npm init后,根據命令行提示,依次輸入

包名稱

版本

描述

入口文件

測試腳本

關鍵詞

作者

版權信息(協議)

等等,最后OK,生成一個package.json文件。

2.確定包的目錄結構

package.json是npm幫我們生成的,根目錄下有入口文件index.js,和readme.md。

index.js中其實就是一句話,將真正的index.vue暴露出去

index.js

/**
 * @file vue-pdf-shower
 * @author v_yangtianjiao(v_yangtianjiao@baidu.com)
 * @time 18/01/15
 */
module.exports = require('./lib/index.vue');

  

readme中放有對包的簡述,以及包的基本用法

readme.md

# vue-pdf-shower

## 介紹
> 基於pdf.js的pdf簡易查看組件。
> 該組件加載全部pdf頁面,不提供翻頁查看功能。

## github
[vue-pdf-shower](https://github.com/TJ666/vue-pdf-shower)

## install
```
npm i vue-pdf-shower --save
```
## example
```
<template>
    <div>
         <pdfshower 
            :pdfurl="pdfurls" 
            :scale="scale" 
            @onErr="onErr"
        ></pdfshower>
    </div>
</template>

<script>
import pdfshower from 'vue-pdf-shower';
export default {
    name: 'pdfshower',
    components: {
        pdfshower
    },
    data() {
        return {
            // 所查看的pdf url
            pdfurls: '//cdn.mozilla.net/pdfjs/tracemonkey.pdf',
            // 縮放 默認為1
            scale: 1.2
        };
    },
    methods: {
        // 加載失敗的callback
        onErr(err) {
            console.log('pdf加載失敗,請重試');
            console.log('錯誤信息:', err);
        }
    }
};
</script>
```

  

至於為啥有個lib文件夾,還有目錄結構為啥長這樣?我的回答是:

看了一遍所有的npm包都是這樣,咱就按人家的來吧 - -

好了,咱們的包已經准備就緒了,就差發布!!!

3.注冊npm賬號&發包

打開冰箱,將大象放進冰箱,關上冰箱門。

注冊很簡單的,只需要一個郵箱就行,連網站都打不開的同學就好好寫寫jquery去吧。

4.npm login

在命令行輸入npm login,

然后依次輸入用戶名和密碼,以及注冊的郵箱。

注意:輸入密碼時,密碼是不會顯示出來的,不要方!

登錄后只要沒有錯誤提示即登錄成功。

5.npm publish發包

離成功只差一步。

一切准備妥當,cd 到我們的vue-pdf-shower目錄,先檢查下npm有沒有重名的包。

可以去npm官網搜索,也可以直接npm install 包名,如果報錯,那么恭喜你包名沒有重復的。

執行npm publish

定睛一看,報了個錯。原來是package.json 的版本號沒有改。將版本號升一個級,在執行publish。

成功!

 6.去npm官網檢驗發包情況

發現已經可以搜到,因為我是昨天發的包,一天時間內已有116次下載。嗯,還不賴。

最后附上本組件github地址,歡迎大家拍磚。
https://github.com/TJ666/vue-pdf-shower

 

參考文獻

PWA 入門: 寫個非常簡單的 PWA 頁面

手把手教你用npm發布一個包

 


免責聲明!

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



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