前记:上一篇 https://www.cnblogs.com/adouwt/p/9211003.html, 说到了一个完整的vue插件开发、发布的流程,总结下来就讲了这么一个事,如何注入vue, 如果封装vue插件,如何测试vue插件,以及如何发布vue插件到npm。但是,这里开发测试到发布是分开在两个项目的,未免有些多余,今天的笔记讲的就是在上一篇的基础上,重新换了一下项目框架,讲开发测试,到打包发

布一个完整的项目,这个项目欢迎大家测试使用,一个基于vue上传文件的一个插件,能够显示上传的速度和进度,如果是图片的话,也可以显示上传预览,有bug即时反馈哦!

github 地址: https://github.com/adouwt/vue-upload

1.项目架构目录:

这里采用的是vue-cli 脚手架,版本是2.**,vue-cli 3.0 已经出来有一段了。今天暂不用3.0 的,回头会详细说上3.0的打包使用。项目目录如下:

这个项目结构直接用 vue init webapck vue-upload  ,脚手架生的模版,大架构我基本没动,添加了一点自己的配置文件和新加了自己的文件夹。如下:

2.打包插件源码的配置文件

var path = require('path')
var webpack = require('webpack') module.exports = {
entry: './src/plugin/ajax-upload.js',
output: {
path: path.resolve(__dirname, '../dist'),
publicPath: '/dist/',
filename: 'vueAjaxUpload.js',
library: 'vueAjaxUpload', // library指定的就是你使用require时的模块名,这里便是require("vueAjaxUpload")
libraryTarget: 'umd', //libraryTarget会生成不同umd的代码,可以只是commonjs标准的,也可以是指amd标准的,也可以只是通过script标签引入的。
umdNamedDefine: true // 会对 UMD 的构建过程中的 AMD 模块进行命名。否则就使用匿名的 define。
},
module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
}, {
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
} if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}

上面的配置文件也很简单,主要就是入口文件和输出文件,上面红色标记的部分,我们需要经常修改的也是这个两个参数,下面的打包规则我们可以不用多管。

3.package.json 的执行脚本的修改。

4.开发插件

在plugin下,新建ajax-upload.js ajax-upload.vue。

ajax-upload.js

import upload from './ajax-upload.vue'
let ajaxUpload = {}
ajaxUpload.install = function (Vue, options) {
Vue.prototype.$msg = 'Hello I am test.js'
Vue.prototype.$myMethod = function (arr) {
if (arr.length < 0) {
return false
} else {
arr = arr.join('连接你我')
return arr
}
}
Vue.component(upload.name, upload)
}
export default ajaxUpload

ajax-upload.vue

<template>
<div class="wt-upload">
<div class="file-area">
<div>
<input type="file" name="file" id="file" class="file" @change="previewImage($event)" multiple/>
<label for="file" class="file-label">选择文件</label>
</div>
<div v-show="options.imagePreview">
<div class="img-preview" ref="imgPreview">
</div>
</div>
<p class="mt-sm">
<button id="upload" @click="uploadFile(file)" class="upload">上传</button>
</p>
<div class="progress-area" v-show="options.showProgress ? options.showProgress : false">
<p class="mb-sm">进度显示:</p>
<div class="progress">
<div class="progress-bar" id="progress" ref="progress">0%</div>
</div>
<div>
<p class="time" ref="time"></p>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'hupload',
props: ['options'],
data () {
return {
imgPreview: null,
xhr: null,
loaded: 0,
ot: 0,
total: 0,
oloaded: 0,
file: null
}
},
components: {
},
mounted () {
this.imgPreview = this.$refs.imgPreview
},
created () {
this.xhr = new XMLHttpRequest()
},
methods: {
uploadFile (file) {
if (!file) {
alert('请选择文件')
return
}
if (this.options.limitSize) {
if (file.files[0].size > (this.options.limitSize) * 1e6) {
alert(`文件大小不得超过${this.options.limitSize}M`)
return
}
} else {
if (file.files[0].size > 10000000) {
alert(`文件大小不得超过10M`)
return
}
}
if (!this.options.fileUploadName) {
alert('请配置与后端约定上传的key值')
return
}
if (!this.options.url) {
alert('请配置与后端约定的上传接口地址')
return
}
let formData = new FormData()
formData.append(this.options.fileUploadName, file.files[0])
this.xhr.onload = this.uploadSuccess
this.xhr.upload.onprogress = this.setProgress
this.xhr.onerror = this.uploadFailed
this.xhr.open('post', this.options.url, true)
this.xhr.send(formData)
},
previewImage (event) {
this.file = event.target
this.imgPreview.innerHTML = ''
// 每次重新选择文件的时候,都会去除上次选择产生的img标签
let isImg = (event.target.files[0].type).indexOf('image/') > -1
if (isImg) {
// 如果是图片 就解析图片预览
let img = document.createElement('img')
this.imgPreview.appendChild(img)
let reader = new FileReader()
reader.onload = function (event) {
img.src = event.target.result
img.width = '200'
}
reader.readAsDataURL(event.target.files[0])
} else {
console.log('为文件选择一个默认的logo')
}
},
setProgress (event) {
let progress = this.$refs.progress
// event.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable不为真,则event.total等于0
if (event.lengthComputable) {
this.loaded = event.loaded
this.total = event.total
let complete = (event.loaded / event.total * 100).toFixed(1)
progress.innerHTML = Math.round(complete) + '%'
progress.style.width = complete + '%'
}
// let time = document.getElementById('time')
let time = this.$refs.time
let nt = new Date().getTime() // 获取当前时间
let pertime = (nt - this.ot) / 1000
// 计算出上次调用该方法时到现在的时间差,单位为s
this.ot = new Date().getTime() // 重新赋值时间,用于下次计算
let perload = event.loaded - this.oloaded
// 计算该分段上传的文件大小,单位b
this.oloaded = event.loaded // 重新赋值已上传文件大小,用以下次计算
// 上传速度计算
let speed = perload / pertime // 单位b/s
let bspeed = speed
let units = 'b/s' // 单位名称
if (speed / 1024 > 1) {
speed = speed / 1024
units = 'k/s'
}
if (speed / 1024 > 1) {
speed = speed / 1024
units = 'M/s'
}
speed = speed.toFixed(1)
// 剩余时间
let resttime = ((event.total - event.loaded) / bspeed).toFixed(1)
resttime = resttime > 0 ? resttime : '0'
time.innerHTML = '传输速度:' + speed + units + ',剩余时间:' + resttime + 's'
},
uploadSuccess () {
if (this.xhr.readyState === 4 && this.xhr.status === 200) {
setTimeout(() => {
// 回调给父组件
this.sendMsgToParent('success')
}, 1000)
}
},
uploadFailed (err) {
console.log(err)
this.sendMsgToParent({'error': err})
},
sendMsgToParent (msg) {
this.$emit('receiveUploadMsg', msg)
}
}
}
</script> <!-- 公共的样式 -->
<style>
.mb-sm {
margin-bottom: 10px;
}
.mt-sm {
margin-top: 10px;
}
.wt-upload {
text-align: left;
}
.file-area {
width: 80%;
margin: 0 auto;
}
.file-area .file {
display: none;
}
.wt-upload .file-label {
display: block;
width: 100px;
padding: 8px;
background: #39D2B4;
color: #fff;
font-size: 1em;
transition: all .4s;
cursor: pointer;
text-align: center;
}
.wt-upload .file-label:hover {
background: rgb(123, 219, 200);
}
.wt-upload .file-label:focus {
background: rgb(32, 148, 125);
}
.wt-upload .img-preview {
margin-top: 20px;
margin-bottom: 20px;
}
.wt-upload .upload,.wt-upload .abort {
display: inline-block;
width: 100px;
padding: 8px;
background: #39D2B4;
color: #fff;
font-size: 1em;
transition: all .4s;
cursor: pointer;
outline: none;
border: none;
}
.wt-upload .upload:hover {
background: rgb(123, 219, 200);
}
.wt-upload .upload:focus {
background: rgb(32, 148, 125);
}
.wt-upload .progress-area {
padding: 20px;
}
.wt-upload .progress {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
height: 1rem;
overflow: hidden;
font-size: 0.75rem;
background-color: #e9ecef;
border-radius: 0.25rem;
}
.wt-upload .progress-bar {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
color: #fff;
text-align: center;
background-color: #007bff;
transition: width 0.6s ease;
}
.wt-upload .time {
margin-top: 10px;
}
</style>

ajax-upload.js的讲解: 引入同级目录的ajax-upload.vue ,通过给一个自定义的对象添加install 方法,然后通过vue.component 方法注册到vue。这里也可以给vue,通过原型方法注册变量和方法。这里我们不需要,我们就只做了一个demo;

ajax-upload.vue的讲解:里面具体的js业务逻辑不讲解了,就提个 props,和name 的属性,我们通过这个方法接受到父组件(调用该组件的组件)传递过来的参数,然后可以通过我们的定义的方法,如果是必须传递的参数,没有该参数我们就alert 提示;name 属性就是调用的封装的标签。为了减少项目的依赖插件的个数,我们也直接使用css不使用less等。

5.本地测试开发的插件的使用:

在dev文件夹下新建文件 dev-upload.vue

代码:

<template>
<div>
<h2>开发测试</h2>
<hupload :options=options v-on:receiveUploadMsg="receiveUploadMsg"> </hupload>
</div>
</template> <script>
import Vue from 'vue'
import hupload from '../plugin/ajax-upload.js'

Vue.use(hupload)

export default {
data () {
return {
options: {
'showProgress': true,
'imagePreview': true,
'url': 'str',
'fileUploadName': 'ajax-upload',
'limitSize': 1
}
}
},
components: {
},
methods: {
receiveUploadMsg (msg) {
console.log(msg)
}

}
}
</script> <style>
</style>

这里使用组件就不直接在main.js下引入插件,直接在使用该插件的组件中,引入,然后通过vue.use 的方法使用组件:

import Vue from 'vue'
import hupload from '../plugin/ajax-upload.js'
Vue.use(hupload)

使用组件,传递参数和接受参数

<hupload :options=options v-on:receiveUploadMsg="receiveUploadMsg"> </hupload>

这里组件的通信 父组件 -> 子组件, 子组件 -> 父组件 ,通过props 接受到父组件的参数,通过事件的方式接受子组件传递过来的参数。

当然,要看到这个组件的使用是否正确,就要看页面了,页面路由 vue-router 如下:

访问页面正常显示,没有报错:

6.打包插件,并本地测试插件

上面第5步骤已经展示了插件是可以使用的,接下里就是打包了。

执行:

npm run dist

本地测试,先开页面路由:

访问页面,没有报错:

以上看到了插件的引入方式不同。

7.发布插件

测试OK了,接下里就是发布了(假设你这里已经登陆npm了),执行命令:

npm publish

记住,每发布一次,需要修改package.json 的版本号:

不然报错。

发布完之后,我们就可以转到我们的npm 官网上看看我们的项目。

https://www.npmjs.com/package/vue-ajax-upload

8.使用插件

安装使用:

npm install vue-ajax-upload --save

测试:

访问页面:

注意:大大的红字,如果要在本项目下测试,需要修改package.json 项目名称,不然报项目名字和包名字是一致的错,无法安装的,如下;

我们来一个实际跑一下这个插件:

修改options:

演示视频:

  结束语: 这个笔记继上一篇 vue插件开发流程详解-从开发到发布至npm(一),替换了开发和测试的项目架构。除了在npm 登陆的那快,基本都是可以跳过上一篇,直接看这篇的,这个插件可以显示上传图片预览,上传速度和上传进度,如果需要讲解这部分话,请在下方留言,我会单独开一篇讲解这部分的内容。接下来的任务,还是要丰富和完善这个插件的具体内容,里面还有一些不足。若您发现不足的地方,敬请指教,

如果觉得好的话,https://github.com/adouwt/vue-upload,以star表示鼓励,继续完善这个plugin哇!

下一篇:基于vue-cli 3 的插件开发,将减少很多的配置工作

https://cli.vuejs.org/zh/dev-guide/plugin-dev.html

如需转载,请说明转载出处。

手把手教你写vue插件并发布(二)的更多相关文章

  1. 手把手教你写vue插件并发布(一)

    vue的插件开发 这篇文章较长,需要一定的阅读时间.这里有一份改善版本的插件笔记,在一个项目下完成开发.测试.发布的全过程.https://www.cnblogs.com/adouwt/p/96555 ...

  2. 手把手教你写 Vue UI 组件库

    最近在研究 muse-ui 的实现,发现网上很少有关于 vue 插件具体实现的文章,官方的文档也只是一笔带过,对于新手来说并不算友好. 笔者结合官方文档,与自己的摸索总结,以最简单的 FlexBox  ...

  3. 手把手教你使用Rollup打包📦并发布自己的工具库🔧

    DevUI是一支兼具设计视角和工程视角的团队,服务于华为云DevCloud平台和华为内部数个中后台系统,服务于设计师和前端工程师. 官方网站:devui.design Ng组件库:ng-devui(欢 ...

  4. 手把手教你写电商爬虫-第四课 淘宝网商品爬虫自动JS渲染

    版权声明:本文为博主原创文章,未经博主允许不得转载. 系列教程: 手把手教你写电商爬虫-第一课 找个软柿子捏捏 手把手教你写电商爬虫-第二课 实战尚妆网分页商品采集爬虫 手把手教你写电商爬虫-第三课 ...

  5. 只有20行Javascript代码!手把手教你写一个页面模板引擎

    http://www.toobug.net/article/how_to_design_front_end_template_engine.html http://barretlee.com/webs ...

  6. 手把手教你写DI_0_DI是什么?

    DI是什么? Dependency Injection 常常简称为:DI. 它是实现控制反转(Inversion of Control – IoC)的一个模式. fowler 大大大神 "几 ...

  7. 手把手教你写Sublime中的Snippet

    手把手教你写Sublime中的Snippet Sublime Text号称最性感的编辑器, 并且越来越多人使用, 美观, 高效 关于如何使用Sublime text可以参考我的另一篇文章, 相信你会喜 ...

  8. 手把手教你写LKM rookit! 之 第一个lkm程序及模块隐藏(一)

    唉,一开始在纠结起个什么名字,感觉名字常常的很装逼,于是起了个这<手把手教你写LKM rookit> 我觉得: 你们觉得:...... 开始之前,我们先来理解一句话:一切的操作都是系统调用 ...

  9. 手把手教你写电商爬虫-第三课 实战尚妆网AJAX请求处理和内容提取

    版权声明:本文为博主原创文章,未经博主允许不得转载. 系列教程: 手把手教你写电商爬虫-第一课 找个软柿子捏捏 手把手教你写电商爬虫-第二课 实战尚妆网分页商品采集爬虫 看完两篇,相信大家已经从开始的 ...

随机推荐

  1. Python3中如何解决中文乱码与编码的问题

    1.解决乱码问题: pyhton中内部所有编码是Unicode,中文是gbk:正常情况下,我们输出的是utf-8: 我们可以采用sys.getdefaultencoding()查看系统默认的编码: 解 ...

  2. Windows apache-flume-1.6.0+Kafka+Es

    apache-flume-1.6.0 kafka_2.11-1.1.0 elasticsearch1.5.1 flume配置 a1.sources = kafkaSource a1.channels ...

  3. nodejs 实现跨域

    1.nodejs let http = require('http'); http.createServer((req,res) => { res.setHeader("Access- ...

  4. Jetson TX1 SD card启动

    上网DNS /var/run/NetworkManager/resolv.conf nameserver 211.100.225.34 nameserver 219.239.26.42

  5. 图片的HTML

    Code <center> <img style="border-radius: 0.3125em; box-shadow: 0 2px 4px 0 rgba(34,36, ...

  6. python 第三方库的加载与虚拟机的登录

    通过pip来安装python模块(pip方式仅需要联网即可,不需要下载其他文件即可实现扩展库哦的安装.升级和卸载).下载python3.5以上的版本(包括3.5),在我的电脑输入cmd进入命令提示符, ...

  7. 入坑MATLAB必会的吐血总结

    本渣想回过头来整理一下MATLAB的一些基本的知识(很多东西比较琐碎,应该系统的梳理梳理),下文中没有提到的,自己用help查即可. 此文用来存个档,便于回顾. 由于matlab各版本部分语法存在差异 ...

  8. 完全理解 Python 迭代对象、迭代器、生成器(转)

    完全理解 Python 迭代对象.迭代器.生成器 本文源自RQ作者的一篇博文,原文是Iterables vs. Iterators vs. Generators » nvie.com,俺写的这篇文章是 ...

  9. 洛谷P1169[ZJOI2007]棋盘制作

    题目 一道悬线法的裸题,悬线法主要是可以处理最大子矩阵的问题. 而这道题就是比较经典的可以用悬线法来处理的题. 而悬线法其实就是把矩阵中对应的每个位置上的元素分别向左向上向右,寻找到不能到达的地方,然 ...

  10. My Todo-List

    有些事情要明着写出来才会去干. 这里是一个不断更新的Todo-List,大致按照重要度和列出时间排序. 主要着眼短期计划,其中的大部分事务应该在一周内解决,争取不做一只鸽子. 填好模板库的坑. 学习树 ...