Explorar el Código

feat: 添加PDF控制栏组件

ChenYangfan hace 6 años
padre
commit
a62c86b3a0

+ 2 - 1
public/index.html

@@ -6,7 +6,8 @@
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width,initial-scale=1.0">
   <link rel="icon" href="<%= BASE_URL %>favicon.ico">
-  <script src="https://cdn.bootcss.com/pdf.js/2.3.200/pdf.min.js"></script>
+<!--  <script src="https://cdn.bootcss.com/pdf.js/2.3.200/pdf.min.js"></script>-->
+  <script src="https://cdn.jsdelivr.net/npm/pdfjs-dist@2.2.228/build/pdf.min.js"></script>
 <!--  <script src="https://cdn.bootcss.com/pdf.js/2.3.200/pdf.worker.min.js"></script>-->
   <title>SEEC 课堂助手</title>
   <style>

+ 6 - 6
src/App.vue

@@ -16,12 +16,12 @@ export default {
 @import "~@/style/theme.scss";
 @font-face {
   font-family: 'iconfont';  /* project id 1598214 */
-  src: url('//at.alicdn.com/t/font_1598214_te9xe3x57p9.eot');
-  src: url('//at.alicdn.com/t/font_1598214_te9xe3x57p9.eot?#iefix') format('embedded-opentype'),
-  url('//at.alicdn.com/t/font_1598214_te9xe3x57p9.woff2') format('woff2'),
-  url('//at.alicdn.com/t/font_1598214_te9xe3x57p9.woff') format('woff'),
-  url('//at.alicdn.com/t/font_1598214_te9xe3x57p9.ttf') format('truetype'),
-  url('//at.alicdn.com/t/font_1598214_te9xe3x57p9.svg#iconfont') format('svg');
+  src: url('//at.alicdn.com/t/font_1598214_vlz5n1dhzwa.eot');
+  src: url('//at.alicdn.com/t/font_1598214_vlz5n1dhzwa.eot?#iefix') format('embedded-opentype'),
+  url('//at.alicdn.com/t/font_1598214_vlz5n1dhzwa.woff2') format('woff2'),
+  url('//at.alicdn.com/t/font_1598214_vlz5n1dhzwa.woff') format('woff'),
+  url('//at.alicdn.com/t/font_1598214_vlz5n1dhzwa.ttf') format('truetype'),
+  url('//at.alicdn.com/t/font_1598214_vlz5n1dhzwa.svg#iconfont') format('svg');
 }
 
 body {

+ 49 - 0
src/components/Icon.vue

@@ -0,0 +1,49 @@
+<template>
+  <div class="icon"><span>{{unicode}}</span></div>
+</template>
+
+<script>
+export default {
+  props: ['unicode']
+}
+</script>
+
+<style lang="scss" scoped>
+@import '~@/style/theme.scss';
+
+.icon {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: rgba(255, 255, 255, .8);
+  padding: 8px;
+  border-radius: 100px;
+  min-width: 28px;
+  min-height: 28px;
+  width: 28px;
+  height: 28px;
+  user-select: none;
+  cursor: pointer;
+  text-align: center;
+  font-family: 'iconfont', sans-serif;
+  font-size: 0;
+  color: $icon-normal-color;
+  transition: box-shadow 0.25s, all 0.1s;
+
+  & > span {
+    font-size: 24px;
+  }
+
+  &:hover {
+    opacity: 0.8;
+    background: white;
+    box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .1);
+  }
+
+  &:active {
+    color: darken($icon-hover-color, 10);
+    background: white;
+    box-shadow: 0 1px 0 0 rgba(0, 0, 0, .1);
+  }
+}
+</style>

+ 11 - 11
src/components/Pdf.vue → src/components/PDF/Pdf.vue

@@ -6,24 +6,24 @@
 import pdfjs from '@/utils/pdf'
 
 export default {
+  props: ['src', 'page'],
   mounted () {
-    const loadingTask = pdfjs.getDocument('http://seec-helper-pdf.oss-cn-hangzhou.aliyuncs.com/test.pdf?OSSAccessKeyId=LTAI4Fi1qmL4iuhH8t7G7r2H&Expires=1580594656&Signature=RUkriwCKFoRp7DU7kM6BmYI8SCI%3D')
-    loadingTask.promise.then(function (pdf) {
-      pdf.getPage(1).then(function (page) {
+    const canvas = document.getElementById('pdf-canvas')
+    const context = canvas.getContext('2d')
+
+    // Default size
+    canvas.height = 1080
+    canvas.width = 1920
+
+    const loadingTask = pdfjs.getDocument(this.src)
+    loadingTask.promise.then(pdf => {
+      pdf.getPage(this.page ? this.page : 1).then(page => {
         const scale = 2
         const viewport = page.getViewport({ scale: scale })
 
-        //
-        // Prepare canvas using PDF page dimensions
-        //
-        const canvas = document.getElementById('pdf-canvas')
-        const context = canvas.getContext('2d')
         canvas.height = viewport.height
         canvas.width = viewport.width
 
-        //
-        // Render PDF page into canvas context
-        //
         const renderContext = {
           canvasContext: context,
           viewport: viewport

+ 86 - 0
src/components/PDF/PdfController.vue

@@ -0,0 +1,86 @@
+<template>
+  <div class="pdf-controller">
+    <icon :class="pageMarked ? 'active' : ''" @click.native="handleMarkButtonClicked"
+          :unicode="pageMarked ? iconMap['mark'] : iconMap['mark_border']"/>
+    <div class="spacer"></div>
+    <icon @click.native="handlePrevious" :unicode="iconMap['previous']"/>
+    <icon @click.native="handleScreenShot" :unicode="iconMap['screen_shot']"/>
+    <icon @click.native="handleNext" :unicode="iconMap['next']"/>
+    <div class="spacer"></div>
+    <icon :class="showDiscussion ? 'active' : ''" @click.native="handleDiscussionShowState"
+          :unicode="iconMap['discussion']"/>
+  </div>
+</template>
+
+<script>
+import Icon from '@/components/Icon'
+
+const iconMap = {
+  'mark_border': '\ue678',
+  'mark': '\ue677',
+  'screen_shot': '\ue6e5',
+  'next': '\ue7da',
+  'previous': '\ue813',
+  'discussion': '\ue610'
+}
+
+export default {
+  components: { Icon },
+  data () {
+    return {
+      iconMap: iconMap,
+      pageMarked: false,
+      showDiscussion: false
+    }
+  },
+  methods: {
+    handleMarkButtonClicked () {
+      this.pageMarked = !this.pageMarked
+      // todo
+    },
+    handleDiscussionShowState () {
+      this.showDiscussion = !this.showDiscussion
+      this.$emit('change-discussion-show-state', this.showDiscussion)
+    },
+    handlePrevious () {},
+    handleNext () {},
+    handleScreenShot () {}
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '~@/style/theme.scss';
+
+.pdf-controller {
+  padding: 0 12px;
+  box-sizing: border-box;
+  display: flex;
+  margin-top: 8px;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+}
+
+.active {
+  color: $icon-hover-color;
+}
+
+.icon {
+  margin: 0 12px;
+}
+
+.spacer {
+  max-width: 24px;
+  flex: 1;
+}
+
+@media (max-width: 480px) {
+  .icon {
+    margin: 0 8px;
+  }
+  .spacer {
+    max-width: 12px;
+  }
+}
+</style>

+ 28 - 0
src/components/PDF/PdfViewer.vue

@@ -0,0 +1,28 @@
+<template>
+  <div>
+    <pdf :src="src"></pdf>
+    <pdf-controller
+      @change-discussion-show-state="handleChangeDiscussionShowState"
+    ></pdf-controller>
+  </div>
+</template>
+
+<script>
+import Pdf from '@/components/PDF/Pdf'
+import PdfController from '@/components/PDF/PdfController'
+export default {
+  components: { PdfController, Pdf },
+  props: ['src'],
+  methods: {
+    handleChangeDiscussionShowState (state) {
+      this.$emit('change-discussion-show-state', state)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.pdf-controller{
+  position: absolute;
+}
+</style>

+ 2 - 2
src/components/IconButton.vue → src/components/TabIconButton.vue

@@ -1,6 +1,6 @@
 <template>
     <div
-      class="icon-link"
+      class="tab-icon-button"
       :class="active ? 'active' : ''"
     >{{ tab.unicode }}</div>
 </template>
@@ -14,7 +14,7 @@ export default {
 <style lang="scss" scoped>
 @import '~@/style/theme.scss';
 
-.icon-link {
+.tab-icon-button {
   user-select: none;
   cursor: pointer;
   text-align: center;

+ 23 - 33
src/views/reader/PdfReader.vue

@@ -1,58 +1,48 @@
 <template>
   <div class="pdf-reader">
     <div class="pdf-wrapper">
-      <pdf></pdf>
-      <c-button
-        class="discussion-show-hide-button"
-        @click.native="handleDiscussionShowState"
-      >
-        {{showDiscussion ? '隐藏' : '显示'}}讨论区
-      </c-button>
+      <pdf-viewer
+        :src="src"
+        @change-discussion-show-state="handleChangeDiscussionShowState"
+      ></pdf-viewer>
     </div>
     <div
       class="discussion-wrapper"
       v-show="showDiscussion"
     >
       <h1 class="title">本页幻灯片讨论区</h1>
-      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium ad distinctio dolores esse est fugiat
-        maxime minus molestiae nisi odit quas quibusdam, quidem recusandae repudiandae sint sit vitae voluptatibus
-        voluptatum?</p>
+      <p><b>是的减肥还是看见很多风景开始是</b></p>
+      <p>是的减收到发史蒂夫史蒂夫史蒂夫史蒂夫肥还是看见史蒂夫史蒂夫说方式方式很多风景开始是</p>
       <br>
-      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium ad distinctio dolores esse est fugiat
-        maxime minus molestiae nisi odit quas quibusdam, quidem recusandae repudiandae sint sit vitae voluptatibus
-        voluptatum?</p>
+      <p><b>是的减肥还是看见很多风景开始是</b></p>
+      <p>是的减收到发史蒂夫史蒂夫史蒂夫史蒂夫肥还是看见史蒂夫史蒂夫说方式方式很多风景开始是</p>
       <br>
-      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium ad distinctio dolores esse est fugiat
-      maxime minus molestiae nisi odit quas quibusdam, quidem recusandae repudiandae sint sit vitae voluptatibus
-      voluptatum?</p>
+      <p><b>是的减肥还是看见很多风景开始是</b></p>
+      <p>是的减收到发史蒂夫史蒂夫史蒂夫史蒂夫肥还是看见史蒂夫史蒂夫说方式方式很多风景开始是</p>
       <br>
-      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium ad distinctio dolores esse est fugiat
-        maxime minus molestiae nisi odit quas quibusdam, quidem recusandae repudiandae sint sit vitae voluptatibus
-        voluptatum?</p>
-      <br>
-      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium ad distinctio dolores esse est fugiat
-        maxime minus molestiae nisi odit quas quibusdam, quidem recusandae repudiandae sint sit vitae voluptatibus
-        voluptatum?</p>
+      <p><b>是的减肥还是看见很多风景开始是</b></p>
+      <p>是的减收到发史蒂夫史蒂夫史蒂夫史蒂夫肥还是看见史蒂夫史蒂夫说方式方式很多风景开始是</p>
       <br>
     </div>
   </div>
 </template>
 
 <script>
-import Pdf from '@/components/Pdf'
-import CButton from '@/components/CButton'
+import PdfViewer from '@/components/PDF/PdfViewer'
 
 export default {
-  components: { CButton, Pdf },
+  components: { PdfViewer },
   mounted () {},
   data () {
     return {
-      showDiscussion: true
+      src: 'http://seec-helper-pdf.oss-cn-hangzhou.aliyuncs.com/test.pdf?OSSAccessKeyId=LTAI4Fi1qmL4iuhH8t7G7r2H&Expires=1584224806&Signature=hi3UaVAMkKCSERdUYEuTeGGCd%2Bg%3D',
+      showDiscussion: false
     }
   },
   methods: {
-    handleDiscussionShowState () {
-      this.showDiscussion = !this.showDiscussion
+    handleChangeDiscussionShowState (state) {
+      console.log(state)
+      this.showDiscussion = state
     }
   }
 }
@@ -62,7 +52,7 @@ export default {
 .pdf-reader {
   color: #5a6a7a;
   box-sizing: border-box;
-  padding: 0 30px;
+  padding: 0 24px;
   min-height: 100vh;
   display: flex;
   align-items: center;
@@ -72,7 +62,7 @@ export default {
 }
 
 .discussion-wrapper {
-  margin-top: 60px;
+  margin-top: 70px;
   box-sizing: border-box;
   overflow: auto;
   min-width: 350px;
@@ -85,10 +75,10 @@ export default {
     margin-top: unset;
     max-height: 90vh;
     height: calc(15vh + 30vw);
-    max-width: 450px;
+    max-width: 600px;
   }
   .pdf-reader {
-    padding: 5vh 30px;
+    padding: 5vh 24px;
   }
 }
 

+ 7 - 7
src/views/shared/UserHomeLayout.vue

@@ -3,13 +3,13 @@
     <div class="menu-container">
       <div class="tab-container-large">
         <template v-for="tab of tabs">
-          <icon-button
+          <tab-icon-button
             :active="currentRouteName.match(tab.name)"
             :tab="tab"
             :key="tab.unicode"
             @click.native="handleIconButtonClick(tab.name)"
           >
-          </icon-button>
+          </tab-icon-button>
         </template>
       </div>
       <div class="view-container">
@@ -24,23 +24,23 @@
 
     <div class="tab-container-small">
       <template v-for="tab of tabs">
-        <icon-button
+        <tab-icon-button
           :active="currentRouteName.match(tab.name)"
           :tab="tab"
           :key="tab.unicode"
           @click.native="handleIconButtonClick(tab.name)"
         >
-        </icon-button>
+        </tab-icon-button>
       </template>
     </div>
   </div>
 </template>
 
 <script>
-import IconButton from '@/components/IconButton'
+import TabIconButton from '@/components/TabIconButton'
 
 export default {
-  components: { IconButton },
+  components: { TabIconButton },
   props: ['tabs'],
   data () {
     return {
@@ -87,7 +87,7 @@ export default {
     align-items: center;
     justify-content: center;
 
-    .icon-link {
+    .tab-icon-button {
       margin: 16px 0;
     }
   }