前記:上一篇 http://www.javashuo.com/article/p-volgacsi-cg.html, 說到了一個完整的vue插件開發、發佈的流程,總結下來就講了這麼一個事,如何注入vue, 若是封裝vue插件,如何測試vue插件,以及如何發佈vue插件到npm。可是,這裏開發測試到發佈是分開在兩個項目的,未免有些多餘,今天的筆記講的就是在上一篇的基礎上,從新換了一下項目框架,講開發測試,到打包發css
佈一個完整的項目,這個項目歡迎你們測試使用,一個基於vue上傳文件的一個插件,可以顯示上傳的速度和進度,若是是圖片的話,也能夠顯示上傳預覽,有bug即時反饋哦!html
這裏採用的是vue-cli 腳手架,版本是2.**,vue-cli 3.0 已經出來有一段了。今天暫不用3.0 的,回頭會詳細說上3.0的打包使用。項目目錄以下:vue
這個項目結構直接用 vue init webapck vue-upload ,腳手架生的模版,大架構我基本沒動,添加了一點本身的配置文件和新加了本身的文件夾。以下:node
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 }) ]) }
上面的配置文件也很簡單,主要就是入口文件和輸出文件,上面紅色標記的部分,咱們須要常常修改的也是這個兩個參數,下面的打包規則咱們能夠不用多管。webpack
在plugin下,新建ajax-upload.js ajax-upload.vue。git
ajax-upload.jsgithub
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.vueweb
<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
ajax-upload.vue的講解:裏面具體的js業務邏輯不講解了,就提個 props,和name 的屬性,咱們經過這個方法接受到父組件(調用該組件的組件)傳遞過來的參數,而後能夠經過咱們的定義的方法,若是是必須傳遞的參數,沒有該參數咱們就alert 提示;name 屬性就是調用的封裝的標籤。爲了減小項目的依賴插件的個數,咱們也直接使用css不使用less等。vue-router
在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 以下:
訪問頁面正常顯示,沒有報錯:
上面第5步驟已經展現了插件是能夠使用的,接下里就是打包了。
執行:
npm run dist
本地測試,先開頁面路由:
訪問頁面,沒有報錯:
以上看到了插件的引入方式不一樣。
測試OK了,接下里就是發佈了(假設你這裏已經登錄npm了),執行命令:
npm publish
記住,每發佈一次,須要修改package.json 的版本號:
否則報錯。
發佈完以後,咱們就能夠轉到咱們的npm 官網上看看咱們的項目。
https://www.npmjs.com/package/vue-ajax-upload
測試:
訪問頁面:
咱們來一個實際跑一下這個插件:
修改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
如需轉載,請說明轉載出處。