插件通常用来为 Vue 添加全局功能,例如数据字典插件、上传插件等等。
一、使用插件
通过全局方法 Vue.use()
使用插件。它需要在你调用 new Vue()
启动应用之前完成:
// 调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin)
new Vue({
// ...组件选项
})
也可以传入一个可选的选项对象:
Vue.use(MyPlugin, { someOption: true })
Vue.use
会自动阻止多次注册相同插件,届时即使多次调用也只会注册一次该插件,在像 CommonJS 这样的模块环境中,你应该始终显式地调用 Vue.use()。
当 install 方法被同一个插件多次调用,插件将只会被安装一次。
二、开发插件
Vue.js 的插件应该暴露一个 install
方法。这个方法的第一个参数是 Vue
构造器,第二个参数是一个可选的选项对象:
MyPlugin.install = function (Vue, options) {
// 1. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 2. 注入组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
// 3. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
// 4. 添加全局组件
Vue.component('uploadplugin',upload) //upload为组件
}
注意:如果插件是一个对象,必须提供 install
方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。
三、开发实例
参考一个上传插件:
import upload from './ajax-upload.vue'
let ajaxUpload = {}
// eslint-disable-next-line no-unused-vars
ajaxUpload.install = function (Vue, options) {
Vue.component(upload.name, upload) // testPanel.name 组件的name属性
}
export default ajaxUpload
然后上传插件对应的组件:
<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>
main.js里面安装插件:
import fileupload from './plugin/fileupload/ajax-upload.js'
Vue.use(fileupload)
插件使用:
<template>
<div>
<h2>插件开发测试</h2>
<hupload :options=options v-on:receiveUploadMsg="receiveUploadMsg"> </hupload>
</div>
</template>
<script>
/*import Vue from 'vue'
import hupload from '../plugin/components/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>
参考:
https://cn.vuejs.org/v2/guide/plugins.html#%E4%BD%BF%E7%94%A8%E6%8F%92%E4%BB%B6
https://cn.vuejs.org/v2/api/#Vue-use