Vue3Pdf预览,缩放拖拽旋转

使用插件:

版本定死了,别的都不行

   "vue-pdf-embed": "^1.1.6",
   "vue3-pdfjs": "^0.1.6",

npm引入

npm install vue-pdf-embed@1.1.6 vue3-pdfjs@0.1.6 

我使用路由传参(pdf预览文件地址):

父组件:

const jump = (item) => {
  // console.log(item.fileUrl);
  router.push({ path: '/eBookPrv', query: { fileUrl: `/api/eBook/getFile/${item.fileUrl}` } });
}

 预览组件:

只需要pdf预览文件地址,其他按我的代码来就好

<template>
  <div class="container">
    <img src="@/assets/svg/fh.svg" @click.prevent="backlist" class="back" />
    <div class="pdf-view-list">
      <div class="item active-item" v-for="(item, index) in state.numPages" :key="item.index" @click="itemindex(index)">
        <div class="pdf-box">
          <vue-pdf-embed :source="pdfUrl" class="vue-pdf-embed" :page="index + 1" />
        </div>
        <div class="page">{{ index + 1 }}</div>
        <div class="mask" :class="{ active: state.numPages === index + 1 }"></div>
      </div>
    </div>
    <div class="pdf-wrap" :ref="refs.wrapper" @wheel.prevent="scaleWheel($event)">
      <div class="box" :ref="refs.box" @mousedown="dragstart($event)">
        <vue-pdf-embed :source="pdfUrl" :style="scaleFun" class="vue-pdf-embed" :page="state.pageNum" />
      </div>
      <div class="zoomin-wrapper">
        <img src="@/assets/svg/bif.svg" @click="rollBtn('enlarge')" />
        <img src="@/assets/svg/small.svg" @click="rollBtn('zoomin')" alt="" />
        <img src="@/assets/svg/fz.svg" @click="rolate" alt="" />
      </div>
    </div>
    <div class="page-tool">
      <div class="page-tool-item">{{ state.pageNum }}/{{ state.numPages }}</div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, onMounted, computed, watch } from "vue";
import VuePdfEmbed from "vue-pdf-embed/dist/vue3-pdf-embed";
import { createLoadingTask } from "vue3-pdfjs";
import { useRouter } from "vue-router";
import { useRoute } from "vue-router";
const router = useRouter();
const route = useRoute();
const pdfUrl = ref("");

const state = reactive({
  pageNum: 1,
  scale: 1,
  numPages: 0,
});
onMounted(() => {
  pdfUrl.value = route.query.fileUrl;
  // console.log(route.query.fileUrl);
  const loadingTask = createLoadingTask(pdfUrl.value);
  loadingTask.promise.then((pdf) => {
    state.numPages = pdf.numPages;
    // console.log(pdf);
  });
});
const itemindex = (i) => {
  state.pageNum = i + 1;
};
const backlist = () => {
  router.push("/eBook");
  // console.log("返回列表");
};
// 实现pdf缩放
const scaleFun = computed(() => {
  return `transform:scale(${scaleData.scale});transition: all 0.3s;`;
});
const refs = {
  wrapper: ref(null), // pdf外层容器
  box: ref(null), // pdf容器,用于拖拽
};
const dragData = reactive({
  x: 0, // 拖拽初始化时的x坐标
  y: 0, // 拖拽初始化时的y坐标
  left: 0, // 拖拽结束时的x偏移量
  top: 0, // 拖拽结束时的y偏移量
  firstX: 0, // 初始x坐标
  firstY: 0, // 初始y坐标
});
const scaleData = reactive({
  scale: 1, // 缩放比例
  scaleNum: 0.1, // 滚轮缩放比例
  scaleMax: 100, // 最大缩放比例
  scaleMin: 0.1, // 最小缩放比例
  scaleBtn: 0.4, // 缩放按钮缩放比例
  rotate: 0, // 旋转角度
});
watch(
  () => state.numPages,
  (v) => {
    // 重置pdf大小和位置
    scaleData.scale = 1;
    scaleData.rotate = 0;
    refs.box.value.style.left = '50%';
    refs.box.value.style.top = '50%';
    boxTransform();
  },
);
// box 容器也要跟着变化
const boxTransform = () => {
  refs.box.value.style.transform = `translate(-50%, -50%) rotate(${scaleData.rotate}deg) scale(${scaleData.scale})`;
};
// 旋转
const rolate = () => {
  scaleData.rotate += 90;
  boxTransform();
};


// 鼠标滚轮缩放
function scaleWheel(e) {
  let dy = -e.deltaY || e.wheelDeltaY;
  if (dy < 0) {
    scaleData.scale -= scaleData.scaleNum;
  } else {
    scaleData.scale += scaleData.scaleNum;
  }
  // 边界判断
  if (scaleData.scale >= scaleData.scaleMax) {
    scaleData.scale = scaleData.scaleMax;
    return;
  }
  if (scaleData.scale <= scaleData.scaleMin) {
    scaleData.scale = scaleData.scaleMin;
    return;
  }
  boxTransform();
  return false;
}
// 点击放大缩小
const rollBtn = (action) => {
  if (action === 'enlarge') {
    scaleData.scale += scaleData.scaleBtn;
  } else {
    scaleData.scale -= scaleData.scaleBtn;
  }
  // 边界判断
  if (scaleData.scale >= scaleData.scaleMax) {
    scaleData.scale = scaleData.scaleMax;
    return;
  }
  if (scaleData.scale <= scaleData.scaleMin) {
    scaleData.scale = scaleData.scaleMin;
    return;
  }
  boxTransform();
};
// 拖拽(box容器拖拽)
function dragstart(e) {
  refs.box.value.style.transition = 'none';
  e.preventDefault(); // 阻止默认事件
  const box = refs.box.value;
  const wrapper = refs.wrapper.value;
  dragData.x = e.pageX - box.offsetLeft;
  dragData.y = e.pageY - box.offsetTop;

  // 添加鼠标移动事件
  document.addEventListener('mousemove', move);
  function move(event) {
    // 计算元素的位置
    dragData.left = event.pageX - dragData.x;
    dragData.top = event.pageY - dragData.y;
    // 边界判断可以在这里添加 ↓

    // 设置元素的位置
    box.style.left = dragData.left + 'px';
    box.style.top = dragData.top + 'px';
  }
  // 添加鼠标抬起事件,鼠标抬起,将事件移除
  document.addEventListener('mouseup', function () {
    document.removeEventListener('mousemove', move);
  });
  // 鼠标离开父级元素,把事件移除
  document.addEventListener('mouseout', function () {
    document.removeEventListener('mousemove', move);
  });
}
</script>

<style lang="scss" scoped>
.container {
  background: #1f1f1f;
  padding: 10px;
  height: calc(100vh - 60px);
  display: flex;
  justify-content: center;
  align-items: flex-start;
  overflow-y: auto;
}

.pdf-preview {
  position: relative;
  height: 100vh;
  padding: 20px 0;
  box-sizing: border-box;
  background-color: e9e9e9;
}

.pdf-wrap {
  margin-left: 10px;
  overflow-y: auto;
  height: calc(100vh - 60px);
  width: 40%;
  position: relative;
  overflow: hidden;

  .box {
    width: 80%;
    height: 100%;
    object-fit: contain;
    user-select: none;
    /* 不可选中,为了拖拽时不让文字高亮 */
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    align-items: center;
    justify-content: center;

    .vue-pdf-embed {
      width: 100%;
    }
  }

  .zoomin-wrapper {
    position: absolute;
    top: 50%;
    right: 20px;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;

    img {
      width: 34px;
      height: 34px;
      cursor: pointer;
      margin: 5px 0;
    }
  }

  .center {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }

  .bottom-left {
    position: absolute;
    bottom: 20px;
    left: 20px;
  }
}

.vue-pdf-embed {
  text-align: center;
  border: 1px solid #e5e5e5;
  margin: 0 auto;
  box-sizing: border-box;
}

.vue-pdf-embed canvas {

  width: 100% !important;
  height: 100% !important;

}

.page-tool {
  position: absolute;
  bottom: 35px;
  padding-left: 15px;
  padding-right: 15px;
  display: flex;
  align-items: center;
  background: rgb(66, 66, 66);
  color: white;
  border-radius: 19px;
  z-index: 100;
  cursor: pointer;
  margin-left: 50%;
  transform: translateX(-50%);
}

.page-tool-item {
  padding: 8px 15px;
  padding-left: 10px;
  cursor: pointer;
}

.pdf-view-list {
  width: 183px;
  height: 100%;
  background-color: #333333;
  overflow-y: scroll;

  // 隐藏滚动条
  &::-webkit-scrollbar {
    display: none;
  }

  .item {
    width: 100%;
    height: 257px;
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    padding: 20px 20px 0 20px;
    cursor: pointer;

    .pdf-box {
      width: 140px;
      height: 203px;
      background: #ffffff;
      border-radius: 4px;
      z-index: 1;

      .vue-pdf-embed {
        width: 100%;
        height: 100%;
      }
    }

    .page {
      font-weight: 600;
      font-size: 12px;
      color: #ffffff;
      line-height: 34px;
      z-index: 1;
    }

    .mask {
      width: 100%;
      height: 100%;
      background-color: transparent;
      position: absolute;
      left: 0;
      top: 0;
      z-index: 0;
    }

    .active {
      background-color: #ffaa46;
      opacity: 0.2;
    }
  }

  .zoomin-wrapper {
    position: absolute;
    top: 50%;
    right: 20px;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;

    img {
      width: 34px;
      height: 34px;
      cursor: pointer;
      margin: 5px 0;
    }
  }
}

.back {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 20px;
  margin: 10px;
  z-index: 100;
}
</style>

引用自:

https://www.cnblogs.com/wx980416/p/17374192.html

Vue3 实现 PDF 文件在线预览功能 - 掘金

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3中,有几种方法可以实现PDF预览。其中一种方法是使用vue3-pdf-app插件。在Vue文件中,你可以引入PDFViewer组件,并设置相应的属性,如页面缩放、宽度、高度、主题和PDF文件的源。你还可以通过监听loaded事件来获取PDF应用程序的实例。以下是一个示例代码: ```html <template> <div> <h1>vue3-pdf-app 参考文档</h1> <ul class="m-list"> <li> <a class="u-file" href="https://www.npmjs.com/package/vue3-pdf-app" target="_blank">vue3-pdf-app</a> </li> </ul> <h2 class="mt30 mb10">PDFViewer 基本使用</h2> <PDFViewer page-scale="page-fit" :width="800" :height="700" theme="dark" :src="PDFSrc" @loaded="onLoaded" /> </div> </template> <script setup lang="ts"> import PDFViewer from './PDFViewer.vue' import { ref } from 'vue' const PDFSrc = ref('https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.3/Markdown.pdf') function onLoaded (pdfApp: any) { console.log('loaded app:', pdfApp) } </script> ``` 另一种方法是使用vue-pdf-embed和pdfjs-dist插件。首先,你需要安装这两个插件的依赖。然后,你可以在Vue文件中使用PDFViewer组件,并设置相应的属性。你还可以通过调用print方法来实现PDF的打印。以下是一个示例代码: ```html <template> <div> <PDFViewer ref="pdf" :src="PDFSrc" /> <div @click="print">打印</div> </div> </template> <script setup> import PDFViewer from 'vue-pdf-embed' import { ref, getCurrentInstance } from 'vue' const PDFSrc = ref('https://example.com/path/to/pdf') function print() { const { proxy } = getCurrentInstance() proxy.$refs\['pdf'\].print() } </script> ``` 这些方法可以帮助你在Vue3中实现PDF预览功能。希望对你有所帮助! #### 引用[.reference_title] - *1* [Vue3PDF预览vue3-pdf-app)](https://blog.csdn.net/Dandrose/article/details/130271456)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Vue3预览并打印PDF的两种方法](https://blog.csdn.net/qing_jian0119/article/details/128739730)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值