PptViewer.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. <template>
  2. <div class="vue_ppt" id="vue_ppt" ref="vuePpt">
  3. <!-- 上下两地址都能用 ——不稳定 -->
  4. <!-- :src="`https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(props?.fileMessage?.url)}`" -->
  5. <!-- <iframe
  6. class="ppt_iframe"
  7. v-else-if="['ppt','pptx'].includes(previewType)"
  8. :src="`https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(props?.fileMessage?.url)}`"
  9. width="100%"
  10. height="100%"
  11. frameborder="0"
  12. ></iframe> -->
  13. <div v-if="pptLoading" class="loading_bg">
  14. <el-icon class="is-loading">
  15. <Loading />
  16. </el-icon>
  17. 加载中
  18. </div>
  19. </div>
  20. </template>
  21. <script setup lang="ts">
  22. import {init} from 'pptx-preview'
  23. import { onMounted, ref,computed} from 'vue'
  24. const props = defineProps({
  25. fileMessage:{
  26. type:{
  27. url:String,
  28. name:String,
  29. }
  30. },
  31. initCourseLearnPage:{
  32. type:Number,
  33. required:false,
  34. default:0
  35. }
  36. })
  37. const emit = defineEmits(['pageChange','fileLoaded'])
  38. const vuePpt = ref()
  39. const pptLoading = ref(false)
  40. const pptxPrviewer = ref()
  41. const timeoutFlag = ref()
  42. const pageTotalHeight = ref()
  43. const currentReadHeight = ref()
  44. const progressPercent = computed(()=>{
  45. if(currentReadHeight.value == 0 || pageTotalHeight.value == 0){
  46. return 0
  47. }
  48. return Math.round((currentReadHeight.value / pageTotalHeight.value) * 100)
  49. })
  50. // 防抖
  51. // 不再连续滚动的时候,记录最后一次滚动的位置,
  52. // 200毫秒内没有再次滚动,就认为用户停止了滚动,此时记录用户的阅读进度
  53. const HandleScroll = (e)=>{
  54. console.log('页面监听滚动',e)
  55. if(timeoutFlag.value){
  56. clearTimeout(timeoutFlag.value)
  57. }
  58. timeoutFlag.value = setTimeout(() => {
  59. let totalHeight = e.target.scrollHeight //总高度
  60. let scrollTop = e.target.scrollTop //滚动高度
  61. let pageHeight = e.target.clientHeight // 客户端高度
  62. // 用户阅读进度 = ( pageHeight + scrollTop ) / totalHeight
  63. console.log('滚动事件',e)
  64. console.log('滚动高度',scrollTop)
  65. console.log('总高度',totalHeight)
  66. console.log('客户端高度',pageHeight)
  67. pageTotalHeight.value = Math.floor(Number(totalHeight)) || 0
  68. currentReadHeight.value = Math.floor( Number(pageHeight) + Number(scrollTop) ) || 0
  69. emit('pageChange',{currentProcess:progressPercent.value})
  70. clearTimeout(timeoutFlag.value)
  71. timeoutFlag.value = null
  72. }, 200);
  73. }
  74. const HandlePageRedirect = (dom)=>{
  75. console.log('滚动dom',dom)
  76. console.log('当前滚动进度--',props.initCourseLearnPage)
  77. // props.initCourseLearnPage
  78. // 根据百分比 换算滚动高度
  79. let totalHeight = dom.scrollHeight //总高度
  80. let pageHeight = dom.clientHeight // 客户端高度
  81. let realScroll = props.initCourseLearnPage * 0.01 * totalHeight - pageHeight
  82. let scrollTop = realScroll > 0 ? realScroll : 0
  83. console.log('高度 pageHeight / totalHeight',pageHeight,totalHeight)
  84. console.log('触发滚动了',scrollTop)
  85. dom.scrollTo({
  86. top: scrollTop,
  87. left: 0,
  88. behavior: 'smooth'
  89. });
  90. pageTotalHeight.value = Math.floor(Number(totalHeight)) || 0
  91. // 用户阅读进度 = ( pageHeight + scrollTop ) / totalHeight
  92. currentReadHeight.value = Math.floor( Number(pageHeight) + Number(scrollTop) ) || 0
  93. emit('pageChange',{currentProcess:progressPercent.value})
  94. }
  95. const HandlePptPreview =()=>{
  96. pptLoading.value = true
  97. //调用库的init方法生成一个预览器
  98. pptxPrviewer.value = init(vuePpt.value, {
  99. width: (vuePpt.value?.clientWidth * 0.8),
  100. // height: 540
  101. })
  102. //获取文件或者读取文件,获取文件的 ArrayBuffer格式数据,传给组件进行预览
  103. fetch(props?.fileMessage?.url).then(response=>{
  104. return response.arrayBuffer()
  105. }).then(res =>{
  106. console.log('获取文件完成',res)
  107. // 在这里监听文档的滚动
  108. let pptDom = document.querySelectorAll('.vue_ppt')
  109. console.log('dom',pptDom)
  110. //调用预览器的preview方法
  111. pptxPrviewer.value.preview(res).then(previewRes=>{
  112. console.log('转换结果',previewRes)
  113. HandlePageRedirect(pptDom[0])
  114. pptLoading.value = false
  115. emit('fileLoaded')
  116. }).catch(err=>{
  117. // 解析失败
  118. pptLoading.value = false
  119. })
  120. pptDom[0]?.addEventListener('scroll',
  121. (e)=>{
  122. HandleScroll(e)
  123. },false)
  124. }).catch(err=>{
  125. // 获取文件失败
  126. pptLoading.value = false
  127. })
  128. }
  129. onMounted(()=>{
  130. console.log('加载中')
  131. HandlePptPreview()
  132. })
  133. </script>
  134. <style lang="scss" scoped>
  135. .vue_ppt{
  136. display: flex;
  137. position: relative;
  138. flex-direction: column;
  139. align-items: center;
  140. justify-content: flex-start;
  141. min-height: 100%;
  142. overflow: auto;
  143. background-color: #e8eaee;
  144. .loading_bg{
  145. width: 100%;
  146. flex: 1 1;
  147. display: flex;
  148. justify-content: center;
  149. align-items: center;
  150. gap:3px;
  151. color:#2e64fa;
  152. }
  153. }
  154. </style>
  155. <style lang="scss">
  156. .vue_ppt{
  157. .pptx-preview-wrapper{
  158. height: auto !important;
  159. width: 80% !important; //主体宽度
  160. }
  161. }
  162. </style>