소스 검색

refactor: 为pdf阅读器、消息组件引入vuex,重写pdf阅读器控制栏逻辑

ChenYangfan 6 년 전
부모
커밋
15799e6f10

+ 1 - 1
package.json

@@ -23,7 +23,7 @@
     "@vue/cli-plugin-pwa": "^4.1.0",
     "@vue/cli-plugin-router": "^4.1.0",
     "@vue/cli-plugin-unit-jest": "^4.1.0",
-    "@vue/cli-plugin-vuex": "^4.1.0",
+    "@vue/cli-plugin-vuex": "^4.1.2",
     "@vue/cli-service": "^4.1.0",
     "@vue/eslint-config-standard": "^4.0.0",
     "@vue/test-utils": "1.0.0-beta.29",

+ 21 - 8
src/components/PDF/Pdf.vue

@@ -5,9 +5,10 @@
 <script>
 import pdfjs from '@/utils/pdf'
 import downloadFile from '@/utils/download-base64'
+import { mapState } from 'vuex'
+import { SET_TOTAL_PAGES, USE_SCREEN_SHOT } from '@/store/types/pdf-types'
 
 export default {
-  props: ['src', 'page'],
   mounted () {
     this._canvas = document.getElementById('pdf-canvas')
     this._context = this._canvas.getContext('2d')
@@ -19,17 +20,31 @@ export default {
     const loadingTask = pdfjs.getDocument(this.src)
     loadingTask.promise.then(pdf => {
       this._pdf = pdf
+      this.$store.commit(SET_TOTAL_PAGES, { totalPages: pdf.numPages })
       this.showPage()
     })
   },
+  computed: {
+    ...mapState({
+      src: state => state.pdf.src,
+      currentPage: state => state.pdf.currentPage,
+      screenShot: state => state.pdf.screenShot
+    })
+  },
   watch: {
-    page (newPage) {
+    currentPage () {
       this.showPage()
+    },
+    screenShot () {
+      if (this.screenShot) {
+        this.getScreenShot()
+        this.$store.commit(USE_SCREEN_SHOT)
+      }
     }
   },
   methods: {
-    showPage() {
-      this._pdf.getPage(this.page ? this.page : 1).then(page => {
+    showPage () {
+      this._pdf && this._pdf.getPage(this.currentPage || 1).then(page => {
         const scale = 2
         const viewport = page.getViewport({ scale: scale })
 
@@ -58,11 +73,9 @@ canvas {
   outline: none;
   display: inline-block;
   direction: ltr;
-  box-shadow: 0 4px 8px -2px rgba(0, 0, 0, 0.1);
-}
-
-canvas {
   margin: 2px;
+  box-shadow: 0 4px 8px -2px rgba(0, 0, 0, 0.1);
+  background-color: white;
 }
 
 @media (min-width: 1001px) {

+ 5 - 5
src/components/PDF/PdfController.vue

@@ -15,6 +15,7 @@
 <script>
 import Icon from '@/components/Icon'
 import iconMap from '@/utils/icon-map'
+import { NEXT_PAGE, PREVIOUS_PAGE, SET_SCREEN_SHOT, TOGGLE_SHOW_DISCUSSION } from '@/store/types/pdf-types'
 
 export default {
   components: { Icon },
@@ -31,17 +32,16 @@ export default {
       // todo
     },
     handleDiscussionShowState () {
-      this.showDiscussion = !this.showDiscussion
-      this.$emit('change-discussion-show-state', this.showDiscussion)
+      this.$store.commit(TOGGLE_SHOW_DISCUSSION)
     },
     handlePrevious () {
-      this.$emit('previous')
+      this.$store.commit(PREVIOUS_PAGE)
     },
     handleNext () {
-      this.$emit('next')
+      this.$store.commit(NEXT_PAGE)
     },
     handleScreenShot () {
-      this.$emit('screen-shot')
+      this.$store.commit(SET_SCREEN_SHOT)
     }
   }
 }

+ 3 - 24
src/components/PDF/PdfViewer.vue

@@ -1,12 +1,7 @@
 <template>
   <div>
-    <pdf ref="pdf" :src="src" :page="page" :class="fullSize ? 'full-size': ''"></pdf>
-    <pdf-controller
-      @change-discussion-show-state="handleChangeDiscussionShowState"
-      @previous="handlePrevious"
-      @next="handleNext"
-      @screen-shot="handleScreenShot"
-    ></pdf-controller>
+    <pdf ref="pdf" :class="fullSize ? 'full-size': ''"></pdf>
+    <pdf-controller></pdf-controller>
   </div>
 </template>
 
@@ -18,7 +13,7 @@ export default {
   props: ['src', 'discussion'],
   data () {
     return {
-      page: 1,
+      currentPage: 1,
       fullSize: !this.discussion
     }
   },
@@ -26,22 +21,6 @@ export default {
     discussion (newValue) {
       this.fullSize = !newValue
     }
-  },
-  methods: {
-    handleChangeDiscussionShowState (state) {
-      this.$emit('change-discussion-show-state', state)
-    },
-    handlePrevious () {
-      if (this.page !== 1) {
-        this.page--
-      }
-    },
-    handleNext () {
-      this.page++
-    },
-    handleScreenShot () {
-      this.$refs.pdf.getScreenShot()
-    }
   }
 }
 </script>

+ 2 - 0
src/main.js

@@ -4,11 +4,13 @@ import App from './App.vue'
 import './registerServiceWorker'
 import router from './router'
 import uuid from 'uuid'
+import store from './store'
 
 Vue.config.productionTip = false
 Vue.prototype.$uuid = uuid
 
 new Vue({
   router,
+  store,
   render: h => h(App)
 }).$mount('#app')

+ 16 - 0
src/store/index.js

@@ -0,0 +1,16 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+import pdf from './modules/pdf'
+import message from './modules/message'
+
+Vue.use(Vuex)
+
+export default new Vuex.Store({
+  state: {},
+  mutations: {},
+  actions: {},
+  modules: {
+    message,
+    pdf
+  }
+})

+ 22 - 0
src/store/modules/message.js

@@ -0,0 +1,22 @@
+import { SET_MESSAGE, USE_MESSAGE } from '@/store/types/message-types'
+
+export default {
+  state: {
+    message: null,
+    type: null,
+    duration: 0
+  },
+
+  mutations: {
+    [SET_MESSAGE] (state, payload) {
+      this.message = payload.message ? payload.message : '未知消息信息'
+      this.type = payload.type ? payload.type : 'info'
+      this.duration = payload.duration ? payload.duration : 3000
+    },
+    [USE_MESSAGE] (state, payload) {
+      this.message = 0
+      this.type = null
+      this.duration = 0
+    }
+  }
+}

+ 52 - 0
src/store/modules/pdf.js

@@ -0,0 +1,52 @@
+import {
+  NEXT_PAGE,
+  PREVIOUS_PAGE,
+  RESET,
+  SET_CURRENT_PAGE, SET_SCREEN_SHOT,
+  SET_SRC, SET_TOTAL_PAGES, TOGGLE_SHOW_DISCUSSION, USE_SCREEN_SHOT
+} from '@/store/types/pdf-types'
+
+export default {
+  state: {
+    src: '',
+    totalPages: 0,
+    currentPage: 1,
+    showDiscussion: false,
+    screenShot: false
+  },
+
+  mutations: {
+    [PREVIOUS_PAGE] (state) {
+      state.currentPage = state.currentPage > 0 ? state.currentPage - 1 : state.currentPage
+    },
+    [NEXT_PAGE] (state) {
+      state.currentPage = state.currentPage < state.totalPages ? state.currentPage + 1 : state.currentPage
+    },
+    [SET_CURRENT_PAGE] (state, payload) {
+      state.currentPage = payload.currentPage
+    },
+    [SET_TOTAL_PAGES] (state, payload) {
+      state.totalPages = payload.totalPages
+    },
+    [SET_SRC] (state, payload) {
+      state.src = payload.src
+    },
+    [TOGGLE_SHOW_DISCUSSION] (state) {
+      state.showDiscussion = !state.showDiscussion
+    },
+    [SET_SCREEN_SHOT] (state) {
+      state.screenShot = true
+      // 防止没有还原导致不能截图
+      setTimeout(() => { state.screenShot = false }, 200)
+    },
+    [USE_SCREEN_SHOT] (state) {
+      state.screenShot = false
+    },
+    [RESET] (state) {
+      state.src = ''
+      state.totalPages = 0
+      state.currentPage = 1
+      state.screenShot = false
+    }
+  }
+}

+ 2 - 0
src/store/types/message-types.js

@@ -0,0 +1,2 @@
+export const SET_MESSAGE = 'setMessage'
+export const USE_MESSAGE = 'useMessage'

+ 9 - 0
src/store/types/pdf-types.js

@@ -0,0 +1,9 @@
+export const SET_TOTAL_PAGES = 'setTotalPages'
+export const SET_CURRENT_PAGE = 'setCurrentPage'
+export const SET_SRC = 'setSrc'
+export const TOGGLE_SHOW_DISCUSSION = 'toggleShowDiscussion'
+export const RESET = 'reset'
+export const NEXT_PAGE = 'nextPage'
+export const PREVIOUS_PAGE = 'previousPage'
+export const SET_SCREEN_SHOT = 'getScreenShot'
+export const USE_SCREEN_SHOT = 'useScreenShot'

+ 13 - 16
src/views/reader/PdfReader.vue

@@ -1,14 +1,11 @@
 <template>
-  <div class="pdf-reader" :discussion="showDiscussion">
+  <div class="pdf-reader">
     <div class="pdf-wrapper">
-      <pdf-viewer
-        :src="src"
-        @change-discussion-show-state="handleChangeDiscussionShowState"
-      ></pdf-viewer>
+      <pdf-viewer></pdf-viewer>
     </div>
     <div
       class="discussion-wrapper"
-      v-show="showDiscussion"
+      v-if="showDiscussion"
     >
       <h1 class="title">本页幻灯片讨论区</h1>
       <p><b>是的减肥还是看见很多风景开始是</b></p>
@@ -47,20 +44,20 @@
 
 <script>
 import PdfViewer from '@/components/PDF/PdfViewer'
+import { mapState } from 'vuex'
+import { SET_SRC } from '@/store/types/pdf-types'
+const src = 'http://seec-helper-pdf.oss-cn-hangzhou.aliyuncs.com/test.pdf?OSSAccessKeyId=LTAI4Fi1qmL4iuhH8t7G7r2H&Expires=1584224806&Signature=hi3UaVAMkKCSERdUYEuTeGGCd%2Bg%3D'
 
 export default {
   components: { PdfViewer },
-  mounted () {},
-  data () {
-    return {
-      src: 'http://seec-helper-pdf.oss-cn-hangzhou.aliyuncs.com/test.pdf?OSSAccessKeyId=LTAI4Fi1qmL4iuhH8t7G7r2H&Expires=1584224806&Signature=hi3UaVAMkKCSERdUYEuTeGGCd%2Bg%3D',
-      showDiscussion: false
-    }
+  computed: {
+    ...mapState({
+      src: state => state.pdf.src,
+      showDiscussion: state => state.pdf.showDiscussion
+    })
   },
-  methods: {
-    handleChangeDiscussionShowState (state) {
-      this.showDiscussion = state
-    }
+  beforeCreate () {
+    this.$store.commit(SET_SRC, { src })
   }
 }
 </script>

+ 6 - 1
yarn.lock

@@ -1261,11 +1261,16 @@
     ts-jest "^24.2.0"
     vue-jest "^3.0.5"
 
-"@vue/cli-plugin-vuex@^4.1.0", "@vue/cli-plugin-vuex@^4.1.1":
+"@vue/cli-plugin-vuex@^4.1.1":
   version "4.1.1"
   resolved "https://registry.npm.taobao.org/@vue/cli-plugin-vuex/download/@vue/cli-plugin-vuex-4.1.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcli-plugin-vuex%2Fdownload%2F%40vue%2Fcli-plugin-vuex-4.1.1.tgz#81908ee66370dda162b5517afc869f91d3abe2bf"
   integrity sha1-gZCO5mNw3aFitVF6/IafkdOr4r8=
 
+"@vue/cli-plugin-vuex@^4.1.2":
+  version "4.1.2"
+  resolved "https://registry.npm.taobao.org/@vue/cli-plugin-vuex/download/@vue/cli-plugin-vuex-4.1.2.tgz#5e728b56ad9de2f062a8944f838affa0297ccb99"
+  integrity sha1-XnKLVq2d4vBiqJRPg4r/oCl8y5k=
+
 "@vue/cli-service@^4.1.0":
   version "4.1.1"
   resolved "https://registry.npm.taobao.org/@vue/cli-service/download/@vue/cli-service-4.1.1.tgz?cache=0&sync_timestamp=1574867856121&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40vue%2Fcli-service%2Fdownload%2F%40vue%2Fcli-service-4.1.1.tgz#a14e9d455752f1a8e4e87ac436ebde88cad82276"