Vue 微信开发(三,pdf/图片预览)

1,292 阅读3分钟

1. 新需求又来了,后台上传pdf,手机微信里要能预览

当时觉得,这个东西牵扯到文件的东西都不怎么好做。

<1>后台上传pdf

因为后台系统使用的是elementui,所以直接就使用elementui的上传组件。感觉elementui 的日期插件有点小小的问题,当我绑定好日期格式,在提交的时候获取的值竟然还是没有格式化的日期,然后我就看教程上的代码还有文档上的api,发现可以绑定一个change,既然我使用的是vue,数据也是双向绑定,但是日期框里面的值要监听change才能拿到转换格式以后的值。就感觉多此一举。然后就是按照官网的例子,操作完了,然后提交请求接口了,歪日,报错了,什么不支持的媒体类型,什么406,,什么后台直接返回不支持类型,我想着我请求头也设置的是multipart/form-data,然后我和后台说为啥报500了啊,你看看是不是你们的问题。人家一口否定了我。当时就在想,请求头也设置了,还有什么设置导致会请求失败么,想来想去也只有请求的数据格式有问题了,后是File格式的数据才行。

async submitUpload() {
        let formData = new FormData();
        if (this.fileList.length < 1) {
          this.$message.error("请上传pdf文件")
        } else {
          formData.append("file", this.fileList[0].raw);
          let res = await savehealthRecord(formData);
          console.log("res", res);
          if (res.flag) {
            this.$message.success("上传成功!");
            this.originName = res.originName;
            this.accessUrl = res.accessUrl;
            this.fileList = [];
          }
        }
      }

<2>前端预览(手机微信预览)

因为我们使用了阿里的oss,所以在上传的时候会返给我地址,我提交的时候又把地址存在我们自己的数据库,微信请求的是这个存储地址。所以一开始我们直接window.location="url",这样做会提示跳转到手机的浏览器,而不是在微信中打开,所以就感觉体验不是很好。希望能在微信中直接开一个页面浏览这些文件内容。 所以参考的 github.com/Lushenggang… 这个哥们的内容。但是稍微的变了一下,他是写了一个组件,把url使用父子传值到pdf渲染页面,因为我想使用路由的方式,所以直接放在Vuex里面,然后使用getter反出来在组件中使用。getter的使用是通过计算属性获取。但是我当时没有在vuex把数据本地化,导致刷新页面以后,数据丢失,页面渲染失败。所以把这个url稍微存储几分钟,防止用户刷新渲染失败。

<template>
  <div class="pdf-preview-container">
    <!--<iscroll-view :options="{preventDefault: false}" @scrollStart="scroll" class="scroll-view">-->
    <navbar ref="navbar"></navbar>

        <div
          class="pageContainer"
          ref="container"
          v-for="page in docPages"
          :style="{
        height: `${pageHeight}px`
      }"
          :key="page">
          <canvas v-show="renderList.includes(page)">
          </canvas>
        </div>
    <div class="notice" v-if="show" @click="gotoTop">
      <p>返回顶部</p>
    </div>
    <div class="refreshPage" v-if="isShow" @click="refreshPage">
      <p>重新加载</p>
    </div>
    <!--</iscroll-view>-->
  </div>
</template>

<script>
  import pdfJS from 'pdfjs-dist'
  import BScroll from 'better-scroll';
  import navbar from '../../components/navbar/navbar'

  export default {
    props: {
      // url: {
      //   type: String,
      //   required: true
      // },
      renderPages: {
        type: Number,
        default: 5
      },
      customScroll: {
        type: Boolean,
        default: false
      },
      offsetHeight: {
        type: Number,
        default: 0
      },
    },
    data() {
      return {
        doc: null,
        docPages: 0,
        currentPage: 0,
        scrollWrapHei: 0,
        pageHeight: 0,
        renderList: [],
        show: false,
        isShow:true,
        notice: '',
        timer: 0,
        isDispaly: false,
        totop: false,
        scrollToTop: "",
        url: ""
      }
    },
    watch: {
      url: {
        immediate: true,
        handler() {
          this.getPDFFile()
        }
      },
      $route:{
        immediate: true,
        deep: true,
        handler(val,oldVal) {
          console.log("to",val);
          console.log("oldval",oldVal)
        }
      },

    },
    created() {
      if (!this.customScroll) {
        document.addEventListener('scroll', this.scroll)
      }
    },
    mounted() {
      this.scrollWrapHei = document.documentElement.clientHeight -
        this.$refs.navbar.$el.clientHeight;
      //
      // this.url = this.getFileUrl;
      this.url = this.$cookies.get("fileUrl");
      console.log("url",this.url);
      this.options = {
        scrollY: true,
        scrollX: false,
        mouseWheel: true,
        click: true,
        taps: true
      };
      // let wrapper = document.querySelector('.iscrollWrap');
      // let scroll = new BScroll(wrapper, options);
      //
      // let wrapper = document.querySelector('.scrollWrap');
      // let betterScroll = new BScroll(wrapper, this.options);
      // betterScroll.on("touchend",(pos)=>{
      //   console.log(pos)
      // })
      //解决@click失效,为什么会失效,因为加上better scroll导致失效,解决就是加一个配置参数

      // console.log("this.$refs.navBar", this.$refs.navBar.getBoundingClientRect().height);
    },
    beforeDestroy() {
      document.removeEventListener('scroll', this.scroll)
    },
    methods: {
      getPDFFile () {
        if (!this.url) return;
        this.currentPage = 0;
        pdfJS.getDocument(this.url).then(pdf => {
          this.doc = pdf;
          this.docPages = pdf.numPages;
          this.$nextTick(() => {
            this.docPages && this.scrollToPage(1)
          })
        })
      },
      scrollToPage (pageNo) {
        if (this.currentPage === pageNo) return
        this.currentPage = pageNo
        let list = []
        for (let page = pageNo - this.renderPages; page <= pageNo + this.renderPages; page++) {
          list.push(page)
        }
        list = list.filter(page => page <= this.docPages && page >= 1)
        this.$nextTick(() => {
          this.renderList = list
          this.renderList.forEach(page => {
            this.renderPage(page)
          })
        })
      },
      // 渲染page
      renderPage (pageNo) {
        this.doc.getPage(pageNo).then(page => {
          let container = this.$refs.container[pageNo - 1]
          if (!container) return
          let canvas = container.querySelector('canvas')
          if (!canvas || canvas.__rendered) return
          let ctx = canvas.getContext('2d')
          let dpr = window.devicePixelRatio || 1
          let bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1
          let ratio = dpr / bsr
          let rect = container.getBoundingClientRect()
          let viewport = page.getViewport(1)
          let width = rect.width
          let height = width / viewport.width * viewport.height
          canvas.style.width = `${width}px`
          canvas.style.height = `${height}px`
          this.pageHeight = height
          canvas.height = height * ratio
          canvas.width = width * ratio
          ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
          page.render({
            canvasContext: ctx,
            viewport: page.getViewport(width/viewport.width)
          })
          canvas.__rendered = true
        })
      },
      scroll () {
        this.checkRender(document.documentElement)
      },
      checkRender (el) {
        if (!this.pageHeight) return;
        let scrollTop = el.scrollTop;
        if(scrollTop > 300){
          this.show = true;
          this.isShow = false;

        }else{
          this.show = false;
          this.isShow = true;
        }
        if (el === document.documentElement) {
          scrollTop = el.scrollTop || window.pageYOffset || document.body.scrollTop
        }
        let page = Math.floor((scrollTop - this.offsetHeight) / this.pageHeight)
        page = Math.max(page, 1)
        page = Math.min(page, this.docPages)
        this.scrollToPage(page)
      },
      gotoTop() {
        let scrolltop = document.documentElement.scrollTop || document.body.scrollTop;
        document.documentElement.scrollTop = document.body.scrollTop = 0;
        this.show = false;
        console.log("gotoTOp");
      },
      refreshPage(){
        this.$router.go(0);
      }
    },
    components: {
      navbar
    },
    computed: {
      getFileUrl() {
        return this.$store.getters.getFileUrl
      }
    }
  }
</script>

<style lang="less" scoped>
  .pdf-preview-container {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 999;
    background-color: #fff;
    height: 100%;

    /*.scroll-view {*/
    /*overflow: scroll;*/
    /*position: fixed;*/
    /*top: 0;*/
    /*bottom: 0;*/
    /*left: 0;*/
    /*right: 0;*/
    /*!*height: 600px;*!*/
    /*!*height: 100%;*!*/
    /*-webkit-overflow-scrolling: touch;*/
    /*}*/

    .iscrollWrap {
      overflow: scroll;
    }

    .notice,refreshPage{
      position: fixed;
      width: 2.5rem; /* 40/16 */
      height: 2.5rem;
      border-radius: 1.25rem /* 20/16 */;
      opacity: 0.8;
      background: darkorange;
      box-shadow: 0 1px 5px 0 #e0e0e0;
      right: 1.125rem; /* 18/16 */
      bottom: 5rem; /* 64/16 */
      z-index: 1100;
      -webkit-transition: opacity .5s;
      transition: opacity .5s;
      color: #fff;

      i {
        font-size: 1.5rem;
        color: #e2294c;
        margin: 0 0 0 0.5rem;
        position: relative;
        top: 0.5rem;
      }

      p {
        font-size: 0.65rem;
        text-align: center;
        padding: 0;
      }
    }
  .refreshPage{
    position: fixed;
    width: 2.5rem; /* 40/16 */
    height: 2.5rem;
    border-radius: 1.25rem /* 20/16 */;
    opacity: 0.8;
    background: darkorange;
    box-shadow: 0 1px 5px 0 #e0e0e0;
    right: 1.125rem; /* 18/16 */
    top: 0.5rem; /* 64/16 */
    z-index: 1100;
    -webkit-transition: opacity .5s;
    transition: opacity .5s;
    color: #fff;

    i {
      font-size: 1.5rem;
      color: #e2294c;
      margin: 0 0 0 0.5rem;
      position: relative;
      top: 0.5rem;
    }

    p {
      font-size: 0.65rem;
      text-align: center;
      padding: 0;
    }
  }
  }

  .active {
    display: none;
  }
</style>

<3> 图片上传预览

图片上传的是使用vant的van-uploader组件,不过样式是全新定义,但是这个没有图片预览功能。所以使用了vue-preview,但是这玩意使用完全不是网上说的那样了,现在完全是一个vue组件的形式来使用的了。

3. 到这里这次开发就算完成了,微信端和pc端,感觉自己需要学习的东西还很多