ソースを参照

编辑器-导航:做出场景和分组的拖拽视觉效果

任一存 3 年 前
コミット
d810aa726a

+ 65 - 0
packages/code/src/components/insertPositionTipInEditor.vue

@@ -0,0 +1,65 @@
+<template>
+  <div
+    class="insert-position-tip"
+    @dragenter="onDragEnterMarginPlaceholder"
+    @dragover="onDragOverMarginPlaceholder"
+    @dragleave="onDragLeaveMarginPlaceHolder"
+    @drop="onDropInMarginPlaceHolder"
+    :style="{
+      marginLeft: marginLeft,
+    }"
+  >
+    {{positionDebug}}
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    positionDebug: {
+      type: String,
+      default: '',
+    },
+    level: {
+      type: Number,
+      default: 1,
+    },
+  },
+  computed: {
+    marginLeft() {
+      return (this.level - 1) * 12 + 'px' 
+    },
+  },
+  methods: {
+    onDragEnterMarginPlaceholder(e) {
+      e.preventDefault()
+      e.target.style.backgroundColor = '#0076f6'
+      e.dataTransfer.dropEffect = 'move'
+    },
+    onDragOverMarginPlaceholder(e) {
+      e.preventDefault()
+      e.dataTransfer.dropEffect = 'move'
+    },
+    onDragLeaveMarginPlaceHolder(e) {
+      // e.preventDefault()
+      e.target.style.backgroundColor = ''
+    },
+    onDropInMarginPlaceHolder(e) {
+      // e.preventDefault()
+      e.target.style.backgroundColor = ''
+    }
+  }
+}
+</script>
+
+<style lang="less" scoped>
+.insert-position-tip {
+  height: 1px;
+  box-sizing: content-box;
+  padding-top: 3px;
+  padding-bottom: 3px;
+  background-clip: content-box;
+  color: transparent;
+  // background-color: red;
+}
+</style>

+ 54 - 16
packages/code/src/components/sceneGroupInEditor.vue

@@ -1,9 +1,14 @@
 <template>
-  <div class="scene-group">
+  <div
+    class="scene-group"
+  >
     <div
       class="top-bar"
       :class="isConfirmingDeletion ? '' : 'show-icons-on-hover'"
       @click="onClickTopBar"
+      @dragstart=onDragStartSceneGroup
+      @dragenter="onDragEnterSceneGroup"
+      draggable="true"
       :style="{
         paddingLeft: topBarPaddingLeft,
       }"
@@ -73,6 +78,10 @@
 
     <div class="group-content" v-if="isExpanded">
       <template v-if="!(groupNode.children.length === 1 && groupNode.children[0].name === '默认二级分组')">
+        <InsertPositionTip
+          position-debug="1"
+          :level="level + 1"
+        ></InsertPositionTip>
         <div
           v-for="(item) of groupNode.children"
           :key=item.id
@@ -87,7 +96,7 @@
             @renameGroup="onInnerGroupRename"
             @deleteGroup="onInnerGroupConfirmDelete"
           />
-          <SceneInGroupInEditor
+          <SceneInGroup
             v-else
             :style="{
               paddingLeft: sceneItemPaddingLeft,
@@ -96,25 +105,40 @@
             @rename="onRenameScene"
             @delete="onDeleteScene"
           />
+          <InsertPositionTip
+            position-debug="2"
+            :level="level + 1"
+          ></InsertPositionTip>
         </div>
       </template>
       <template v-else>
         <!-- 自动生成的默认二级分组不显示,里边的内容显示成直属于一级分组的效果。 -->
-        <SceneInGroupInEditor
+        <InsertPositionTip
+          position-debug="3"
+          :level="level + 1"
+        ></InsertPositionTip>
+        <div
           v-for="(item) of groupNode.children[0].children"
           :key=item.id
-          :style="{
-            paddingLeft: sceneItemPaddingLeft,
-          }"
-          :sceneInfo="item"
-          @rename="onRenameScene"
-          @delete="onDeleteScene"
-        />
+        >
+          <SceneInGroup
+            :style="{
+              paddingLeft: sceneItemPaddingLeft,
+            }"
+            :sceneInfo="item"
+            @rename="onRenameScene"
+            @delete="onDeleteScene"
+          />
+          <InsertPositionTip
+            position-debug="4"
+            :level="level + 1"
+          ></InsertPositionTip>
+        </div>
       </template>
     </div>
 
     <div class="dialog" style="z-index: 2000" v-if="isShowSelectionWindow">
-      <MaterialSelectorForEditor
+      <MaterialSelector
         title="选择素材"
         @cancle="isShowSelectionWindow = false"
         @submit="onSubmitFromMaterialSelector"
@@ -127,15 +151,17 @@
 </template>
 
 <script>
-import SceneInGroupInEditor from "@/components/sceneInGroupInEditor.vue";
-import MaterialSelectorForEditor from "@/components/materialSelectorForEditor.vue";
+import SceneInGroup from "@/components/sceneInGroupInEditor.vue";
+import MaterialSelector from "@/components/materialSelectorForEditor.vue";
+import InsertPositionTip from "@/components/insertPositionTipInEditor.vue";
 import { mapGetters } from "vuex";
 
 export default {
   name: 'SceneGroup',
   components: {
-    SceneInGroupInEditor,
-    MaterialSelectorForEditor,
+    SceneInGroup,
+    MaterialSelector,
+    InsertPositionTip,
   },
   props: {
     groupNode: {
@@ -280,6 +306,17 @@ export default {
         this.$msg.success("操作成功")
       }
     },
+    onDragStartSceneGroup(e) {
+      e.dataTransfer.setData("application/target-type", `scene-group-${this.level}`)
+      e.dataTransfer.setData("application/target-id", this.groupNode.id)
+      // e.dataTransfer.setDragImage(e.target.children[1], -10, -18)
+    },
+    onDragEnterSceneGroup(e) {
+      if (!this.isExpanded) {
+        this.isExpanded = true
+        this.$bus.emit('scene-group-expanded', this.groupNode.id, this.level)
+      }
+    },
   },
   mounted() {
     this.$bus.on('scene-group-expanded', this.onOtherSceneGroupExpanded)
@@ -292,7 +329,6 @@ export default {
 
 <style lang="less" scoped>
 .scene-group {
-  margin-top: 6px;
   .top-bar {
     position: relative;
     color: rgba(255, 255, 255, 0.6);
@@ -423,5 +459,7 @@ export default {
       }
     }
   }
+  .group-content {
+  }
 }
 </style>

+ 13 - 2
packages/code/src/components/sceneInGroupInEditor.vue

@@ -2,8 +2,15 @@
   <div
     class="scene-item"
     :class="isConfirmingDeletion ? '' : 'not-confirming-deletion'"
+    @dragstart="onDragStart"
+    draggable="true"
   >
-    <img :src="sceneInfo.icon + ossImagePreviewUrlSuffix()" alt="" class="scene-image">
+    <img
+      :src="sceneInfo.icon + ossImagePreviewUrlSuffix()"
+      alt=""
+      class="scene-image"
+      draggable="false"
+    >
     <div class="right">
       <span v-if="!isRenaming" class="scene-title" v-title="sceneInfo.sceneTitle">{{sceneInfo.sceneTitle}}</span>
       <input
@@ -62,6 +69,11 @@ export default {
     }
   },
   methods: {
+    onDragStart(e) {
+      e.dataTransfer.setData("application/target-type", `scene`)
+      e.dataTransfer.setData("application/target-id", this.sceneInfo.id)
+      e.dataTransfer.setDragImage(e.target.children[0], -10, -18)
+    },
     ossImagePreviewUrlSuffix,
     translateSceneType(type) {
       if (type === 'pano') {
@@ -102,7 +114,6 @@ export default {
 <style lang="less" scoped>
 .scene-item {
   position: relative;
-  margin-top: 6px;
   margin-left: -12px;
   margin-right: -10px;
   padding-right: 10px;

+ 16 - 0
packages/code/src/directives/vTitleInEditor.js

@@ -73,5 +73,21 @@ Vue.directive('title', {
         document.body.removeChild(titleNode)
       }
     })
+    el.addEventListener('dragstart', function () {
+      if (!isShowTitle) {
+        clearTimeout(timerId)
+      } else {
+        isShowTitle = false
+        document.body.removeChild(titleNode)
+      }
+    })
+    el.addEventListener('dragleave', function () {
+      if (!isShowTitle) {
+        clearTimeout(timerId)
+      } else {
+        isShowTitle = false
+        document.body.removeChild(titleNode)
+      }
+    })
   },
 })

+ 21 - 0
packages/code/src/directives/vTooltipInEditor.js

@@ -102,5 +102,26 @@ Vue.directive('tooltip', {
         console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
       }
     })
+    el.addEventListener('dragstart', function () {
+      try {
+        document.body.removeChild(tooltipNode)
+      } catch(e) {
+        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
+      }
+    })
+    el.addEventListener('dragstart', function () {
+      try {
+        document.body.removeChild(tooltipNode)
+      } catch(e) {
+        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
+      }
+    })
+    el.addEventListener('dragleave', function () {
+      try {
+        document.body.removeChild(tooltipNode)
+      } catch(e) {
+        console.log('尝试从DOM上移除tooltip元素失败,通常是因为已经在其他回调中被移除了,不需处理:', e);
+      }
+    })
   },
 })

+ 16 - 12
packages/code/src/views/navigation/groupSettings.vue

@@ -12,17 +12,22 @@
     </button>
 
     <div class="scene-group-wrap">
-      <SceneGroupInEditor
+      <InsertPositionTip position-debug="-1"></InsertPositionTip>
+      <div
         v-for="(item) of catalogTopology"
         :key=item.id
-        :groupNode="item"
-        :level="1"
-        @addGroup="onRequestForAddGroupLevel2"
-        @renameScene="onRenameScene"
-        @deleteScene="onDeleteScene"
-        @renameGroup="onRenameGroup"
-        @deleteGroup="onDeleteGroup"
-      />
+      >
+        <SceneGroupInEditor
+          :groupNode="item"
+          :level="1"
+          @addGroup="onRequestForAddGroupLevel2"
+          @renameScene="onRenameScene"
+          @deleteScene="onDeleteScene"
+          @renameGroup="onRenameGroup"
+          @deleteGroup="onDeleteGroup"
+        />
+        <InsertPositionTip position-debug="0"></InsertPositionTip>
+      </div>
     </div>
     <popup v-if="addGroupLevel" :canClose="false">
       <div class="ui-message ui-message-confirm dark add-group-window">
@@ -59,18 +64,17 @@
 </template>
 
 <script>
-import draggable from "vuedraggable";
 import SceneGroupInEditor from "@/components/sceneGroupInEditor.vue";
 import { mapGetters } from "vuex";
 import { deepClone } from "@/utils/other.js";
 import Popup from "@/components/shared/popup/index.vue";
+import InsertPositionTip from "@/components/insertPositionTipInEditor.vue";
 
 export default {
   components: {
-    draggable,
     SceneGroupInEditor,
     Popup,
-
+    InsertPositionTip,
   },
   computed: {
     ...mapGetters({