Просмотр исходного кода

refactor: 根据重新定义的数据结构更改前端编辑器逻辑

ChenYangfan 6 лет назад
Родитель
Сommit
c5a4174f23

+ 43 - 37
src/components/editor/EditableItem.vue

@@ -1,7 +1,7 @@
 <template>
   <component
     ref="element"
-    :is="item.type"
+    :is="tagName"
     :id="item.id"
     @compositionstart.stop="handleCompositionStart"
     @compositionend.stop="handleCompositionEnd"
@@ -29,29 +29,50 @@ import defaultPlaceholder from '../../utils/default-placeholder'
 import defaultMarkdownFagment from '../../utils/default-markdown-fagment'
 export default {
   name: 'editable-item',
-  props: ['item', 'pageId'],
+  props: ['item'],
   data: function() {
     return {
       isCompositionStarted: false,
       range: null,
-      contentForShow:
-        this.item.type === 'div'
-          ? this.item.content
-          : this.item.content.replace(blockTypeRegs[this.item.type], '')
+      tagName: 'div',
+      contentForShow: ''
     }
   },
+  mounted() {
+    this.init()
+  },
+  updated() {
+    this.init()
+  },
   methods: {
+    init() {
+      this.tagName = this.matchTagName()
+      this.contentForShow =
+        this.tagName === 'div'
+          ? this.item.content
+          : this.item.content.replace(blockTypeRegs[this.tagName], '')
+    },
+    matchTagName() {
+      let res = 'div'
+      Object.entries(blockTypeRegs)
+        .map(array => ({ tagName: array[0], reg: array[1] }))
+        .some(({ tagName, reg }) => {
+          if (reg.test(this.item.content)) {
+            res = tagName
+          }
+        })
+      return res
+    },
     handleKeyDown(e) {
       if (!this.isCompositionStarted) {
         switch (e.key) {
           case 'Enter':
             e.preventDefault()
             this.$store.commit(ADD_ITEM_AFTER, {
-              pageId: this.pageId,
-              itemId: this.item.id
+              id: this.item.id
             })
             this.$store.commit(SET_FOCUS_AFTER, {
-              itemId: this.item.id
+              focusId: this.item.id
             })
             break
 
@@ -59,11 +80,10 @@ export default {
             if (!this.item.content) {
               e.preventDefault()
               this.$store.commit(SET_FOCUS_BEFORE, {
-                itemId: this.item.id
+                focusId: this.item.id
               })
               this.$store.commit(DELETE_ITEM, {
-                pageId: this.pageId,
-                itemId: this.item.id
+                id: this.item.id
               })
               break
             }
@@ -74,36 +94,32 @@ export default {
             if (
               offset === 0 &&
               this.range.collapsed &&
-              this.item.type !== 'div'
+              this.tagName !== 'div'
             ) {
               this.$store.commit(MODIFY_ITEM, {
-                pageId: this.pageId,
-                itemId: this.item.id,
+                id: this.item.id,
                 diff: {
-                  type: 'div',
                   placeholder: defaultPlaceholder['div'],
                   content: this.contentForShow
                 }
               })
               this.$store.commit(SET_FOCUS, {
-                focusItemId: this.item.id,
-                focusItemOffset: offset
+                diff: { focusId: this.item.id, offset }
               })
             }
-
             break
 
           case 'ArrowUp':
             e.preventDefault()
             this.$store.commit(SET_FOCUS_BEFORE, {
-              itemId: this.item.id
+              focusId: this.item.id
             })
             break
 
           case 'ArrowDown':
             e.preventDefault()
             this.$store.commit(SET_FOCUS_AFTER, {
-              itemId: this.item.id
+              focusId: this.item.id
             })
             break
 
@@ -124,31 +140,21 @@ export default {
     },
     handleInputValue(e) {
       const diff = {
-        content: defaultMarkdownFagment[this.item.type] + e.target.textContent
+        content: defaultMarkdownFagment[this.tagName] + e.target.textContent
+      }
+      if (this.tagName === 'div' && this.matchTagName() !== this.tagName) {
+        diff.placeholder = defaultPlaceholder[this.matchTagName()]
       }
-      this.item.type === 'div' &&
-        Object.entries(blockTypeRegs)
-          .map(array => ({ tagName: array[0], reg: array[1] }))
-          .some(({ tagName, reg }) => {
-            if (reg.test(e.target.textContent)) {
-              diff.type = tagName
-              diff.placeholder = defaultPlaceholder[tagName]
-            }
-          })
 
       this.$store.commit(MODIFY_ITEM, {
-        pageId: this.pageId,
-        itemId: this.item.id,
+        id: this.item.id,
         diff
       })
 
       this.range = window.getSelection().getRangeAt(0)
       const offset = this.range.startOffset
 
-      this.$store.commit(SET_FOCUS, {
-        focusItemId: this.item.id,
-        focusItemOffset: offset
-      })
+      this.$store.commit(SET_FOCUS, { diff: { focusId: this.item.id, offset } })
     }
   }
 }

+ 0 - 1
src/components/editor/EditingPage.vue

@@ -4,7 +4,6 @@
       <editable-item-vue
         :key="item.id"
         :item="item"
-        :pageId="page.id"
       />
     </template>
   </section>

+ 21 - 6
src/components/editor/Editor.vue

@@ -18,8 +18,25 @@ export default {
   },
   computed: {
     ...mapState({
-      pages: state => state.editor.pages
+      items: state => state.editor.items
     }),
+    pages() {
+      const items = this.$store.state.editor.items
+      const pages = []
+      let lastIndex = 0
+      let times = 0
+      items.forEach((item, index) => {
+        if (item.content === '===') {
+          pages.push({ items: [...items].slice(lastIndex, index) })
+          lastIndex = index
+        }
+        times = index
+      })
+      if (times !== items.length) {
+        pages.push({ items: [...items].slice(lastIndex) })
+      }
+      return pages
+    },
     focus() {
       const res = this.$store.state.editor.focus
       res !== null &&
@@ -32,17 +49,15 @@ export default {
   methods: {
     checkFocus() {
       if (this.focus !== null) {
-        if (this.focus.focusItemId) {
+        if (this.focus.focusId) {
           this.$nextTick(() => {
-            const item = document.getElementById(this.focus.focusItemId)
+            const item = document.getElementById(this.focus.focusId)
             item.focus()
-            const offset = this.focus.focusItemOffset
+            const offset = this.focus.offset
             const computeResult = this.computeContainerAndOffset(item, offset)
-
             const range = document.getSelection().getRangeAt(0)
             range.setStart(computeResult.container, computeResult.offset)
             range.collapse()
-
             this.$store.commit(USE_FOCUS)
           })
         }

+ 54 - 118
src/store/modules/editor.js

@@ -1,8 +1,6 @@
 import {
   INIT_BY_STATE,
   INIT_BY_DEFAULT,
-  ADD_PAGE_AFTER,
-  DELETE_PAGE,
   ADD_ITEM_AFTER,
   MODIFY_ITEM,
   DELETE_ITEM,
@@ -16,7 +14,7 @@ import uuid from 'uuid'
 
 export default {
   state: {
-    pages: [],
+    items: [],
     focus: null
   },
 
@@ -24,159 +22,97 @@ export default {
     [INIT_BY_STATE](state, payload) {},
     [INIT_BY_DEFAULT](state, payload) {
       const newItemId = uuid.v4()
-      const newPageId = uuid.v4()
-      state.pages = [{
-        id: newPageId,
-        items: [{
-          id: newItemId,
-          type: 'h1',
-          placeholder: '未编辑文档标题',
-          content: '# '
-        }]
+      state.items = [{
+        id: newItemId,
+        placeholder: '未编辑文档标题',
+        content: '# '
       }]
       state.focus = {
-        focusPageId: newPageId,
-        focusItemId: newItemId,
-        focusItemOffset: 0
+        focusId: newItemId,
+        offset: 0
       }
     },
-    [ADD_PAGE_AFTER](state, payload) {
-      const index = state.pages.indexOf(state.pages.filter(page => page.id === payload.pageId)[0])
+    [ADD_ITEM_AFTER](state, payload) {
+      const index = state.items.indexOf(state.items.filter(item => item.id === payload.id)[0])
 
-      state.pages = [
-        ...state.pages.slice(0, index + 1), {
+      state.items = [
+        ...state.items.slice(0, index + 1), {
           id: uuid.v4(),
-          items: [{
-            id: uuid.v4(),
-            type: 'h3',
-            placeholder: '未编辑小标题',
-            content: ''
-          }, ...state.pages.slice(index + 1)]
-        }
-      ]
-    },
-    [DELETE_PAGE](state, payload) {
-      state.pages = [...state.pages.filter(page => page.id !== payload.id)]
-    },
-    [ADD_ITEM_AFTER](state, payload) {
-      state.pages = [
-        ...state.pages.map(page => {
-          if (page.id === payload.pageId) {
-            const index = page.items.indexOf(page.items.filter(item => item.id === payload.itemId)[0])
-            return {
-              ...page,
-              items: [
-                ...page.items.slice(0, index + 1), {
-                  id: uuid.v4(),
-                  type: 'div',
-                  content: '',
-                  placeholder: '未编辑正文项'
-                },
-                ...page.items.slice(index + 1)
-              ]
-            }
-          }
-          return page
-        })
+          content: '',
+          placeholder: '正文'
+        },
+        ...state.items.slice(index + 1)
       ]
     },
     [MODIFY_ITEM](state, payload) {
-      state.pages = [
-        ...state.pages.map(page => {
-          if (page.id === payload.pageId) {
-            return {
-              ...page,
-              items: page.items.map(item => {
-                if (item.id === payload.itemId) {
-                  return {
-                    ...item,
-                    ...payload.diff
-                  }
-                }
-                return item
-              })
-            }
+      state.items = [...state.items.map(item => {
+        if (item.id === payload.id) {
+          return {
+            ...item,
+            ...payload.diff
           }
-          return page
-        })
-      ]
+        } else {
+          return item
+        }
+      })]
     },
     [DELETE_ITEM](state, payload) {
-      state.pages = [
-        ...state.pages.map(page => {
-          if (page.id === payload.pageId) {
-            return {
-              ...page,
-              items: page.items.filter((item, index) => index === 0 || item.id !== payload.itemId)
-            }
-          } else {
-            return page
-          }
-        })
-      ]
+      state.items = [...state.items.filter((item, index) => index === 0 || item.id !== payload.id)]
     },
     [SET_FOCUS](state, payload) {
       state.focus = {
         ...state.focus,
-        ...payload
+        ...payload.diff
       }
     },
     [SET_FOCUS_AFTER](state, payload) {
       let focusId = ''
-      let targetedFlag = false
-      const isHit = state.pages.some(page => {
-        page.items.some(item => {
-          if (targetedFlag) {
-            focusId = item.id
-            return true
-          }
-          if (item.id === payload.itemId) {
-            targetedFlag = true
-          }
-          return false
-        })
-        return targetedFlag
+      let tagetedFlag = false
+      const isHit = state.items.some(item => {
+        if (tagetedFlag) {
+          focusId = item.id
+          return true
+        }
+        if (item.id === payload.focusId) {
+          tagetedFlag = true
+        }
+        return false
       })
 
       if (isHit) {
         state.focus = {
-          focusItemId: focusId,
-          focusItemOffset: payload.offset
+          focusId: focusId,
+          offset: payload.offset ? payload.offset : 0
         }
       } else {
-        // todo log
+        // todo warn
       }
     },
     [SET_FOCUS_BEFORE](state, payload) {
       let focusId = ''
-      let targetedFlag = false
-      const isHit = state.pages.some(page => {
-        [...page.items].reverse().some(item => {
-          if (targetedFlag) {
-            focusId = item.id
-            return true
-          }
-          if (item.id === payload.itemId) {
-            targetedFlag = true
-          }
-          return false
-        })
-        return targetedFlag
+      let tagetedFlag = false
+      const isHit = [...state.items].reverse().some(item => {
+        if (tagetedFlag) {
+          focusId = item.id
+          return true
+        }
+        if (item.id === payload.focusId) {
+          tagetedFlag = true
+        }
+        return false
       })
 
-      if (isHit && targetedFlag) {
+      if (isHit) {
         state.focus = {
-          focusItemId: focusId,
-          focusItemOffset: payload.offset ? payload.offset : 9999
+          focusId: focusId,
+          offset: payload.offset ? payload.offset : 99999
         }
       } else {
-        // todo log
+        // todo warn
       }
     },
     [USE_FOCUS](state, payload) {
       state.focus = null
     }
-  },
-  actions: {},
-  getters: {}
+  }
 }

+ 2 - 2
src/store/types/editor-types.js

@@ -1,7 +1,7 @@
 export const INIT_BY_STATE = 'initByState'
 export const INIT_BY_DEFAULT = 'initByDefault'
-export const ADD_PAGE_AFTER = 'addPageAfter'
-export const DELETE_PAGE = 'initByState'
+// export const ADD_PAGE_AFTER = 'addPageAfter'
+// export const DELETE_PAGE = 'initByState'
 export const ADD_ITEM_AFTER = 'addItemAfter'
 export const MODIFY_ITEM = 'modifyItem'
 export const DELETE_ITEM = 'deleteItem'