Commit c784e56d9c7ae9b91a524b1ad3b1a8c28f0f8d9e
1 parent
abd9e622
feat(page): support copy, delete page
Showing
7 changed files
with
33 additions
and
11 deletions
README.en.md
| @@ -15,8 +15,11 @@ English | [简体中文](./README.md) | @@ -15,8 +15,11 @@ English | [简体中文](./README.md) | ||
| 15 | - [x] Edit Element (Canvas) | 15 | - [x] Edit Element (Canvas) |
| 16 | - [x] Copy Element (Canvas) | 16 | - [x] Copy Element (Canvas) |
| 17 | - [x] Delete Element (Canvas) | 17 | - [x] Delete Element (Canvas) |
| 18 | - - [ ] Page: add, copy, delete | ||
| 19 | - - [x] Preview | 18 | + - [x] Edit Page |
| 19 | + - [x] Copy Page | ||
| 20 | + - [x] Delete Page | ||
| 21 | + - [x] Quick Preview | ||
| 22 | + - [x] Undo、Redo | ||
| 20 | 23 | ||
| 21 | 2. Plugin System | 24 | 2. Plugin System |
| 22 | 25 |
README.md
front-end/h5/src/components/core/editor/index.js
| @@ -79,8 +79,8 @@ export default { | @@ -79,8 +79,8 @@ export default { | ||
| 79 | </a> | 79 | </a> |
| 80 | <a-menu slot="overlay" onClick={({ key }) => { this.pageManager({ type: key }) }}> | 80 | <a-menu slot="overlay" onClick={({ key }) => { this.pageManager({ type: key }) }}> |
| 81 | <a-menu-item key="add"><a-icon type="user" />新增页面</a-menu-item> | 81 | <a-menu-item key="add"><a-icon type="user" />新增页面</a-menu-item> |
| 82 | - {/* <a-menu-item key="copy"><a-icon type="user" />复制页面</a-menu-item> */} | ||
| 83 | - {/* <a-menu-item key="delete"><a-icon type="user" />删除页面</a-menu-item> */} | 82 | + <a-menu-item key="copy"><a-icon type="user" />复制页面</a-menu-item> |
| 83 | + <a-menu-item key="delete"><a-icon type="user" />删除页面</a-menu-item> | ||
| 84 | </a-menu> | 84 | </a-menu> |
| 85 | </a-dropdown> | 85 | </a-dropdown> |
| 86 | </span> | 86 | </span> |
front-end/h5/src/components/core/models/element.js
| 1 | +const clone = (value) => JSON.parse(JSON.stringify(value)) | ||
| 1 | 2 | ||
| 2 | const defaultProps = { | 3 | const defaultProps = { |
| 3 | top: 100, | 4 | top: 100, |
| @@ -16,14 +17,18 @@ class Element { | @@ -16,14 +17,18 @@ class Element { | ||
| 16 | this.name = ele.name | 17 | this.name = ele.name |
| 17 | this.uuid = +new Date() | 18 | this.uuid = +new Date() |
| 18 | /** | 19 | /** |
| 20 | + * #!zh: | ||
| 19 | * 之前版本代码:https://github.com/ly525/luban-h5/blob/a7875cbc73c0d18bc2459985ca3ce1d4dc44f141/front-end/h5/src/components/core/models/element.js#L21 | 21 | * 之前版本代码:https://github.com/ly525/luban-h5/blob/a7875cbc73c0d18bc2459985ca3ce1d4dc44f141/front-end/h5/src/components/core/models/element.js#L21 |
| 20 | * 1.之前的版本为:this.pluginProps = {}, 改为下面的版本 | 22 | * 1.之前的版本为:this.pluginProps = {}, 改为下面的版本 |
| 21 | * 是因为要支持[复制画布上的元素],所以需要先使用 ele.pluginProps 进行初始化(也就是拷贝之前的元素的值) | 23 | * 是因为要支持[复制画布上的元素],所以需要先使用 ele.pluginProps 进行初始化(也就是拷贝之前的元素的值) |
| 22 | * | 24 | * |
| 23 | * 2. 移除 this.init() 原因是:如果是 复制元素,则 init 会把 copy 的值重新覆盖为初始值,copy 无效 | 25 | * 2. 移除 this.init() 原因是:如果是 复制元素,则 init 会把 copy 的值重新覆盖为初始值,copy 无效 |
| 26 | + * | ||
| 27 | + * 3. 为何需要 clone,因为会有 element.clone() 以及 page.clone(), | ||
| 28 | + * element.pluginProps 和 elementcommonStyle 是引用类型,如果不做 deep_clone 可能会出现意外错误 | ||
| 24 | */ | 29 | */ |
| 25 | - this.pluginProps = ele.pluginProps || this.getDefaultPluginProps(ele.editorConfig || {}) | ||
| 26 | - this.commonStyle = ele.commonStyle || this.getDefaultCommonStyle() | 30 | + this.pluginProps = clone(ele.pluginProps) || this.getDefaultPluginProps(ele.editorConfig || {}) |
| 31 | + this.commonStyle = clone(ele.commonStyle) || this.getDefaultCommonStyle() | ||
| 27 | this.events = [] | 32 | this.events = [] |
| 28 | } | 33 | } |
| 29 | 34 | ||
| @@ -74,7 +79,7 @@ class Element { | @@ -74,7 +79,7 @@ class Element { | ||
| 74 | clone () { | 79 | clone () { |
| 75 | return new Element({ | 80 | return new Element({ |
| 76 | name: this.name, | 81 | name: this.name, |
| 77 | - pluginProps: JSON.parse(JSON.stringify(this.pluginProps)), | 82 | + pluginProps: this.pluginProps, |
| 78 | commonStyle: { | 83 | commonStyle: { |
| 79 | ...this.commonStyle, | 84 | ...this.commonStyle, |
| 80 | top: this.commonStyle.top + 20, | 85 | top: this.commonStyle.top + 20, |
front-end/h5/src/components/core/models/page.js
| 1 | +import Element from '../models/element' | ||
| 2 | + | ||
| 1 | class Page { | 3 | class Page { |
| 2 | constructor (page = {}) { | 4 | constructor (page = {}) { |
| 5 | + this.uuid = +new Date() | ||
| 3 | this.elements = page.elements || [] | 6 | this.elements = page.elements || [] |
| 4 | } | 7 | } |
| 8 | + | ||
| 9 | + clone () { | ||
| 10 | + const elements = this.elements.map(element => new Element(element)) | ||
| 11 | + return new Page({ elements }) | ||
| 12 | + } | ||
| 5 | } | 13 | } |
| 6 | 14 | ||
| 7 | export default Page | 15 | export default Page |
front-end/h5/src/store/modules/page.js
| @@ -26,10 +26,12 @@ export const mutations = { | @@ -26,10 +26,12 @@ export const mutations = { | ||
| 26 | state.work.pages.push(state.editingPage.clone()) | 26 | state.work.pages.push(state.editingPage.clone()) |
| 27 | break | 27 | break |
| 28 | case 'delete': | 28 | case 'delete': |
| 29 | + if (state.work.pages.length === 1) return // #!zh: 作品中至少需要保留一个页面,TODO 需要在页面中提示用户此信息 | ||
| 30 | + | ||
| 29 | const { work, editingPage } = state | 31 | const { work, editingPage } = state |
| 30 | - let index = work.pages.findIndex(e => e.uuid === editingPage.uuid) | 32 | + let index = work.pages.findIndex(page => page.uuid === editingPage.uuid) |
| 31 | if (index !== -1) { | 33 | if (index !== -1) { |
| 32 | - let newPages = work.slice() | 34 | + let newPages = work.pages.slice() |
| 33 | newPages.splice(index, 1) | 35 | newPages.splice(index, 1) |
| 34 | state.work.pages = newPages | 36 | state.work.pages = newPages |
| 35 | } | 37 | } |
front-end/h5/src/store/modules/work.js
| 1 | // import Work from '../../components/core/models/work' | 1 | // import Work from '../../components/core/models/work' |
| 2 | import Element from '../../components/core/models/element' | 2 | import Element from '../../components/core/models/element' |
| 3 | import strapi from '../../utils/strapi' | 3 | import strapi from '../../utils/strapi' |
| 4 | +import Page from '../../components/core/models/page' | ||
| 4 | 5 | ||
| 5 | export const actions = { | 6 | export const actions = { |
| 6 | previewWork ({ commit }, payload = {}) { | 7 | previewWork ({ commit }, payload = {}) { |
| @@ -32,8 +33,9 @@ export const actions = { | @@ -32,8 +33,9 @@ export const actions = { | ||
| 32 | // mutations | 33 | // mutations |
| 33 | export const mutations = { | 34 | export const mutations = { |
| 34 | setWork (state, work) { | 35 | setWork (state, work) { |
| 35 | - work.pages.forEach(page => { | 36 | + work.pages = work.pages.map(page => { |
| 36 | page.elements = page.elements.map(element => new Element(element)) | 37 | page.elements = page.elements.map(element => new Element(element)) |
| 38 | + return new Page(page) | ||
| 37 | }) | 39 | }) |
| 38 | state.work = work | 40 | state.work = work |
| 39 | }, | 41 | }, |