فهرست منبع

refactor: 增加reader页面和相关组件,重构项目结构

- 把只会在editor或者reader中使用的组件放到views下的components文件夹
ChenYangfan 6 سال پیش
والد
کامیت
807bd15829

+ 1 - 1
src/common/slide/slide.scss

@@ -3,7 +3,7 @@
   text-align: justify;
   margin: 0 auto;
   outline: none;
-  width: 1100px;
+  max-width: 1100px;
 
   line-height: 1.6;
 

+ 0 - 0
src/components/home/IconLink.vue → src/components/IconLink.vue


+ 0 - 0
src/components/common/SearchBar.vue → src/components/SearchBar.vue


+ 0 - 0
src/components/home/SlideListItem.vue → src/components/SlideListItem.vue


+ 4 - 0
src/router/index.js

@@ -12,6 +12,10 @@ const routes = [{
   path: '/editor/:id',
   name: 'editor',
   component: () => import('../views/editor/EditorView.vue')
+}, {
+  path: '/reader/:id',
+  name: 'reader',
+  component: () => import('../views/reader/ReaderView.vue')
 }, {
   path: '/typography',
   name: 'typography',

+ 3 - 1
src/store/index.js

@@ -1,6 +1,7 @@
 import Vue from 'vue'
 import Vuex from 'vuex'
 import editor from './modules/editor'
+import reader from './modules/reader'
 
 Vue.use(Vuex)
 
@@ -9,6 +10,7 @@ export default new Vuex.Store({
   mutations: {},
   actions: {},
   modules: {
-    editor: editor
+    editor: editor,
+    reader: reader
   }
 })

+ 20 - 0
src/store/modules/reader.js

@@ -0,0 +1,20 @@
+import {
+  READER_INIT
+} from '../types/reader-types'
+
+export default {
+  state: {
+    slideInfo: null,
+    items: []
+  },
+
+  mutations: {
+    [READER_INIT](state, payload) {
+      console.log(payload)
+      state.items = [...payload.items]
+      state.slideInfo = {
+        ...payload
+      }
+    }
+  }
+}

+ 0 - 5
src/store/modules/teacher.js

@@ -1,5 +0,0 @@
-export default {
-  state: {
-    previewSlide: {}
-  }
-}

+ 1 - 0
src/store/types/reader-types.js

@@ -0,0 +1 @@
+export const READER_INIT = 'reader_init'

+ 0 - 0
src/store/types/teacher-types.js


+ 0 - 0
src/utils/default-markdown-fagment.js → src/utils/default-markdown-fragment.js


+ 25 - 0
src/utils/generate-pages.js

@@ -0,0 +1,25 @@
+import uuid from 'uuid'
+
+export default function (items) {
+  const pages = []
+  let lastIndex = 0
+  let times = 0
+  items.forEach((item, index) => {
+    if (item.content === '====') {
+      pages.push({
+        items: [...items].slice(lastIndex, index + 1),
+        id: uuid.v4()
+      })
+      lastIndex = index + 1
+    }
+    times = index
+  })
+  if (times !== items.length) {
+    const page = {
+      items: [...items].slice(lastIndex),
+      id: uuid.v4()
+    }
+    pages.push(page)
+  }
+  return pages
+}

+ 59 - 0
src/utils/item-common.js

@@ -0,0 +1,59 @@
+import blockTypeRegs from './block-type-regs'
+
+const matchType = (content) => {
+  let res = 'div'
+  Object.entries(blockTypeRegs)
+    .map(array => ({
+      type: array[0],
+      reg: array[1]
+    }))
+    .some(({
+      type,
+      reg
+    }) => {
+      if (reg.test(content)) {
+        res = type
+      }
+    })
+  return res
+}
+
+const generateShowInfo = (type, item) => {
+  if (type === 'slideBreak') {
+    const content = ''
+    return {
+      tagName: 'div',
+      className: {
+        placeholder: true,
+        slideBreak: true
+      },
+      content,
+      placeholder: item.placeholder
+    }
+  } else if (type === 'div') {
+    const content = item.content
+    return {
+      tagName: 'div',
+      className: {
+        placeholder: content === ''
+      },
+      content,
+      placeholder: item.placeholder
+    }
+  } else {
+    const content = item.content.replace(blockTypeRegs[type], '')
+    return {
+      tagName: type,
+      className: {
+        placeholder: content === ''
+      },
+      content,
+      placeholder: item.placeholder
+    }
+  }
+}
+
+export {
+  matchType,
+  generateShowInfo
+}

+ 8 - 1
src/views/Home.vue

@@ -4,11 +4,18 @@
     <router-link to="/typography">排版布局原型</router-link><br />
     <router-link to="/teacher">教师主页</router-link><br />
     <router-link to="/student">学生主页</router-link>
+    {{ height }}
   </div>
 </template>
 
 <script>
-export default {}
+export default {
+  data() {
+    return {
+      height: window.innerHeight
+    }
+  }
+}
 </script>
 
 <style lang="scss">

+ 1 - 2
src/views/editor/EditorView.vue

@@ -6,7 +6,7 @@
 </template>
 
 <script>
-import EditorVue from '../../components/editor/Editor.vue'
+import EditorVue from './components/Editor.vue'
 import { updateSlide, teacherGetSlideById } from '../../server/slide'
 import { DIFF, INIT_BY_STATE } from '../../store/types/editor-types'
 import { mapState } from 'vuex'
@@ -20,7 +20,6 @@ export default {
   },
   created() {
     teacherGetSlideById(this.slideId).then(res => {
-      console.log(res)
       this.$store.commit(INIT_BY_STATE, res)
     })
   },

+ 7 - 43
src/components/editor/EditableItem.vue → src/views/editor/components/EditableItem.vue

@@ -16,7 +16,6 @@
 </template>
 
 <script>
-import blockTypeRegs from '../../utils/block-type-regs'
 import {
   MODIFY_ITEM,
   ADD_ITEM_AFTER,
@@ -24,9 +23,11 @@ import {
   SET_FOCUS_AFTER,
   SET_FOCUS_BEFORE,
   SET_FOCUS
-} from '../../store/types/editor-types'
-import defaultPlaceholder from '../../utils/default-placeholder'
-import defaultMarkdownFagment from '../../utils/default-markdown-fagment'
+} from '@/store/types/editor-types'
+import defaultPlaceholder from '@/utils/default-placeholder'
+import defaultMarkdownFagment from '@/utils/default-markdown-fragment'
+import { matchType, generateShowInfo } from '@/utils/item-common'
+
 export default {
   name: 'editable-item',
   props: ['item'],
@@ -45,48 +46,11 @@ export default {
   },
   computed: {
     showInfo() {
-      if (this.type === 'slideBreak') {
-        const content = ''
-        return {
-          tagName: 'div',
-          className: {
-            placeholder: true,
-            slideBreak: true
-          },
-          content,
-          placeholder: this.item.placeholder
-        }
-      } else if (this.type === 'div') {
-        const content = this.item.content
-        return {
-          tagName: 'div',
-          className: { placeholder: content === '' },
-          content,
-          placeholder: this.item.placeholder
-        }
-      } else {
-        const content = this.item.content.replace(blockTypeRegs[this.type], '')
-        return {
-          tagName: this.type,
-          className: { placeholder: content === '' },
-          content,
-          placeholder: this.item.placeholder
-        }
-      }
+      return generateShowInfo(this.type, this.item)
     }
   },
   methods: {
-    matchType(content) {
-      let res = 'div'
-      Object.entries(blockTypeRegs)
-        .map(array => ({ type: array[0], reg: array[1] }))
-        .some(({ type, reg }) => {
-          if (reg.test(content)) {
-            res = type
-          }
-        })
-      return res
-    },
+    matchType,
     handleKeyDown(e) {
       if (!this.isCompositionStarted) {
         switch (e.key) {

+ 0 - 0
src/components/editor/EditingPage.vue → src/views/editor/components/EditingPage.vue


+ 5 - 17
src/components/editor/Editor.vue → src/views/editor/components/Editor.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="slide show-mode">
     <template v-for="page in pages">
-      <editing-page-vue :key="page.frontendId" :page="page"></editing-page-vue>
+      <editing-page-vue :key="page.id" :page="page"></editing-page-vue>
     </template>
     <div v-show="false">{{ focus }}</div>
   </div>
@@ -10,7 +10,9 @@
 <script>
 import { mapState } from 'vuex'
 import EditingPageVue from './EditingPage.vue'
-import { USE_FOCUS, INIT_BY_DEFAULT } from '../../store/types/editor-types'
+import { USE_FOCUS, INIT_BY_DEFAULT } from '@/store/types/editor-types'
+import generatePages from '@/utils/generate-pages'
+
 export default {
   name: 'editor',
   components: {
@@ -30,22 +32,8 @@ export default {
           )
         })
       }
-      const pages = []
-      let lastIndex = 0
-      let times = 0
-      items.forEach((item, index) => {
-        if (item.content === '====') {
-          pages.push({ items: [...items].slice(lastIndex, index + 1) })
-          lastIndex = index + 1
-        }
-        times = index
-      })
-      if (times !== items.length) {
-        const page = { items: [...items].slice(lastIndex) }
-        pages.push(page)
-      }
 
-      return pages
+      return generatePages(items)
     },
     focus() {
       const res = this.$store.state.editor.focus

+ 27 - 0
src/views/reader/ReaderView.vue

@@ -0,0 +1,27 @@
+<template>
+  <reader-vue></reader-vue>
+</template>
+
+<script>
+import ReaderVue from './components/Reader.vue'
+import { teacherGetSlideById } from '@/server/slide'
+import { READER_INIT } from '@/store/types/reader-types'
+
+export default {
+  components: { ReaderVue },
+  data() {
+    return {
+      slideId: this.$route.params.id,
+      slide: null
+    }
+  },
+  created() {
+    teacherGetSlideById(this.slideId).then(res => {
+      this.$store.commit(READER_INIT, res)
+    })
+  }
+}
+</script>
+
+<style>
+</style>

+ 28 - 0
src/views/reader/components/Reader.vue

@@ -0,0 +1,28 @@
+<template>
+  <div class="slide show-mode">
+    <template v-for="page in pages">
+      <reader-page-vue :key="page.id" :page="page"></reader-page-vue>
+    </template>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+import ReaderPageVue from './ReaderPage.vue'
+import generatePages from '@/utils/generate-pages'
+export default {
+  components: { ReaderPageVue },
+  computed: {
+    ...mapState({
+      items: state => state.reader.items
+    }),
+    pages() {
+      return generatePages(this.$store.state.reader.items)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/common/slide/slide.scss';
+</style>

+ 51 - 0
src/views/reader/components/ReaderItem.vue

@@ -0,0 +1,51 @@
+<template>
+  <component
+    ref="element"
+    :is="showInfo.tagName"
+    :id="item.frontendId"
+    v-html="showInfo.content"
+    :class="showInfo.className"
+  >
+  </component>
+</template>
+
+<script>
+import { matchType, generateShowInfo } from '@/utils/item-common'
+export default {
+  props: ['item'],
+  data: function() {
+    return {
+      type: 'div'
+    }
+  },
+  mounted() {
+    this.type = this.matchType(this.item.content)
+  },
+  updated() {
+    this.type = this.matchType(this.item.content)
+  },
+  computed: {
+    showInfo() {
+      return generateShowInfo(this.type, this.item)
+    }
+  },
+  methods: {
+    matchType
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/common/slide/item.scss';
+* [contenteditable] {
+  outline: none;
+  width: 100%;
+
+  &:hover {
+    background: #fafcfe;
+  }
+}
+.slideBreak {
+  color: lightblue;
+}
+</style>

+ 24 - 0
src/views/reader/components/ReaderPage.vue

@@ -0,0 +1,24 @@
+<template>
+  <section class="page">
+    <div>
+      <template v-for="item in page.items">
+        <reader-item-vue :item="item" :key="item.frontendId" />
+      </template>
+    </div>
+  </section>
+</template>
+
+<script>
+import ReaderItemVue from './ReaderItem.vue'
+export default {
+  name: 'editing-page',
+  props: ['page'],
+  components: {
+    ReaderItemVue
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/common/slide/page.scss';
+</style>

+ 2 - 2
src/views/student/StudentHomeView.vue

@@ -5,13 +5,13 @@
         <icon-link-vue :tab="tab" :key="index"></icon-link-vue>
       </template>
     </template>
-    <template v-slot:preview></template>
+    <template v-slot:preview> </template>
   </role-home-vue>
 </template>
 
 <script>
 import RoleHomeVue from '@/layouts/RoleHome.vue'
-import IconLinkVue from '@/components/home/IconLink.vue'
+import IconLinkVue from '@/components/IconLink.vue'
 
 export default {
   components: { RoleHomeVue, IconLinkVue },

+ 2 - 2
src/views/teacher/TeacherHomeView.vue

@@ -10,8 +10,8 @@
 </template>
 
 <script>
-import RoleHomeVue from '../../layouts/RoleHome.vue'
-import IconLinkVue from '../../components/home/IconLink.vue'
+import RoleHomeVue from '@/layouts/RoleHome.vue'
+import IconLinkVue from '@/components/IconLink.vue'
 
 export default {
   components: { RoleHomeVue, IconLinkVue },

+ 2 - 2
src/views/teacher/tabs/HomeTab.vue

@@ -24,8 +24,8 @@
 </template>
 
 <script>
-import SlideListItemVue from '@/components/home/SlideListItem.vue'
-import { teacherGetRecentSlides } from '../../../server/slide'
+import SlideListItemVue from '@/components/SlideListItem.vue'
+import { teacherGetRecentSlides } from '@/server/slide'
 
 export default {
   data() {

+ 1 - 1
src/views/teacher/tabs/SearchTab.vue

@@ -10,7 +10,7 @@
 </template>
 
 <script>
-import SearchBarVue from '@/components/common/SearchBar'
+import SearchBarVue from '@/components/SearchBar'
 export default {
   data() {
     return {