Commit 67b129aef0b73dcb1a988466dbdf72e23c1f62e7

Authored by ly525
Committed by 小小鲁班
1 parent f002c516

feat: support drag&drop element from the left panel to the canvas; !#: 支持从左侧元素列表中拖拽元素至中间画布

front-end/h5/src/components/core/editor/drag-mixin.js 0 → 100644
  1 +/*
  2 + * @Author: ly525
  3 + * @Date: 2020-05-17 17:21:04
  4 + * @LastEditors: ly525
  5 + * @LastEditTime: 2020-05-24 18:09:23
  6 + * @FilePath: /luban-h5/front-end/h5/src/components/core/editor/drag-mixin.js
  7 + * @Github: https://github.com/ly525/luban-h5
  8 + * @Copyright 2018 - 2019 luban-h5. All Rights Reserved
  9 + * @Description:
  10 + * 组件拖拽至画布功能
  11 + * 其中部分代码参考自:https://github.com/hakubox/haku-form-design,已经征得作者同意,目的是后续考虑做 tab 之类的嵌套容器
  12 + */
  13 +
  14 +let dragDom = null
  15 +
  16 +let dragConfig = {
  17 + isPreDrag: false, // 准备拖拽
  18 + isDrag: false, // 正式拖拽
  19 + origin: {
  20 + clientY: 0, // 鼠标按下时候时候值
  21 + clientX: 0,
  22 + layerX: 0, // 鼠标.x 相对于元素左上角.left 的偏移
  23 + layerY: 0 // 鼠标.y 相对于元素左上角.top 的偏移
  24 + }
  25 +}
  26 +
  27 +class Drag {
  28 + constructor (options) {
  29 + this.mousedown = options.mousedown
  30 + this.mousemove = options.mousemove
  31 + this.mouseup = options.mouseup
  32 +
  33 + this._mousedown = this._mousedown.bind(this)
  34 + this._mousemove = this._mousemove.bind(this)
  35 + this._mouseup = this._mouseup.bind(this)
  36 + }
  37 +
  38 + start (e) {
  39 + this._mousedown(e)
  40 + }
  41 +
  42 + _mousedown (e) {
  43 + this.mousedown(e)
  44 + this.toggleListener('add')
  45 + }
  46 +
  47 + _mousemove (e) {
  48 + console.log('mousemove')
  49 + this.mousemove(e)
  50 + }
  51 +
  52 + _mouseup (e) {
  53 + console.log('mouseup')
  54 + this.mouseup(e)
  55 + this.toggleListener('remove')
  56 + }
  57 +
  58 + toggleListener (action) {
  59 + document[`${action}EventListener`]('mousemove', this._mousemove)
  60 + document[`${action}EventListener`]('mouseup', this._mouseup)
  61 + }
  62 +}
  63 +
  64 +export default {
  65 + data () {
  66 + return {
  67 +
  68 + }
  69 + },
  70 + methods: {
  71 + /**
  72 + *
  73 + * @param {*} element
  74 + * @param {*} e
  75 + */
  76 + handleDragStartFromMixin (element, e) {
  77 + // https://developer.mozilla.org/zh-CN/docs/Web/API/event.button
  78 + // 0 为 左键点击.
  79 + if (e.button !== 0) return
  80 + if (dragDom) {
  81 + document.body.removeChild(dragDom)
  82 + dragDom = null
  83 + }
  84 + this.dragElement = element
  85 + dragDom = e.target.cloneNode(true)
  86 + document.body.appendChild(dragDom)
  87 +
  88 + new Drag({
  89 + mousedown: this.mousedown,
  90 + mousemove: this.mousemove,
  91 + mouseup: this.mouseup
  92 + }).start(e)
  93 + },
  94 + /**
  95 + *
  96 + * @param {*} e
  97 + */
  98 + mousedown (e) {
  99 + // 鼠标.x 相对于元素左上角 的偏移
  100 + const { layerX, layerY } = e
  101 + dragConfig.origin.layerX = layerX
  102 + dragConfig.origin.layerY = layerY
  103 + dragConfig.origin.clientX = e.clientX
  104 + dragConfig.origin.clientY = e.clientY
  105 +
  106 + dragDom.style.position = 'absolute'
  107 + dragDom.style.left = e.clientX - layerX + 'px'
  108 + dragDom.style.top = e.clientY - layerY + 'px'
  109 + dragDom.classList.add('dragging-dom-ele', 'hidden')
  110 +
  111 + dragConfig.isPreDrag = true
  112 + },
  113 + /** 组件拖拽中 */
  114 + mousemove (e) {
  115 + dragDom.classList.remove('hidden')
  116 + const { layerX, layerY } = dragConfig.origin
  117 + dragDom.style.left = e.clientX - layerX + 'px'
  118 + dragDom.style.top = e.clientY - layerY + 'px'
  119 + },
  120 + mouseup (e) {
  121 + const { layerX, layerY } = dragConfig.origin
  122 + document.body.removeChild(dragDom)
  123 + dragDom = null
  124 +
  125 + const canvasWrapper = document.querySelector('.canvas-wrapper')
  126 + const position = canvasWrapper.getBoundingClientRect()
  127 + this.dragElement && this.clone({
  128 + ...this.dragElement,
  129 + customStyle: {
  130 + left: e.clientX - layerX - position.left,
  131 + top: e.clientY - layerY - position.top
  132 + }
  133 + })
  134 + }
  135 + },
  136 + updated () {
  137 + console.log('updated')
  138 + }
  139 +}
... ...
front-end/h5/src/components/core/editor/index.js
... ... @@ -22,26 +22,7 @@ import LangSelect from '@/components/common/header/LangSelect.vue'
22 22 import Feedback from '@/components/common/feedback/index'
23 23 import AdjustLineV from '@/components/core/support/adjust-line/vertical'
24 24  
25   -// const sidebarMenus = [
26   -// {
27   -// i18nLabel: 'editor.sidebar.components',
28   -// label: '组件列表',
29   -// value: 'pluginList',
30   -// antIcon: 'bars'
31   -// },
32   -// {
33   -// i18nLabel: 'editor.sidebar.pages',
34   -// label: '页面管理',
35   -// value: 'pageManagement',
36   -// antIcon: 'snippets'
37   -// },
38   -// {
39   -// i18nLabel: 'editor.sidebar.templates',
40   -// label: '免费模板',
41   -// value: 'freeTemplate',
42   -// antIcon: 'appstore'
43   -// }
44   -// ]
  25 +import DragMixin from './drag-mixin'
45 26  
46 27 const fixedTools = [
47 28 {
... ... @@ -103,6 +84,7 @@ const fixedTools = [
103 84 ]
104 85  
105 86 export default {
  87 + mixins: [DragMixin],
106 88 name: 'Editor',
107 89 components: {
108 90 LogoOfHeader,
... ... @@ -184,7 +166,11 @@ export default {
184 166 <strong>{ this.$t('editor.tip.click') }</strong>{ this.$t('editor.tip.click') }
185 167 </i18n>
186 168 </div>
187   - <RenderShortcutsPanel pluginsList={this.pluginsList} handleClickShortcut={this.clone} />
  169 + <RenderShortcutsPanel
  170 + pluginsList={this.pluginsList}
  171 + handleClickShortcut={this.clone}
  172 + handleDragStart={this.handleDragStartFromMixin}
  173 + />
188 174 </a-tab-pane>
189 175 <a-tab-pane key='page-manager' tab={this.$t('editor.sidebar.pages')}>
190 176 <RenderPageManager
... ... @@ -202,46 +188,6 @@ export default {
202 188 </a-tab-pane>
203 189 </a-tabs>
204 190 )
205   - // switch (this.activeMenuKey) {
206   - // case sidebarMenus[0].value:
207   - // return (
208   - // <a-tabs
209   - // style="height: 100%;"
210   - // tabBarGutter={10}
211   - // >
212   - // <a-tab-pane key="plugin-list" tab={this.$t('editor.sidebar.components')}>
213   - // <RenderShortcutsPanel pluginsList={this.pluginsList} handleClickShortcut={this.clone} />
214   - // </a-tab-pane>
215   - // <a-tab-pane key='page-manager' tab={this.$t('editor.sidebar.pages')}>
216   - // <RenderPageManager
217   - // pages={this.pages}
218   - // editingPage={this.editingPage}
219   - // onSelectMenuItem={(menuKey) => {
220   - // this.pageManager({ type: menuKey })
221   - // }}
222   - // onEditTitle={({ pageIndexForEditingTitle, newTitle }) => {
223   - // this.pageManager({ type: 'editTitle', value: { pageIndexForEditingTitle, newTitle } })
224   - // this.saveWork({ isSaveCover: false })
225   - // }}
226   - // onSelectPage={(pageIndex) => { this.setEditingPage(pageIndex) }}
227   - // />
228   - // </a-tab-pane>
229   - // </a-tabs>
230   - // )
231   - // case sidebarMenus[1].value:
232   - // return (
233   - // <RenderPageManager
234   - // pages={this.pages}
235   - // editingPage={this.editingPage}
236   - // onSelectMenuItem={(menuKey) => {
237   - // this.pageManager({ type: menuKey })
238   - // }}
239   - // onSelectPage={(pageIndex) => { this.setEditingPage(pageIndex) }}
240   - // />
241   - // )
242   - // default:
243   - // return null
244   - // }
245 191 }
246 192 },
247 193 mounted () {
... ...
front-end/h5/src/components/core/editor/shortcuts-panel/index.js
... ... @@ -11,6 +11,10 @@ export default {
11 11 },
12 12 handleClickShortcut: {
13 13 type: Function
  14 + },
  15 + handleDragStart: {
  16 + type: Function,
  17 + default: (e) => {}
14 18 }
15 19 },
16 20 data: () => ({
... ... @@ -97,6 +101,7 @@ export default {
97 101 <a-col span={12} style={{ marginTop: '10px' }}>
98 102 <ShortcutButton
99 103 clickFn={this.onClickShortcut.bind(this, plugin)}
  104 + mousedownFn={this.handleDragStart.bind(this, plugin)}
100 105 // title={plugin.title}
101 106 title={plugin.i18nTitle[this.currentLang] || plugin.title}
102 107 faIcon={plugin.icon}
... ...
front-end/h5/src/components/core/styles/index.scss
... ... @@ -52,6 +52,28 @@
52 52 }
53 53 }
54 54  
  55 +.hidden {
  56 + display: none !important;
  57 +}
  58 +
  59 +// 拖拽出来的控件
  60 +.dragging-dom-ele {
  61 + position: fixed !important;
  62 + z-index: 100;
  63 +
  64 + display: inline-block;
  65 + box-sizing: border-box;
  66 +
  67 + height: 30px;
  68 + width: 130px;
  69 + border-radius: 4px;
  70 + border: 1px solid #CCC;
  71 +
  72 + cursor: grabbing;
  73 + user-select: none;
  74 + opacity: 0.6;
  75 +}
  76 +
55 77 .ant-tabs-nav .ant-tabs-tab {
56 78 padding: 12px 0 !important;
57 79 }
... ...