1 | # vue-pdf
|
2 | vue.js pdf viewer
|
3 |
|
4 | ## Install
|
5 | ```bash
|
6 | npm install --save vue-pdf
|
7 | ```
|
8 |
|
9 | ## Example - basic
|
10 | ```vue
|
11 | <template>
|
12 | <pdf src="./static/relativity.pdf"></pdf>
|
13 | </template>
|
14 |
|
15 | <script>
|
16 | import pdf from 'vue-pdf'
|
17 |
|
18 | export default {
|
19 | components: {
|
20 | pdf
|
21 | }
|
22 | }
|
23 | ```
|
24 |
|
25 | ## Demo
|
26 |
|
27 | [vue-pdf demo on jsfiddle](https://jsfiddle.net/fossfiddler/5k4ptmqg/145/)
|
28 |
|
29 | _TBD: fix the demo_
|
30 |
|
31 | ## Browser support
|
32 | Same browser support as [Vue.js 2](https://github.com/vuejs/vue/blob/dev/README.md)
|
33 |
|
34 | ## Note
|
35 | since v2.x, the script is exported as esm.
|
36 |
|
37 | ## API
|
38 |
|
39 | ### Props
|
40 |
|
41 | #### :src <sup>String / Object - default: ''<sup>
|
42 | The url of the pdf file. `src` may also be a `string|TypedArray|DocumentInitParameters|PDFDataRangeTransport` for more details, see [`PDFJS.getDocument()`](https://github.com/mozilla/pdf.js/blob/8ff1fbe7f819513e7d0023df961e3d223b35aefa/src/display/api.js#L117).
|
43 |
|
44 | #### :page <sup>Number - default: 1<sup>
|
45 | The page number to display.
|
46 |
|
47 | #### :rotate <sup>Number - default: 0<sup>
|
48 | The page rotation in degrees, only multiple of 90 are valid.
|
49 |
|
50 | ### Events
|
51 |
|
52 | #### @password <sup>(updatePassword, reason)<sup>
|
53 | * `updatePassword`: The function to call with the pdf password.
|
54 | * `reason`: the reason why this function is called `'NEED_PASSWORD'` or `'INCORRECT_PASSWORD'`
|
55 |
|
56 | #### @progress <sup>Number<sup>
|
57 | Document loading progress. Range [0, 1].
|
58 |
|
59 | #### @loaded
|
60 | Triggered when the document is loaded.
|
61 |
|
62 | #### @page-loaded <sup>Number<sup>
|
63 | Triggered when a page is loaded.
|
64 |
|
65 | #### @num-pages <sup>Number<sup>
|
66 | The total number of pages of the pdf.
|
67 |
|
68 | #### @error <sup>Object<sup>
|
69 | Triggered when an error occurred.
|
70 |
|
71 | #### @link-clicked <sup>Number<sup>
|
72 | Triggered when an internal link is clicked
|
73 |
|
74 |
|
75 | ### Public methods
|
76 |
|
77 | #### print(dpi, pageList) * _experimental_ *
|
78 | * `dpi`: the print rezolution of the document (try 100).
|
79 | * `pageList`: the list (array) of pages to print.
|
80 |
|
81 | ### Public static methods
|
82 |
|
83 | #### createLoadingTask(src)
|
84 | * `src`: see `:src` prop
|
85 | This function creates a PDFJS loading task that can be used and reused as `:src` property.
|
86 | The loading task is a promise that resolves with the PDFJS pdf document that exposes the `numPages` property (see example below).
|
87 |
|
88 | **beware:** when the component is destroyed, the object returned by `createLoadingTask()` become invalid.
|
89 |
|
90 |
|
91 | ## Examples
|
92 |
|
93 | ##### Example - current page / page count
|
94 | ```vue
|
95 | <template>
|
96 | <div>
|
97 | {{currentPage}} / {{pageCount}}
|
98 | <pdf
|
99 | src="https://cdn.mozilla.net/pdfjs/tracemonkey.pdf"
|
100 | @num-pages="pageCount = $event"
|
101 | @page-loaded="currentPage = $event"
|
102 | ></pdf>
|
103 | </div>
|
104 | </template>
|
105 |
|
106 | <script>
|
107 |
|
108 | import pdf from 'vue-pdf'
|
109 |
|
110 | export default {
|
111 | components: {
|
112 | pdf
|
113 | },
|
114 | data() {
|
115 | return {
|
116 | currentPage: 0,
|
117 | pageCount: 0,
|
118 | }
|
119 | }
|
120 | }
|
121 |
|
122 | </script>
|
123 | ```
|
124 |
|
125 |
|
126 | ##### Example - display multiple pages of the same pdf document
|
127 | ```vue
|
128 | <template>
|
129 | <div>
|
130 | <pdf
|
131 | v-for="i in numPages"
|
132 | :key="i"
|
133 | :src="src"
|
134 | :page="i"
|
135 | style="display: inline-block; width: 25%"
|
136 | ></pdf>
|
137 | </div>
|
138 | </template>
|
139 |
|
140 | <script>
|
141 |
|
142 | import pdf from 'vue-pdf'
|
143 |
|
144 | var loadingTask = pdf.createLoadingTask('https://cdn.mozilla.net/pdfjs/tracemonkey.pdf');
|
145 |
|
146 | export default {
|
147 | components: {
|
148 | pdf
|
149 | },
|
150 | data() {
|
151 | return {
|
152 | src: loadingTask,
|
153 | numPages: undefined,
|
154 | }
|
155 | },
|
156 | mounted() {
|
157 |
|
158 | this.src.then(pdf => {
|
159 |
|
160 | this.numPages = pdf.numPages;
|
161 | });
|
162 | }
|
163 | }
|
164 |
|
165 | </script>
|
166 | ```
|
167 |
|
168 |
|
169 | ##### Example - print all pages
|
170 | ```vue
|
171 | <template>
|
172 | <button @click="$refs.myPdfComponent.print()">print</button>
|
173 | <pdf ref="myPdfComponent" src="https://cdn.mozilla.net/pdfjs/tracemonkey.pdf"></pdf>
|
174 | </template>
|
175 | ```
|
176 |
|
177 |
|
178 | ##### Example - print multiple pages
|
179 | ```vue
|
180 | <template>
|
181 | <button @click="$refs.myPdfComponent.print(100, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])">print</button>
|
182 | <pdf ref="myPdfComponent" src="https://cdn.mozilla.net/pdfjs/tracemonkey.pdf"></pdf>
|
183 | </template>
|
184 | ```
|
185 |
|
186 |
|
187 | ##### Example - get text content
|
188 | ```vue
|
189 | <template>
|
190 | <div>
|
191 | <button
|
192 | @click="logContent"
|
193 | >
|
194 | log content
|
195 | </button>
|
196 | <pdf
|
197 | ref="myPdfComponent"
|
198 | src="https://cdn.mozilla.net/pdfjs/tracemonkey.pdf"
|
199 | ></pdf>
|
200 | </div>
|
201 | </template>
|
202 |
|
203 | <script>
|
204 |
|
205 | import pdf from 'vue-pdf'
|
206 |
|
207 | export default {
|
208 | components: {
|
209 | pdf
|
210 | },
|
211 | methods: {
|
212 | logContent() {
|
213 |
|
214 | this.$refs.myPdfComponent.pdf.forEachPage(function(page) {
|
215 |
|
216 | return page.getTextContent()
|
217 | .then(function(content) {
|
218 |
|
219 | var text = content.items.map(item => item.str);
|
220 | console.log(text);
|
221 | })
|
222 | });
|
223 | }
|
224 | }
|
225 | }
|
226 |
|
227 | </script>
|
228 | ```
|
229 |
|
230 |
|
231 | ##### Example - complete
|
232 | ```vue
|
233 | <template>
|
234 | <div>
|
235 | <input type="checkbox" v-model="show">
|
236 | <select v-model="src" style="width: 30em">
|
237 | <option v-for="item in pdfList" :value="item" v-text="item"></option>
|
238 | </select>
|
239 | <input v-model.number="page" type="number" style="width: 5em"> /{{numPages}}
|
240 | <button @click="rotate += 90">⟳</button>
|
241 | <button @click="rotate -= 90">⟲</button>
|
242 | <button @click="$refs.pdf.print()">print</button>
|
243 | <div style="width: 50%">
|
244 | <div v-if="loadedRatio > 0 && loadedRatio < 1" style="background-color: green; color: white; text-align: center" :style="{ width: loadedRatio * 100 + '%' }">{{ Math.floor(loadedRatio * 100) }}%</div>
|
245 | <pdf v-if="show" ref="pdf" style="border: 1px solid red" :src="src" :page="page" :rotate="rotate" @password="password" @progress="loadedRatio = $event" @error="error" @num-pages="numPages = $event" @link-clicked="page = $event"></pdf>
|
246 | </div>
|
247 | </div>
|
248 | </template>
|
249 | <script>
|
250 | import pdf from 'vue-pdf'
|
251 |
|
252 | export default {
|
253 | components: {
|
254 | pdf: pdf
|
255 | },
|
256 | data () {
|
257 | return {
|
258 | show: true,
|
259 | pdfList: [
|
260 | '',
|
261 | 'https://cdn.mozilla.net/pdfjs/tracemonkey.pdf',
|
262 | 'https://cdn.rawgit.com/mozilla/pdf.js/c6e8ca86/test/pdfs/freeculture.pdf',
|
263 | 'https://cdn.rawgit.com/mozilla/pdf.js/c6e8ca86/test/pdfs/annotation-link-text-popup.pdf',
|
264 | 'https://cdn.rawgit.com/mozilla/pdf.js/c6e8ca86/test/pdfs/calrgb.pdf',
|
265 | 'https://cdn.rawgit.com/sayanee/angularjs-pdf/68066e85/example/pdf/relativity.protected.pdf',
|
266 | 'data:application/pdf;base64,JVBERi0xLjUKJbXtrvsKMyAwIG9iago8PCAvTGVuZ3RoIDQgMCBSCiAgIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlCj4+CnN0cmVhbQp4nE2NuwoCQQxF+/mK+wMbk5lkHl+wIFislmIhPhYEi10Lf9/MVgZCAufmZAkMppJ6+ZLUuFWsM3ZXxvzpFNaMYjEriqpCtbZSBOsDzw0zjqPHZYtTrEmz4eto7/0K54t7GfegOGCBbBdDH3+y2zsMsVERc9SoRkXORqKGJupS6/9OmMIUfgypJL4KZW5kc3RyZWFtCmVuZG9iago0IDAgb2JqCiAgIDEzOAplbmRvYmoKMiAwIG9iago8PAogICAvRXh0R1N0YXRlIDw8CiAgICAgIC9hMCA8PCAvQ0EgMC42MTE5ODcgL2NhIDAuNjExOTg3ID4+CiAgICAgIC9hMSA8PCAvQ0EgMSAvY2EgMSA+PgogICA+Pgo+PgplbmRvYmoKNSAwIG9iago8PCAvVHlwZSAvUGFnZQogICAvUGFyZW50IDEgMCBSCiAgIC9NZWRpYUJveCBbIDAgMCA1OTUuMjc1NTc0IDg0MS44ODk3NzEgXQogICAvQ29udGVudHMgMyAwIFIKICAgL0dyb3VwIDw8CiAgICAgIC9UeXBlIC9Hcm91cAogICAgICAvUyAvVHJhbnNwYXJlbmN5CiAgICAgIC9DUyAvRGV2aWNlUkdCCiAgID4+CiAgIC9SZXNvdXJjZXMgMiAwIFIKPj4KZW5kb2JqCjEgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzCiAgIC9LaWRzIFsgNSAwIFIgXQogICAvQ291bnQgMQo+PgplbmRvYmoKNiAwIG9iago8PCAvQ3JlYXRvciAoY2Fpcm8gMS4xMS4yIChodHRwOi8vY2Fpcm9ncmFwaGljcy5vcmcpKQogICAvUHJvZHVjZXIgKGNhaXJvIDEuMTEuMiAoaHR0cDovL2NhaXJvZ3JhcGhpY3Mub3JnKSkKPj4KZW5kb2JqCjcgMCBvYmoKPDwgL1R5cGUgL0NhdGFsb2cKICAgL1BhZ2VzIDEgMCBSCj4+CmVuZG9iagp4cmVmCjAgOAowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDA1ODAgMDAwMDAgbiAKMDAwMDAwMDI1MiAwMDAwMCBuIAowMDAwMDAwMDE1IDAwMDAwIG4gCjAwMDAwMDAyMzAgMDAwMDAgbiAKMDAwMDAwMDM2NiAwMDAwMCBuIAowMDAwMDAwNjQ1IDAwMDAwIG4gCjAwMDAwMDA3NzIgMDAwMDAgbiAKdHJhaWxlcgo8PCAvU2l6ZSA4CiAgIC9Sb290IDcgMCBSCiAgIC9JbmZvIDYgMCBSCj4+CnN0YXJ0eHJlZgo4MjQKJSVFT0YK',
|
267 | ],
|
268 | src:'',
|
269 | loadedRatio: 0,
|
270 | page: 1,
|
271 | numPages: 0,
|
272 | rotate: 0,
|
273 | }
|
274 | },
|
275 | methods: {
|
276 | password: function(updatePassword, reason) {
|
277 |
|
278 | updatePassword(prompt('password is "test"'));
|
279 | },
|
280 | error: function(err) {
|
281 |
|
282 | console.log(err);
|
283 | }
|
284 | }
|
285 | }
|
286 | </script>
|
287 | ```
|
288 |
|
289 | ## Credits
|
290 | [<img src="https://www.franck-freiburger.com/FF.png" width="16"> Franck Freiburger](https://www.franck-freiburger.com)
|