从去年年初开始,本身便下决心要写一个vue系列的博客,但时至今日,才写系列的第三篇博客,想来甚是惭愧。javascript
可是慢归慢,每一篇都要保证质量,以及要写出本身的心路历程,防止本身工做中填的坑再让读者走一遍。html
vue上手相对react来讲是比较简单的,对于vue的基本指令以及语法,应该没有什么能比官网更详细,更生动的了。仔细想来,vue值得一说的,在项目中会让新手感到困惑的,是vue的组件,今天就最近工做中用到的一个pdf查看组件,和你们聊聊vue的组件。最后会讲如何将本身的代码封装成一个npm包,发布到npm官网。前端
去年5月份的,写了vue系列的第一篇使用vue-cli脚手架工具搭建vue-webpack项目,今天再次使用vue-cli初始化项目时,发现vue-cli已经升级到2.9.2。vue
多说一句,由于vue-cli的命令为vue,因此查看vue-cli的版本时,须要使用vue -V,并且是大写的V。仔细看下vue-cli 2.9的官方模板,惊喜的发现多了一个pwa模板。java
前一阵子,谷歌开发者大会在上海举办,会上主推pwa,在这在简单说下PWA,大神可直接忽略。react
PWA是Progressive Web App的缩写,字面意思理解为渐进加强的网页应用。一个 PWA 应用首先是一个网页, 能够经过 Web 技术编写出一个网页应用. 随后添加上 App Manifest 和 Service Worker 来实现 PWA 的安装和离线等功能。jquery
在一个正常的HTML中,添加一个link标签,href为manifest.json,便可将你的网页应用添加到主屏幕。webpack
manifest.json中会包含你的图标、名称。背景色等信息。git
{ "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 在网页已经关闭的状况下还能够运行, 用来实现页面的缓存和离线, 后台通知等等功能。github
为了让应用离线工做,须要注册一个 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组件。
最近笔者在项目中遇到一个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便可。
<template> <div class="pdf-wraper"> <div id="cvsWraper"> <div class="loading-pdf" v-if="isloading">{{loadingTxt}}</div> </div> </div> </template>
该组件须要传两个参数,一个是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包,下面我会一步步讲讲如何将上述的vue-pdf-viewer组件发布到npm官网的。
执行npm init后,根据命令行提示,依次输入
包名称
版本
描述
入口文件
测试脚本
关键词
做者
版权信息(协议)
等等,最后OK,生成一个package.json文件。
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包都是这样,咱就按人家的来吧 - -
好了,我们的包已经准备就绪了,就差发布!!!
打开冰箱,将大象放进冰箱,关上冰箱门。
注册很简单的,只须要一个邮箱就行,连网站都打不开的同窗就好好写写jquery去吧。
在命令行输入npm login,
而后依次输入用户名和密码,以及注册的邮箱。
注意:输入密码时,密码是不会显示出来的,不要方!
登陆后只要没有错误提示即登陆成功。
离成功只差一步。
一切准备稳当,cd 到咱们的vue-pdf-shower目录,先检查下npm有没有重名的包。
能够去npm官网搜索,也能够直接npm install 包名,若是报错,那么恭喜你包名没有重复的。
执行npm publish
定睛一看,报了个错。原来是package.json 的版本号没有改。将版本号升一个级,在执行publish。
成功!
发现已经能够搜到,由于我是昨天发的包,一天时间内已有116次下载。嗯,还不赖。
最后附上本组件github地址,欢迎你们拍砖。
https://github.com/TJ666/vue-pdf-shower