Vue插件开发之拍照上传功能

更新日期: 2023-01-04阅读: 1.3k标签: 插件

一、前言

因为最近做H5项目,需要拍照上传照片的功能。

于是就写了一个传统的vue组件,功能实现都没问题,可是用着用着发现了问题:

  • 1.传统组件引用需要先import,然后放到components,然后放在template,很繁琐。
  • 2.项目不同,UI设计不同,需要改样式代码

多个项目都有拍照上传功能,但是界面样式都不一样,每次还要临时改样式。

所以本着偷懒的原则,把这个组件拍照上传到客户端这部分功能UI给单独分离开出来,单独写成一个插件,即用即插。

优点:

  • 1.和UI分离,单独使用,保留核心功能,提高了复用性。
  • 2.使用形式为this.$useUpload,十分方便,无需像组件引入那样,便捷性大大提升!


二、开始编写上传组件

2.1使用jsx语法更加简洁

// upload-basic.vue
export default {
  name: 'UploadBasic',
  methods: {
      _changeFile(e) {
        const file = e.target.files[0];
        const reader = new FileReader();
        const self = this
        
        reader.onloadend = function() {
          const result = this.result;
          const img = new Image();
          img.src = result;
          img.onload = function() {
            self.$el.appendChild(img)
          }
        }
        
        reader.readAsDataURL(file);
      }
  }
  render() {
      return (
        <input ref="upBIuput" type="file" accept="image/*" onChange={(e) => {this._changeFile(e)}}/>
      )
  }
}

上面代码很简单,主要就是在页面上渲染一个input元素,这个input用于文件的上传,在手机上点击后的效果就是唤醒系统的相机和相册(2选1)

当你上传图片,或者拍照上传后,就会触发onChange事件,通过e.target.files[0]就可以拿到当前上传的文件(这里指照片)。

接着我使用了一个FileReader去读取文件的内容,将文件格式转换成base64位的形式,然后赋值到imgsrc属性上,当图片加载完毕后,通过this.$el.appenChild()方法把img这个dom元素渲染到页面上进行图片的预览。

这样就实现了拍照上传到浏览器并且预览,然后后续可以通过把file塞到formData对象中上传到后端服务器(这部分内容不提)。

2.2 把input隐藏掉

因为我们一般上传都有一个很好看的UI界面对吧,不需要这个丑丑的input,所以我们只需要加一句样式代码去隐藏这个input。

<input ref="upBIuput" style="display:none;" type="file" accept="image/*" onChange={(e) => {this._changeFile(e)}}/>

这样按钮就隐藏了,而且不占文档流,但是按钮是存在的。

把按钮隐藏了,我们怎么触发它的上传事件呢?

很简单,因为我们使用了一个ref属性,可以去获取到input的DOM对象。我们只需要模拟按钮点击事件即可:

this.$refs.upBInput.click()

我们把这句话包裹一层函数,需要的地方调用即可。

methods: {
  upload() {
    this.$refs.upBInput.click()
  }  
}

我们写好一个漂亮的上传UI界面后,绑定一个click事件为this.upload()就可以触发上传了。

这样效果也达到了,但是还是没有和UI分离,引入的时候也需要引入这个组件。想达到一开始说的效果怎么办呢?


三、抽离上传功能

这就要用到我们Vue中的插件功能了。

另起一个文件,以index.js命名。

// index.js
import Vue from 'vue'
import uploadComponent from './upload-basic.vue'

// 使用Vue构造器去创建一个上传组件的子类
const uploadBasic = Vue.extend(uploadComponent)
// 创建一个div
const createDiv = () => document.createElement("div")

function useUpload(callback) {
  // 创建一个上传组件类的实例化对象,这个uploadVm你可以认为就是上面那个组件
  const uploadVm = new uploadBasic()
  // 挂载目标
  let uploadEl = createDiv()
  // 将实例化对象挂载到uploadEl中
  uploadVm.$mount(uploadEl)
  // 触发上传操作,这个upload()方法就是我们刚刚封装的
  uploadVm.upload()
  // 绑定一个finish事件去通知我们上传完成了
  uploadVm.$on('finish', data => {

    uploadVm.$nextTick(() => {
      // 上传完成后,做销毁工作
      uploadVm.$destroy()
      uploadEl = null
    })
    // 通过callback回调函数将我们需要的内容回调出去,供外部环境使用
    if(callback) callback(data)
  })
}

// 注册这个插件,挂载到prototype上
export default {
  install: function (Vue, options) {
    Vue.prototype.$useUpload = function () {
      // [].splice.call(类数组对象, 0) 这个方法是将一个类数组对象拷贝一份转换成一个Array
      // 通过...解构变成这个函数的参数
      useUpload(...([].splice.call(arguments, 0)))
    }
  }
}

现在我们定义好了一个上传组件的插件,但是我们组件中并没与去emit一个叫finish的事件,所以我们需要回到组件中去写这个。

// upload-basic.vue
// 重构一下这个函数
_changeFile(e) {
    const file = e.target.files[0];
    const reader = new FileReader();
    const self = this
    
    reader.onloadend = function() {
      // 这个this指代的是reader实例
      // result就是一个base64格式的文本
      const result = this.result;
      
      // 当reader实例读取文件完毕后,咱们把这个result和file都emit出去
      self.emit('finish', {
        base64: result,
        file: file
      })
    }
    
    reader.readAsDataURL(file);
  }

现在,我们的组件upload-basic.vue和插件index.js都写好了,将它们放到一个uploadPlugin文件夹中。


四、在main.js中引用

// main.js
import uploadPlugin from './uploadPlugin/index'

Vue.use(uploadPlugin)

接着到需要的页面中:

// 业务1.vue
<template>
  <div>
    <h2 @click="handleClick">点击上传</h2>
    <img src="imgUrl" />
  </div>
</template>
<script>
export default {
 data() {
   return {
     imgUrl: ''
   }
 },
 methods: {
    handleClick() {
      this.$useUpload(data => {
        this.imgUrl = data.base64;
        console.log('文件:', data.file)
      }) 
    }
 },
}
</script>

以上这个例子,当你点击“上传文件”这个h2标签时,就会去调用我们封装好的上传组件,然后放到img中显示,后续要上传到后端也可以。

这样非常方便的,你就可以在Vue组件中任意去调用这个全局的方法去使用上传功能,通过回调函数中的data对象可以拿到上传文件的file和base64。


五、优点

就如我刚开始说的那样。
  • 1.和UI分离,单独使用,保留核心功能,提高了复用性。
  • 2.使用形式为this.$useUpload,十分方便,无需像组件引入那样,便捷性大大提升!


六、后话

  • 1.其实我们常用的element-ui中弹窗,提示等组件都有这种调用的形式,不知道小伙伴们发现没有?(包括其他UI框架
  • 2.它们实现的原理都是通过Vue.extend()构造的,不信你可以去看看它们的源码。
  • 3.我们一起完成的这个上传组件其实功能还十分的简单,小伙伴们可以自行扩展完善。
  • 4.移动端拍照上传,图片会莫名的旋转,不是我们想要的那样,所以后面还需要将角度不正常的图片旋转过来然后给用户预览,不然体验十分差劲。(我已经写好了,嘿嘿。)
原文来自:https://pengpeng.fun/blog/Vue插件开发之拍照上传功能.html

链接: https://fly63.com/article/detial/12293

对于前端开发,整理推荐好用的chrome插件或应用

向web前端开发者整理提供的chrome插件或应用:比如Postman、JSON Viewer、Page Ruler 、ChromeADB 等等

使用原生js开发插件的实现方法

作为前端开发,我们都习惯使用一些开源的插件例如jquery工具库,那么如何使用原生js来开发封装一个自己的插件呢?接下来就看一下怎么去开发一个自己的js插件,先上代码

typeahead.js_jquery input 搜索自动补全jQuery插件

jquery.typeahead.js是一款高级的自动补全jQuery插件。该自动补全插件提供超过50个配置选项和回调方法,用于完成自动补全功能,能够完成绝大部分表单自动补全的需求。

js轮播插件_轮播图js代码插件总汇

这篇文章为大家分享图片轮播插件,最全最简单最通用的 幻灯片轮播插件,pc端和移动端都可完美使用,能满足绝大部分网站的轮播需求。js轮播插件包括Swiper、slick、owl carousel2、jssor/slider 、iSlider 等

ios风格的时间选择插件

在上个项目中,客户希望时间选择插件可以是ios风格的那种,但是找了很久,发现并没有用vue的ios风格时间插件,于是自己便自己造了一个轮子.插件依赖于better-scroll和vue

前端最常用的vscode插件集

在前端开发中,使用Visual Studio Code有哪些你常用的插件?推荐几个自己喜欢的,不带链接,自己搜索安装吧。这些都是比较实用、前端必备的插件集

浏览器插件_常用谷歌浏览器插件推荐

常用谷谷歌浏览器确实没有其它国产软件的内置功能丰富。但是 Google 浏览器的的优点恰恰就体现在拥有超简约的界面,以及支持众多强大好用的扩展程序,用户能够按照自己的喜好去个性化定制浏览器。今天我就给大家介绍几款自己常用的插件。

sublime安装插件

安装Sublime text 2插件很方便,可以直接下载安装包解压缩到Packages目录,也可以安装package control组件,然后直接在线安装

BlockUI详细用法_Jquery中ajax加载提示插件blickUI

BlockUI 插件是用于进行AJAX操作时模拟同步传输时锁定浏览器操作。当它被激活时,它会阻止使用者与页面(或页面的一部分)进行交互,直至它被取消。BlockUI以在DOM中添加元素的方法来实现阻止用户与浏览器交互的外观和行为

vue项目中vscode格式化配置和eslint配置冲突

使用vscode开发vue项目的时候,从远端拉下一个新的项目后,安装完依赖后跑起项目时,发现直接报了一堆语法错误:包括换行、空格、单双引号、分号等各种格式问题

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!