uni-app做APP端选择非媒体文件(.doc,.txt...)上传问题,使用renderjs

693 阅读2分钟

uni.chooseFile在app端是不受支持的,如果想在app端选择非媒体文件就需要用plus api。

image.png

调用原生SDK来实现,这对于我这种前端开发人员来说太难受了,老长一大串子代码看不懂,然后想到js浏览器的方法来选择文件,用input的file属性来做。

uni-app原生的input是不支持file属性的,所以要用html原生input,这里需要用v-html使用,类似使用富文本。

<view v-html="fileIptNode" />

data() {
  return {
    fileIptNode: `<input id="fileIpt" style="display:none" type="file">`,
  }
},

uni-app默认是不支持操作dom的,所以需要用到renderjs来实现,直接上完整代码了。 加一个 script 标签 加两个属性 module="dom" lang="renderjs",renderjs是运行在视图层的所以可以操控Dom,文档可以去uniapp官网查看。

<template>
  <!-- 
      绑定视图层方法要用module属性的值.方法名 
      逻辑层向视图层传值要写一个自定义属性 :prop 名prop是自定义的
      然后绑定视图层的一个方法 我这里绑定的是 onChange 方法名也是自定义的
      要固定这么写 :change:prop="dom.onChange"
  -->
  <view class="content">
    <button 
      @click="dom.doSelectFile" 
      :prop="uploadData" 
      :change:prop="dom.onChange" 
      type="primary" 
      size="mini"
    >
      选择文件
    </button>
    <view v-html="fileIptNode" />
  </view>
</template>

<script>
  export default {
    data() {
      return {
        fileIptNode: `<input id="fileIpt" style="display:none" type="file">`,
        uploadData: { // 传给视图层的数据 接口前缀和token
          baseUrl: "http://xxx.xxx",
          token: uni.getStorageSync("token")
        }
      }
    },
    methods: {
      getIsUpload(val) { // 用于接收视图层传来的数据
        console.log(val);
      }
    }
  }
</script>

<script module="dom" lang="renderjs">
  export default {
    data() {
      return {
        fileIpt: null,
        formData: {}
      }
    },
    mounted() {
      this.fileIpt = document.querySelector("#fileIpt"); // 获取input dom
    },
    methods: {
      onChange(val) {
        this.formData = val; // 接收逻辑层传来的数据
      },
      doSelectFile() {
        this.fileIpt.click(); // 触发input点击事件
        this.fileIpt.onchange = async (e) => { // 绑定 input change 事件
          const file = e.target.files[0]; // 获取选择的文件
          const fmData = new FormData(); // new 一个 FormData 对象并插入file
          fmData.append("file", file);
          try {
            // 使用js原生的fetch调用后端文件上传接口
            const resp = await fetch(this.formData.baseUrl + "/upload", {
              method: "POST",
              body: fmData,
              headers: {
                token: this.formData.token
              }
            });
            const res = await resp.json();
            if (res.code == 200) {
              // 上传成功了使用 this.$ownerInstance.callMethod 方法把结果传回逻辑层
              // 两个参数 第一个是逻辑层方法的名称 第二个是要返回的值
              this.$ownerInstance.callMethod("getIsUpload", res);
            } else {
              // 没成功返回 null
              this.$ownerInstance.callMethod("getIsUpload", null);
            }
          } catch (e) {
            this.$ownerInstance.callMethod("getIsUpload", null);
          }
        }
      }
    },
  }
</script>