Commit d039dcbafbf0e160b175f7fea52a27ae7bb4cf44
Committed by
GitHub
1 parent
a9a71231
feat: 添加快捷键+更完整的辅助线提示 (#148) add shortcuts for editor and more guidelines
* fix scrollbar show when h-line&v-line visible * remove unused text code * add hotkey to menu tools * 除了left和top,其他四条线(midx,right,midy,bottom)也提示辅助线 * change width and height when point move situation * rename argument and optimize some experience * Fix typo thanks @shihongzhi
Showing
4 changed files
with
96 additions
and
66 deletions
front-end/h5/package.json
front-end/h5/src/components/core/editor/canvas/edit.js
| ... | ... | @@ -23,73 +23,97 @@ export default { |
| 23 | 23 | // TODO #!zh: 优化代码 |
| 24 | 24 | // generate vertical line |
| 25 | 25 | drawVLine (newLeft) { |
| 26 | - // this.editingElement.commonStyle.left = newLeft | |
| 27 | - this.setElementPosition({ left: newLeft }) | |
| 28 | 26 | this.vLines = [{ left: newLeft }] |
| 29 | 27 | }, |
| 28 | + clearVLine () { | |
| 29 | + this.vLines = [] | |
| 30 | + }, | |
| 30 | 31 | // generate horizontal line |
| 31 | 32 | drawHLine (newTop) { |
| 32 | - // this.editingElement.commonStyle.top = newTop | |
| 33 | - this.setElementPosition({ top: newTop }) | |
| 34 | 33 | this.hLines = [{ top: newTop }] |
| 35 | 34 | }, |
| 36 | - calcX (newLeft) { | |
| 35 | + clearHLine () { | |
| 36 | + this.hLines = [] | |
| 37 | + }, | |
| 38 | + calcVHLine (isPointMove) { | |
| 37 | 39 | const uuid = this.editingElement.uuid |
| 38 | - let xCoords = [] | |
| 39 | - this.elements.filter(e => e.uuid !== uuid).forEach(e => { | |
| 40 | + const referElements = this.elements.filter(e => e.uuid !== uuid) | |
| 41 | + let referElementsXCoords = [] | |
| 42 | + let referElementsYCoords = [] | |
| 43 | + referElements.forEach(e => { | |
| 40 | 44 | const width = e.commonStyle.width |
| 41 | 45 | const left = e.commonStyle.left |
| 42 | - xCoords = [ | |
| 43 | - ...xCoords, | |
| 46 | + const height = e.commonStyle.height | |
| 47 | + const top = e.commonStyle.top | |
| 48 | + | |
| 49 | + referElementsXCoords = [ | |
| 50 | + ...referElementsXCoords, | |
| 44 | 51 | left, |
| 45 | 52 | left + (width / 2), |
| 46 | 53 | left + width |
| 47 | 54 | ] |
| 48 | - }) | |
| 49 | - | |
| 50 | - xCoords.some(x => { | |
| 51 | - if (Math.abs(newLeft - x) <= 5) { | |
| 52 | - this.drawVLine(x) | |
| 53 | - return true | |
| 54 | - } else { | |
| 55 | - this.vLines = [] | |
| 56 | - } | |
| 57 | - }) | |
| 58 | - }, | |
| 59 | - calcY (newTop) { | |
| 60 | - const uuid = this.editingElement.uuid | |
| 61 | - let yCoords = [] | |
| 62 | - this.elements.filter(e => e.uuid !== uuid).forEach(e => { | |
| 63 | - const height = e.commonStyle.height | |
| 64 | - const top = e.commonStyle.top | |
| 65 | - yCoords = [ | |
| 66 | - ...yCoords, | |
| 55 | + referElementsYCoords = [ | |
| 56 | + ...referElementsYCoords, | |
| 67 | 57 | top, |
| 68 | 58 | top + (height / 2), |
| 69 | 59 | top + height |
| 70 | 60 | ] |
| 71 | 61 | }) |
| 72 | 62 | |
| 73 | - yCoords.some(y => { | |
| 74 | - if (Math.abs(newTop - y) <= 5) { | |
| 75 | - this.drawHLine(y) | |
| 76 | - return true | |
| 77 | - } else { | |
| 78 | - this.hLines = [] | |
| 79 | - } | |
| 63 | + // e代表 editingElement | |
| 64 | + const eleft = this.editingElement.commonStyle.left | |
| 65 | + const etop = this.editingElement.commonStyle.top | |
| 66 | + const ewidth = this.editingElement.commonStyle.width | |
| 67 | + const eheight = this.editingElement.commonStyle.height | |
| 68 | + const exCoords = [eleft + ewidth, eleft + (ewidth / 2), eleft] | |
| 69 | + const eyCoords = [etop + eheight, etop + (eheight / 2), etop] | |
| 70 | + let hasVLine = false | |
| 71 | + let hasHLine = false | |
| 72 | + exCoords.forEach(eX => { | |
| 73 | + referElementsXCoords.forEach(referX => { | |
| 74 | + let offset = referX - eX | |
| 75 | + if (Math.abs(offset) <= 5) { | |
| 76 | + if (isPointMove) { | |
| 77 | + this.setElementPosition({ width: ewidth + offset }) | |
| 78 | + } else { | |
| 79 | + this.setElementPosition({ left: eleft + offset }) | |
| 80 | + } | |
| 81 | + this.drawVLine(referX) | |
| 82 | + hasVLine = true | |
| 83 | + } | |
| 84 | + }) | |
| 85 | + }) | |
| 86 | + eyCoords.forEach(eY => { | |
| 87 | + referElementsYCoords.forEach(referY => { | |
| 88 | + let offset = referY - eY | |
| 89 | + if (Math.abs(offset) <= 5) { | |
| 90 | + if (isPointMove) { | |
| 91 | + this.setElementPosition({ height: eheight + offset }) | |
| 92 | + } else { | |
| 93 | + this.setElementPosition({ top: etop + offset }) | |
| 94 | + } | |
| 95 | + this.drawHLine(referY) | |
| 96 | + hasHLine = true | |
| 97 | + } | |
| 98 | + }) | |
| 80 | 99 | }) |
| 100 | + if (!hasVLine) { | |
| 101 | + this.clearVLine() | |
| 102 | + } | |
| 103 | + if (!hasHLine) { | |
| 104 | + this.clearHLine() | |
| 105 | + } | |
| 81 | 106 | }, |
| 82 | 107 | /** |
| 83 | 108 | * #!zh: 在元素移动过程中,计算和生成辅助线 |
| 84 | 109 | */ |
| 85 | 110 | handleElementMove (pos) { |
| 86 | 111 | this.setElementPosition(pos) |
| 87 | - this.calcX(pos.left) | |
| 88 | - this.calcY(pos.top) | |
| 112 | + this.calcVHLine(false) | |
| 89 | 113 | }, |
| 90 | - handlePointMove ({ top, left }) { | |
| 91 | - this.calcX(left) | |
| 92 | - this.calcY(top) | |
| 114 | + handlePointMove (pos) { | |
| 115 | + this.setElementPosition(pos) | |
| 116 | + this.calcVHLine(true) | |
| 93 | 117 | }, |
| 94 | 118 | bindContextMenu (e) { |
| 95 | 119 | // 优化右击菜单的显示,去除冗余的无效逻辑 |
| ... | ... | @@ -185,14 +209,16 @@ export default { |
| 185 | 209 | this.setEditingElement(element) |
| 186 | 210 | }} |
| 187 | 211 | // TODO 矩形四周的点叫什么?暂时叫 Point 吧 |
| 188 | - handlePointMoveProp={pos => { | |
| 189 | - this.setElementPosition(pos) | |
| 190 | - }} | |
| 212 | + handlePointMoveProp={this.handlePointMove} | |
| 191 | 213 | handleElementMoveProp={this.handleElementMove} |
| 192 | 214 | handleElementMouseUpProp={() => { |
| 215 | + this.clearHLine() | |
| 216 | + this.clearVLine() | |
| 193 | 217 | this.recordElementRect() |
| 194 | 218 | }} |
| 195 | 219 | handlePointMouseUpProp={() => { |
| 220 | + this.clearHLine() | |
| 221 | + this.clearVLine() | |
| 196 | 222 | this.recordElementRect() |
| 197 | 223 | }} |
| 198 | 224 | nativeOnContextmenu={e => { | ... | ... |
front-end/h5/src/components/core/editor/index.js
| 1 | 1 | import { mapState, mapActions } from 'vuex' |
| 2 | +import hotkeys from 'hotkeys-js' | |
| 2 | 3 | import undoRedoHistory from '../../../store/plugins/undo-redo/History' |
| 3 | 4 | |
| 4 | 5 | import '../styles/index.scss' |
| ... | ... | @@ -44,58 +45,47 @@ import Feedback from '@/components/common/feedback/index' |
| 44 | 45 | const fixedTools = [ |
| 45 | 46 | { |
| 46 | 47 | i18nTooltip: 'editor.fixedTool.undo', |
| 47 | - 'tooltip': '撤消', // TODO 支持快捷键 | |
| 48 | - 'text': '撤消', | |
| 49 | 48 | 'icon': 'mail-reply', |
| 50 | - 'action': () => undoRedoHistory.undo() | |
| 49 | + 'action': () => undoRedoHistory.undo(), | |
| 50 | + 'hotkey': 'ctrl&z,⌘&z' | |
| 51 | 51 | }, |
| 52 | 52 | { |
| 53 | 53 | i18nTooltip: 'editor.fixedTool.redo', |
| 54 | - 'tooltip': '恢复', | |
| 55 | - 'text': '恢复', | |
| 56 | 54 | 'icon': 'mail-forward', |
| 57 | - 'action': () => undoRedoHistory.redo() | |
| 55 | + 'action': () => undoRedoHistory.redo(), | |
| 56 | + 'hotkey': 'ctrl&y,⌘&u' | |
| 58 | 57 | }, |
| 59 | 58 | { |
| 60 | 59 | i18nTooltip: 'editor.fixedTool.preview', |
| 61 | - 'tooltip': '刷新预览', | |
| 62 | - 'text': '刷新预览', | |
| 63 | 60 | 'icon': 'eye', |
| 64 | 61 | 'action': function () { this.previewVisible = true } |
| 65 | 62 | }, |
| 66 | 63 | { |
| 67 | 64 | i18nTooltip: 'editor.fixedTool.copyCurrentPage', |
| 68 | - 'tooltip': '复制当前页', | |
| 69 | - 'text': '复制当前页', | |
| 70 | 65 | 'icon': 'copy', |
| 71 | - 'action': function () { this.pageManager({ type: 'copy' }) } | |
| 66 | + 'action': function () { this.pageManager({ type: 'copy' }) }, | |
| 67 | + 'hotkey': 'ctrl&c,⌘&c' | |
| 72 | 68 | }, |
| 73 | 69 | { |
| 74 | 70 | i18nTooltip: 'editor.fixedTool.importPSD', |
| 75 | - 'tooltip': '导入PSD', | |
| 76 | - 'text': 'Ps', | |
| 77 | 71 | 'icon': '', |
| 78 | 72 | 'action': '', |
| 79 | 73 | 'disabled': true |
| 80 | 74 | }, |
| 81 | 75 | { |
| 82 | 76 | i18nTooltip: 'editor.fixedTool.zoomOut', |
| 83 | - 'tooltip': '放大画布', | |
| 84 | - 'text': '放大画布', | |
| 85 | 77 | 'icon': 'plus', |
| 86 | - 'action': function () { this.scaleRate += 0.25 } | |
| 78 | + 'action': function () { this.scaleRate += 0.25 }, | |
| 79 | + 'hotkey': 'ctrl&=,⌘&=' | |
| 87 | 80 | }, |
| 88 | 81 | { |
| 89 | 82 | i18nTooltip: 'editor.fixedTool.zoomIn', |
| 90 | - 'tooltip': '缩小画布', | |
| 91 | - 'text': '缩小画布', | |
| 92 | 83 | 'icon': 'minus', |
| 93 | - 'action': function () { this.scaleRate -= 0.25 } | |
| 84 | + 'action': function () { this.scaleRate -= 0.25 }, | |
| 85 | + 'hotkey': 'ctrl&-,⌘&-' | |
| 94 | 86 | }, |
| 95 | 87 | { |
| 96 | 88 | i18nTooltip: 'editor.fixedTool.issues', |
| 97 | - 'tooltip': 'issues', | |
| 98 | - 'text': '常见问题', | |
| 99 | 89 | 'icon': 'question', |
| 100 | 90 | 'action': function () { window.open('https://github.com/ly525/luban-h5/issues/110') } |
| 101 | 91 | } |
| ... | ... | @@ -237,6 +227,15 @@ export default { |
| 237 | 227 | // } |
| 238 | 228 | } |
| 239 | 229 | }, |
| 230 | + mounted () { | |
| 231 | + fixedTools.map(tool => { | |
| 232 | + tool.hotkey && hotkeys(tool.hotkey, { splitKey: '&' }, (event, handler) => { | |
| 233 | + event.preventDefault() | |
| 234 | + event.stopPropagation() | |
| 235 | + tool.action && tool.action.call(this) | |
| 236 | + }) | |
| 237 | + }) | |
| 238 | + }, | |
| 240 | 239 | render (h) { |
| 241 | 240 | return ( |
| 242 | 241 | <a-layout id="luban-editor-layout" style={{ height: '100vh' }}> |
| ... | ... | @@ -340,10 +339,9 @@ export default { |
| 340 | 339 | <a-button-group style={{ display: 'flex', flexDirection: 'column' }}> |
| 341 | 340 | { |
| 342 | 341 | fixedTools.map(tool => ( |
| 343 | - // <a-tooltip effect="dark" placement="left" title={tool.tooltip}> | |
| 344 | 342 | <a-tooltip effect="dark" placement="left" title={this.$t(tool.i18nTooltip)}> |
| 345 | 343 | <a-button block class="transparent-bg" type="link" size="small" style={{ height: '40px', color: '#000' }} onClick={() => tool.action && tool.action.call(this) } disabled={!!tool.disabled}> |
| 346 | - { tool.icon ? <i class={['shortcut-icon', 'fa', `fa-${tool.icon}`]} aria-hidden='true'/> : tool.text } | |
| 344 | + { tool.icon ? <i class={['shortcut-icon', 'fa', `fa-${tool.icon}`]} aria-hidden='true'/> : this.$t(tool.i18nTooltip) } | |
| 347 | 345 | </a-button> |
| 348 | 346 | { tool.icon === 'minus' && <div style={{ fontSize: '12px', textAlign: 'center' }}>{this.scaleRate * 100}%</div> } |
| 349 | 347 | </a-tooltip> | ... | ... |
front-end/h5/yarn.lock
| ... | ... | @@ -5071,6 +5071,11 @@ hosted-git-info@^2.1.4: |
| 5071 | 5071 | resolved "https://registry.npm.taobao.org/hosted-git-info/download/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c" |
| 5072 | 5072 | integrity sha1-dZz88sTRVq3lmwst+r3cQqa5xww= |
| 5073 | 5073 | |
| 5074 | +hotkeys-js@^3.7.6: | |
| 5075 | + version "3.7.6" | |
| 5076 | + resolved "https://registry.npm.taobao.org/hotkeys-js/download/hotkeys-js-3.7.6.tgz#b90ae3453a7be2f2b2bed6ee55cb96443944c77b" | |
| 5077 | + integrity sha1-uQrjRTp74vKyvtbuVcuWRDlEx3s= | |
| 5078 | + | |
| 5074 | 5079 | hpack.js@^2.1.6: |
| 5075 | 5080 | version "2.1.6" |
| 5076 | 5081 | resolved "https://registry.npm.taobao.org/hpack.js/download/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" | ... | ... |