收藏
回答

IOS下小程序 webview 内嵌H5页面,使用input file拍照确认后页面会刷新

框架类型 问题类型 操作系统 操作系统版本 手机型号 微信版本
小程序 Bug iOS IOS14.4 iphone 11XR 8.0.5

IOS下,小程序 webview 内嵌H5页面,使用input file拍照确认后页面会刷新 , 并且获取不到刚才拍摄的照片,请问这是怎么回事?

<template>
  <div class="wrapper">
    <div class="picture">
      <scroller lock-y scrollbar-x>
        <div class="scroll-wrapper" :style="{width:( imgList.length * 75 )+'px'}">
          <div class="cuspic"  v-for="(item,index) of imgList" :key="index">
            <img :src="item" @click="show(index)"/>
<!--            <span @click="del(index)" class="badge">
              <span class="del-icon"></span>
            </span>-->
            <span class="del-icon" @click="del(index)" ></span>
          </div>
        </div>
      </scroller>

      <div class="up-wrapper">
        <div class="file-icon" v-show="imgList.length<max">
          <img @click="clickFile" src="../../../common/assets/icon/apply/Group 70@3x.png"/>
          <input ref="fileinput"
                 type="file"
                 accept="image/*"
                 capture="camera"
                 fieldName="file"
                 multiple="multiple"
                 @change="selectFiles"
                 class="fileinput"
          />
        </div>
        <div class="pic-hint">
          <div class="max-message">上传检查报告或患处照片(最多9张)</div>
          <div class="g-pic">照片仅自己和医生可见</div>
        </div>
      </div>
    </div>
    <div>
      <loading :show="loadingShow" text="上传中"></loading>
    </div>
    <!--------图片预览-------start-->
    <div v-transfer-dom>
      <previewer :list="previewList" ref="previewer" :options="options">
        <template slot="button-before">

        </template>
      </previewer>
    </div>
    <!-------图片预览-------end-->
  </div>
</template>

<script type="text/ecmascript-6">
  import {Badge, Loading, TransferDomDirective as TransferDom, Previewer,Grid, GridItem,Scroller  } from 'vux'
  import {uploadFile} from '@network/Api'
  import {mapState,mapMutations} from 'vuex'


  export default {
    name: 'imageUpload',
    directives: {
      TransferDom
    },
    components: {
      Badge, Loading, Previewer,Grid, GridItem,Scroller
    },
    props: {
      multiple: {
        type: Boolean,
        default: true,
      },
      value: {
        type: [Boolean, String, Number, Array],
        default: false
      },
      max: {
        type: [Boolean, String, Number, Array],
        default: 9
      }
    },
    data() {
      return {
        files: null,
        imgList: [],
        imgListBig: [],
        formData: null,
        fileUrl: [],
        loadingShow: false,
        options: {
          getThumbBoundsFn(index) {
            // find thumbnail element
            let thumbnail = document.querySelectorAll('.cuspic')[index]
            // get window scroll Y
            let pageYScroll = window.pageYOffset || document.documentElement.scrollTop
            // optionally get horizontal scroll
            // get position of element relative to viewport
            let rect = thumbnail.getBoundingClientRect()
            // w = width
            return {x: rect.left, y: rect.top + pageYScroll, w: rect.width}
            // Good guide on how to get element coordinates:
            // http://javascript.info/tutorial/coordinates
          },
          isClickableElement: function (el) {
            return /previewer-delete-icon/.test(el.className)
          },
          tapToToggleControls: false,
        },
        directives: {
          TransferDom
        },
      }
    },
    watch: {
      imgList(val) {
        this.$emit('input', val)
      },
      bigPictureUrls(){
        this.imgListBig = this.bigPictureUrls
      }
    },
    computed:{
      ...mapState({
        bigPictureUrls: state => state.bigPictureUrls
      }),
      previewList(){
        let array = [];
        this.imgListBig.map((item, index) => {
          array.push({
            src: item
          })
        })
        console.log('array---缓存大图',array)
        return array
      }
    },
    methods: {
      ...mapMutations(['saveBigPictureUrl']),
      //压缩图片
      compressImage(src) {
        return new Promise(function (resolve, reject) {

          let _this = this, imgType
          let img = new Image()
          if (src) {
            imgType = src.split(';')[0]
            if (imgType) {
              imgType = imgType.split(':')[1]
            }
          }
          img.src = src
          img.onload = function () {
            //计算符合目标尺寸宽高值,若上传图片的宽高都大于目标图,对目标图等比压缩;如果有一边小于,对上传图片等比放大。
            let goalWidth = 1080,     //目标宽度
              goalHeight = 1080,  //目标高度
              imgWidth = img.naturalWidth,  //图片宽度
              imgHeight = img.naturalHeight, //图片高度
              tempWidth = imgWidth,   //放大或缩小后的临时宽度
              tempHeight = imgHeight,   //放大或缩小后的临时宽度
              r = imgWidth / imgHeight,      //压缩比
              quality = 0.5   //图片压缩质量

            // 宽高均 <= 1080,图片尺寸大小保持不变
            if (imgWidth < goalWidth && imgHeight < goalHeight) {
            }
            // 宽高均 > 1080 && 宽高比 > 2,
            else if (imgWidth > goalHeight && imgWidth > goalHeight) {
              // 宽大于高 取较小值(高)等于1080,较大值等比例压缩
              if (r > 1) {
                tempHeight = goalHeight
                tempWidth = goalHeight * r
              }
              // 高大于宽 取较小值(宽)等于1080,较大值等比例压缩 (宽高比在0.5到2之间 )
              else {
                tempHeight = goalWidth / r
                tempWidth = goalWidth
              }
            }
            // 宽或高 > 1080
            else {
              // 宽图 图片尺寸大小保持不变
              if (r > 2) {
                tempWidth = imgWidth
                tempHeight = imgHeight
              }
              // 长图 图片尺寸大小保持不变
              else if (r < 0.5) {
                tempWidth = imgWidth
                tempHeight = imgHeight
              }
              // 宽大于高 取较大值(宽)等于1080,较小值等比例压缩
              else if (r > 1) {
                tempWidth = goalWidth
                tempHeight = goalWidth / r
              }
              // 高大于宽 取较大值(高)等于1080,较小值等比例压缩
              else {
                tempHeight = goalHeight
                tempWidth = goalHeight * r
              }
            }

            let canvas = document.createElement('canvas')
            let ctx = canvas.getContext('2d')
            canvas.width = tempWidth
            canvas.height = tempHeight
            ctx.drawImage(img, 0, 0, tempWidth, tempHeight)
            // let base64 = canvas.toDataURL(imgType || 'image/jpeg', quality)
            canvas.toBlob(function (blob) {
              resolve(blob)
            }, imgType || 'image/jpeg')
          }
        })
      },
      compressImageWithFiles(files) {

        let fileProms = [];

        for (let file of files) {

          let fp = new Promise((resolve, reject) => {
            let vueInst = this;
            let reader = new FileReader()
            reader.onload = function (e) {
              let pro = vueInst.compressImage(e.target.result);
              resolve(pro)
            }
            reader.readAsDataURL(file);
          })

          fileProms.push(fp);
        }

        return Promise.all(fileProms)
      },

      async selectFiles(e) {
        const maxCount = this.max
        const files = e.target.files
        if (!files.length) {
          return
        }
        console.log('------image size------',files[0].size)
        let count = this.imgList.length + files.length
        if (count > maxCount) {
          this.$alert.error({
            content: `最多上传${maxCount}张`, confirmText: '好的', onConfirm() {
            }
          })

          return
        }
        let filesFilter = await this.converImgList(files);
        if (filesFilter == null || filesFilter.length == 0) {
          return
        }
        filesFilter = await this.compressImageWithFiles(filesFilter);
        this.formData = new FormData()
        if (this.multiple) {
          for (let i = 0; i < filesFilter.length; i += 1) {
            this.formData.append('file', filesFilter[i])
          }
          this.formData.append('userid', shareInst.store.state.user.uid)
          this.formData.append('ext', '80')
          this.formData.append('module', 1)
        } else {
          this.file = filesFilter[0]
          this.formData.append('userid', shareInst.store.state.user.uid)
          this.formData.append('file', this.file)
          this.formData.append('ext', '80')
          this.formData.append('module', 1)
        }
        this.upload()
        let ele = document.querySelector('.scroll-wrapper')
        if(this.imgList.length >=4){
          console.log('this.imgList.length------ ',this.imgList.length )
          ele.style.transform =`translate(${-90 * (this.imgList.length - 4) }px,0px)`
        }
      },
      async converImgList(files) {
        let maxSize = '10MB';
        let allowed = [".jpg", ".gif", ".png", ".jpeg"];
        let _this = this;
        let errFile = []
        for (let i = 0; i < files.length; i++) {
          let file = files[i]
          if (!this.checkType(file, allowed)) {
            errFile.push({
              index: i,
              lable: file.name,
              type: 'type'
            })
            continue
          }
          if (!this.limitFileSize(file, maxSize)) {
            errFile.push({
              index: i,
              lable: file.name,
              type: 'size'
            })
            continue
          }
          /* let reader = new FileReader();
           reader.readAsDataURL(file);
           reader.onload = function (e) {
           _this.imgList.push(this.result)
           }*/
        }
        if (errFile.length) {
          let sizeErr = ''
          let typeErr = ''
          let errIndex = []
          errFile.map(item => {
            if (item.type == 'size') {
              sizeErr += item.lable + ' | '
            }
            if (item.type == 'type') {
              typeErr += item.lable + '| '
            }
            errIndex.push(item.index)
          })
          let content = '';
          if (sizeErr) {
            sizeErr = sizeErr.substring(0, sizeErr.length - 2)
            content += `单文件大小超出[${maxSize}]:${sizeErr}`;
          }
          if (typeErr) {
            sizeErr = typeErr.substring(0, typeErr.length - 2)
            content += `类型只允许[${allowed}]:${typeErr}`;
          }
          this.$alert.error({
            content: `${content},请重新上传`, confirmText: '好的', onConfirm() {
            }
          })
          this.$refs.fileinput.value = ''
          return null
        }
        return files;
      },
      upload() {
        // this.loadingShow = true;
        uploadFile(this.formData).then((res) => {
          if (res && res.length) {
            res.map(item => {
              let str1 = this.insertStr(item.filepath, item.filepath.lastIndexOf('/'), '/thumb')
              let str2 = this.insertStr(str1, str1.lastIndexOf('_'), '_thumb')
              this.imgList.push(str2)
              console.log('str2---',str2)
              this.imgListBig.push(item.filepath)
              this.$store.commit('saveBigPictureUrl', this.imgListBig)
              console.log(' this.imgListBig-----', this.imgListBig)
            })
          }
          // this.loadingShow = false;
        }).catch((e) => {

        })

        this.$refs.fileinput.value = ''
      },
      // DataURL转Blob对象
      dataURLToBlob(dataurl) {
        var arr = dataurl.split(',');
        var mime = arr[0].match(/:(.*?);/)[1];
        var bstr = atob(arr[1]);
        var n = bstr.length;
        var u8arr = new Uint8Array(n);
        while (n--) {
          u8arr[n] = bstr.charCodeAt(n);
        }
        return new Blob([u8arr], {type: mime});
      },
      clickFile() {
        this.$refs.fileinput.click()
      },
      limitFileSize(file, limitSize) {
        var arr = ["KB", "MB", "GB"]
        var limit = limitSize.toUpperCase();
        var limitNum = 0;
        for (var i = 0; i < arr.length; i++) {
          var leval = limit.indexOf(arr[i]);
          if (leval > -1) {
            limitNum = parseInt(limit.substr(0, leval)) * Math.pow(1024, (i + 1))
            break
          }
        }
        if (file.size > limitNum) {
          return false
        }
        return true
      },
      insertStr(soure, start, newStr) {
        return soure.slice(0, start) + newStr + soure.slice(start);
      },
      checkType(file, allowed) {
        const fileName = file.name;
        const seat = fileName.lastIndexOf(".");
        const extension = fileName.substring(seat).toLowerCase();
        return this.contains(allowed, extension)
      },
      contains(arr, obj) {
        let i = arr.length;
        while (i--) {
          if (arr[i] == obj) {
            return true;
          }
        }
        return false;
      },
      del(index) {
        this.imgList.splice(index, 1);
        this.imgListBig.splice(index, 1);
      },
      show(index) {
        this.$refs.previewer.show(index)
      },
    },
    created() {
      this.imgList = this.value
      this.imgListBig = this.bigPictureUrls
    },
  }
</script>

<style lang="scss" type="text/scss" scoped>
  .wrapper {
    width: 100%;
    overflow: hidden;
    .scroll-wrapper{
      overflow: auto;
    }
    .picture {
      width: auto;
      .cuspic {
        display: inline-block;
        margin-right: 15px;
        margin-top: 10px;
        position: relative;
        .del-icon{
          position: absolute;
          right: -8px;
          top: -8px;
          display: inline-block;
          width: 20px;
          height: 20px;
          background-size:100% 100%;
          background-position:center ;
          background-image: url("../../../common/assets/icon/apply/del@3x.png");
        }
      }

      .file-icon {
        position: relative;
        display: inline-block;
        margin-right: 10px;
        input {
          position: absolute;
          left: 0;
          top: 24px;
          opacity: 0;
        }
      }
      img {
        width: 60px;
        height: 60px;
        /*   margin-right: 9px;*/
        margin-left: 0px;
     /*   margin-top: 5px;*/
        border-radius: 3px;
        object-fit:cover;
      }
    }
    /deep/ .weui-grids:before {
      height: 0px;
      border-top: none;
    }
    /deep/ .weui-grid:after {
      height: 0px;
      border-bottom: none;
    }
    .pic-hint{
      height: 60px;
      display: inline-flex;
      justify-content: center;
      flex-direction: column;
      align-content: center;
      vertical-align: middle;
    }
    .g-pic{
      color: $subtitle-color;
    }
    .max-message{

    }
    .up-wrapper{
      display: flex;
      justify-content: flex-start;
      align-content: center;
      margin-top: 10px;
    }
    /deep/ .weui-grid{
      padding: 10px;
    }
  }
</style>

回答关注问题邀请回答
收藏

9 个回答

  • 然后,向着明天
    然后,向着明天
    2021-08-24

    这个问题其实是原生input的锅,直接在浏览器里或者微信环境打开,有的IOS也有同样问题,把IOS所有的后台进程都杀掉,大概率可以正常拍照,原生input type = file,打开相机和选择照片的时候,在IOS上消耗的内存非常多,内存不足的时候就会自动释放从而导致刷新

    2021-08-24
    有用 5
    回复 3
    • lRl啊
      lRl啊
      2022-09-27
      你好,这个bug有没有什么好的解决办法呢
      2022-09-27
      回复
    • 然后,向着明天
      然后,向着明天
      2022-11-09回复lRl啊
      只能把拍照的相关功能迁移至小程序页面实现
      2022-11-09
      回复
    • Joeshu
      Joeshu
      2023-08-02
      到今天了,还是这个样子,唉
      2023-08-02
      回复
  • 元
    2022-09-05

    ios后台较多的时候,还是会出现这个问题

    2022-09-05
    有用 3
    回复
  • 大菜牙铝式
    大菜牙铝式
    2022-10-01

    一样的问题,蹲一个回复。

    iphone12 ios15.1 微信8.0.29


    2022-10-01
    有用 1
    回复
  • 🤡
    🤡
    2021-09-17

    蹲一个回复 遇到相同的问题

    2021-09-17
    有用 1
    回复
  • Ro  td
    Ro td
    2021-05-28

    部分机型有问题,部分木得问题,硁硁坑坑

    2021-05-28
    有用 1
    回复
  • Mxf
    Mxf
    04-15

    24 年了,问题依旧存在,没人管吗?

    04-15
    有用
    回复
  • 。
    2023-09-01

    请问你们解决了吗?

    2023-09-01
    有用
    回复
  • Incredible
    Incredible
    2022-08-24

    一样的问题,蹲一个回复。

    iphone12 ios15.6 微信8.0.26

    2022-08-24
    有用
    回复
  • Cjiang
    Cjiang
    2021-05-06

    你好,Android 正常吗?

    2021-05-06
    有用
    回复 9
    • lin
      lin
      2021-05-07
      安卓是正常的, 但是有部分手机(比如小米09pro)存在拍照上传后图片旋转的问题,我尝试过使用exif-js去获取图片的方向, 但是获取不到
      2021-05-07
      回复
    • Cjiang
      Cjiang
      2021-05-08回复lin
      你好,麻烦提供出现问题的具体机型、微信版本号、系统版本号,以及能复现问题的代码片段(https://developers.weixin.qq.com/miniprogram/dev/devtools/minicode.html
      2021-05-08
      回复
    • lin
      lin
      2021-05-11回复Cjiang
      出现问题的具体机型、微信版本号、系统版本号这些信息, 我在问题上面不是写的一清二楚吗? 代码片段也贴在上面了啊
      2021-05-11
      回复
    • Ro  td
      Ro td
      2021-05-28回复lin
      请问,你解决了没,我也遇到了,坑啊
      2021-05-28
      回复
    • 正年
      正年
      2021-07-02回复lin
      请问问题解决了吗
      2021-07-02
      回复
    查看更多(4)
登录 后发表内容