Skip to content
On this page

uni-app 使用webview上传文件:七牛云版本

简介

因为小程序和uni-app框架对于文件上传的限制,所以在实际开发中,官方提供的api无法满足我们的上传需求,所以需用通过webview来实现对特定文件的上传

本文介绍的方式是在webview链接的网页里直接通过七牛的JSSDK直接将文件上传的七牛云中,然后把获取的key和hash值传递会小程序或者app中

因为uni-app框架的限制,导致在下载文件的时候存储的路径用户难以寻找,所以本文展示的代码里也会包含文件下载功能

webview链接的页面

请添加图片描述

项目结构

在这里插入图片描述

javascript
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title></title>
  </head>

  <body>
    <div class="box">
      <div class="upload" id="upload">
        <input type="file" id="f" />
        <div class="file_info">
          <div class="file_box" id="file_box">
            <!-- <div class="error">未选择文件</div> -->
            <!-- <div class="error">文件大小超过限制</div> -->
            <!-- <div class="error">文件类型错误</div> -->
            <!-- <div>
                       <div>文件名:jkdaljsfklaj.mp3</div>
                       <div>文件大小:1M</div>
                   </div> -->
          </div>
        </div>
        <div class="btn_box">
          <div class="btn" id="btn">选择文件</div>
        </div>
        <div class="mes">(文件大小不能超过5M)</div>
        <div
          style="
            font-size: 14px;
            text-align: center;
            color: #999;
            padding-top: 10px;
          "
        >
          <span>上传进度:</span>
          <span id="percent">未选择文件上传</span>
        </div>
      </div>
      <div class="download" id="download">
        <div style="display: flex; justify-content: center">
          <img
            src="/images/logo.png"
            alt=""
            style="width: 80px; height: 80px"
          />
        </div>
        <div
          style="
            font-size: 15px;
            color: #2dc4b5;
            text-align: center;
            margin: 10px 0px;
          "
        >
          英才云
        </div>
        <div
          style="
            text-align: center;
            font-size: 16px;
            margin-top: 20px;
            font-weight: bold;
            color: rgb(102, 102, 102);
          "
        >
          互联网灵活用工云平台
        </div>
        <div
          style="
            text-align: center;
            font-size: 12px;
            margin-top: 20px;
            color: rgb(154, 154, 154);
          "
        >
          (点击下载后,请自行返回聊天页面)
        </div>
      </div>
    </div>
  </body>
</html>

<script type="text/javascript" src="./utils/jweixin.js"></script>
<script type="text/javascript" src="./utils/uni-webview.js"></script>
<script type="text/javascript" src="./utils/axios.js"></script>
<script type="text/javascript" src="./utils/qiniu.min.js"></script>
<script type="text/javascript">
  let maxSize = 5 * 1024 * 1024;
  window.onload = () => {
    var downloadUrl = decodeURI(getUrlParam("downloadUrl"));
    var uploadDOM = document.getElementById("upload");
    var downloadDOM = document.getElementById("download");
    if (downloadUrl && downloadUrl != "null") {
      uploadDOM.style.display = "none";
      downloadDOM.style.display = "block";
      download(downloadUrl);
      return;
    }
    uploadDOM.style.display = "block";
    downloadDOM.style.display = "none";
    var accessToken = getUrlParam("accessToken");
    var domain = getUrlParam("domain");
    let percentDom = document.getElementById("percent");
    document.addEventListener("UniAppJSBridgeReady", function () {
      //   console.log("uni准备就绪");
      //   alert("uni准备就绪");
      // uni.postMessage({
      //     data: {
      //         action: 'postMessage'
      //     }
      // });
    });
    // 添加节点
    var box = document.getElementById("file_box");
    box.innerHTML = '<div class="error">未选择文件</div>';

    // input节点
    var f = document.getElementById("f");

    // 监听按钮点击
    var btn = document.getElementById("btn");
    btn.addEventListener("click", () => {
      f.click();
    });

    f.onchange = () => {
      let file = f.files[0];
      console.log(f.files[0]);
      if (file.size > maxSize) {
        box.innerHTML = '<div class="error">文件大小超过限制</div>';
        alert("不能上传大于5M的文件");
        return;
      }

      let size = (file.size / 1024 / 1024).toFixed(2);
      let name = file.name;
      let type = fileType(file.name);
      console.log("type", type);
      box.innerHTML = `<div>
                       <div>文件名:${name}</div>
                       <div>文件大小:${size}M</div>
                   </div> `;
      let observable = qiniu.upload(file, name, accessToken);
      var subscription = observable.subscribe({
        // 上传开始
        next: (result) => {
          // 接收上传进度信息,result是带有total字段的 Object
          // loaded: 已上传大小; size: 上传总信息; percent: 当前上传进度
          console.log(result); // 形如:{total: {loaded: 1671168, size: 2249260, percent: 74.29856930723882}}
          let percent = result.total.percent.toFixed(0);
          percentDom.innerHTML = percent;
        },
        error: (errResult) => {
          box.innerHTML = '<div class="error">文件上传失败,请稍后再试</div>';
          // 上传错误后失败报错
          // console.log(errResult);
        },
        complete: (result) => {
          result.url = domain + "/" + result.key;
          result.type = type;
          result.name = name;
          // 接收成功后返回的信息
          // console.log(result); // 形如:{hash: "Fp5_DtYW4gHiPEBiXIjVsZ1TtmPc", key: "%TStC006TEyVY5lLIBt7Eg.jpg"}
          // alert(`上传成功: ${JSON.stringify(result)}`);
          uni.postMessage({
            data: {
              action: JSON.stringify(result),
            },
          });
          setTimeout(() => {
            uni.navigateBack();
          }, 500);
        },
      });
    };
  };
  // 获取小程序传递过来的参数
  function getUrlParam(name) {
    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
    var r = window.location.search.substr(1).match(reg);
    if (r != null) return unescape(r[2]);
    return null;
  }
  // 判断文件类型
  function fileType(filePath) {
    //获取最后一个.的位置
    var index = filePath.lastIndexOf(".");
    //获取后缀
    var ext = filePath.substr(index + 1);

    //判断是否是视频类型
    if (
      ["mp4", "avi", "mov", "rmvb", "rm", "flv", "3gp"].indexOf(
        ext.toLowerCase()
      ) != -1
    ) {
      return "video";
    }
    //判断是否是图片类型
    if (
      [
        "png",
        "jpg",
        "jpeg",
        "bmp",
        "gif",
        "webp",
        "psd",
        "svg",
        "tiff",
      ].indexOf(ext.toLowerCase()) != -1
    ) {
      return "image";
    }
    //判断是否是音频类型
    if (
      ["cda", "wav", "mp3", "wmv", "flac", "aac"].indexOf(ext.toLowerCase()) !=
      -1
    ) {
      return "audio";
    }
    if (
      ["doc", "xls", "ppt", "pdf", "docx", "xlsx", "pptx"].indexOf(
        ext.toLowerCase()
      ) != -1
    ) {
      return "document";
    }
    return "otherType";
  }

  // 下载文件
  function download(downloadUrl) {
    let link = document.createElement("a"); // 创建a标签
    link.style.display = "none";
    link.href = downloadUrl + "?response-content-type=application/octet-stream"; // 设置下载地址
    link.setAttribute("download", ""); // 添加downLoad属性
    document.body.appendChild(link);
    link.click();
  }
</script>

uni-app项目中的webview 页面

在这里插入图片描述

代码功能介绍

1、参数传递:在该页面中,需要传递webview链接的网页中所需要的参数:七牛云授权token,七牛云的上传地址,以及页面类型(是上传文件还是下载文件,下载文件时还需要传递要下载文件的链接地址)

2、数据处理:在该页面中需要处理webview链接页面传递回来的数据,通过@message="handleMessage" 绑定处理函数 ,在绑定的函数中可以获取到传递回来的数据,是字符串形式的

javascript
<template>
	<web-view :src="url" @message="handleMessage"></web-view>
</template>

<script>
	import {
		mapState
	} from "vuex"
	import {
		uploadUrl
	} from "@/common/constant.js"
	export default {
		data() {
			return {
				url: ""
			}
		},
		computed: {
			...mapState('thirdParty', ['qiniuData'])
		},
		onLoad(options) {
			this.url = uploadUrl
			if (options.downloadUrl) {
				let url = `${this.url}?downloadUrl=${options.downloadUrl}`
				this.url = encodeURI(encodeURI(url))
			} else {
				this.url = `${this.url}?accessToken=${this.qiniuData.accessToken}&domain=${this.qiniuData.domain}`
			}

		},
		methods: {
			handleMessage(evt) {
				console.log('接收到的消息:' + JSON.stringify(evt.detail.data));
				uni.setStorageSync('uploadFile', evt.detail.data)
			},
		}
	}
</script>

<style>
</style>