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

tooltip改为基于floating-ui和js dom操作实现

任一存 3 лет назад
Родитель
Сommit
19b695a86d

+ 27 - 0
package-lock.json

@@ -8,6 +8,7 @@
       "name": "code2.6",
       "version": "0.1.0",
       "dependencies": {
+        "@floating-ui/dom": "^0.5.4",
         "core-js": "^3.8.2",
         "element-ui": "^2.15.1",
         "html2canvas": "^1.4.1",
@@ -1280,6 +1281,19 @@
         "to-fast-properties": "^2.0.0"
       }
     },
+    "node_modules/@floating-ui/core": {
+      "version": "0.7.3",
+      "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-0.7.3.tgz",
+      "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="
+    },
+    "node_modules/@floating-ui/dom": {
+      "version": "0.5.4",
+      "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-0.5.4.tgz",
+      "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==",
+      "dependencies": {
+        "@floating-ui/core": "^0.7.3"
+      }
+    },
     "node_modules/@hapi/address": {
       "version": "2.1.4",
       "resolved": "https://registry.npm.taobao.org/@hapi/address/download/@hapi/address-2.1.4.tgz?cache=0&sync_timestamp=1603524710662&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40hapi%2Faddress%2Fdownload%2F%40hapi%2Faddress-2.1.4.tgz",
@@ -20569,6 +20583,19 @@
         "to-fast-properties": "^2.0.0"
       }
     },
+    "@floating-ui/core": {
+      "version": "0.7.3",
+      "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-0.7.3.tgz",
+      "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="
+    },
+    "@floating-ui/dom": {
+      "version": "0.5.4",
+      "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-0.5.4.tgz",
+      "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==",
+      "requires": {
+        "@floating-ui/core": "^0.7.3"
+      }
+    },
     "@hapi/address": {
       "version": "2.1.4",
       "resolved": "https://registry.npm.taobao.org/@hapi/address/download/@hapi/address-2.1.4.tgz?cache=0&sync_timestamp=1603524710662&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40hapi%2Faddress%2Fdownload%2F%40hapi%2Faddress-2.1.4.tgz",

+ 1 - 0
package.json

@@ -11,6 +11,7 @@
     "lint": "vue-cli-service lint"
   },
   "dependencies": {
+    "@floating-ui/dom": "^0.5.4",
     "core-js": "^3.8.2",
     "element-ui": "^2.15.1",
     "html2canvas": "^1.4.1",

+ 5 - 12
src/components/materialSelectorForEditor.vue

@@ -173,16 +173,11 @@
     <div class="btns">
       <button class="ui-button upload-btn">
         <span>上传素材</span>
-        <i class="iconfont icon-material_prompt tool-tip-for-editor" v-tool-tip-wrapper>
-          <TooltipInEditor
-            :text="
-              currentMaterialType === 'image' ? '请上传10MB以内、jpg/png格式的图片' :
-              currentMaterialType === 'pano' ? '请上传2:1、120MB以内、jpg格式的图片' :
-              ''
-            "
-            :frameCenterPos="'30px'"
-            :arrowCenterPos="'calc(50% - 24px)'"
-          ></TooltipInEditor>
+        <i class="iconfont icon-material_prompt tool-tip-for-editor"
+          v-tooltip="
+            currentMaterialType === 'image' ? '请上传10MB以内、jpg/png格式的图片' :
+            currentMaterialType === 'pano' ? '请上传2:1、120MB以内、jpg格式的图片' : ''
+          ">
         </i>
       </button>
       <div>
@@ -200,7 +195,6 @@ import { getMaterialList} from "@/api";
 import { changeByteUnit } from '@/utils/file'
 import config from "@/config";
 import { debounce } from "@/utils/other.js"
-import TooltipInEditor from '@/components/TooltipInEditor.vue'
 
 export default {
   props:{
@@ -228,7 +222,6 @@ export default {
     },
   },
   components:{
-    TooltipInEditor,
   },
   watch:{
     searchKey: {

+ 4 - 18
src/components/sceneGroupInEditor.vue

@@ -15,38 +15,26 @@
         <span class="group-name" v-title="groupNode.name">{{groupNode.name}}</span>
         <i v-show="level === 1"
           class="iconfont icon-editor_list_add icon-add"
-          v-tool-tip-wrapper
+          v-tooltip="'新增二级分组'"
           @click="onRequestForAddGroup"
         >
-          <TooltipInEditor
-            :text="'新增二级分组'"
-          ></TooltipInEditor>
         </i>
         <i
           class="iconfont icon-editor_list_image icon-image"
-          v-tool-tip-wrapper
+          v-tooltip="'新增全景图或三维场景'"
         >
-          <TooltipInEditor
-            :text="'新增全景图或三维场景'"
-          ></TooltipInEditor>
         </i>
         <i
           class="iconfont icon-editor_list_edit icon-edit"
-          v-tool-tip-wrapper
+          v-tooltip="'重命名'"
           @click="onClickForRename"
         >
-          <TooltipInEditor
-            :text="'重命名'"
-          ></TooltipInEditor>
         </i>
         <i
           class="iconfont icon-editor_list_delete icon-delete"
-          v-tool-tip-wrapper
+          v-tooltip="'删除'"
           @click.stop="onRequestForDelete"
         >
-          <TooltipInEditor
-            :text="'删除'"
-          ></TooltipInEditor>
         </i>
         <div class="deletion-confirm-wrap">
           <div class="deletion-confirm" :class="isConfirmingDeletion ? 'show' : 'hide'"
@@ -111,13 +99,11 @@
 </template>
 
 <script>
-import TooltipInEditor from '@/components/TooltipInEditor.vue'
 import SceneInGroupInEditor from "@/components/sceneInGroupInEditor.vue";
 
 export default {
   name: 'SceneGroup',
   components: {
-    TooltipInEditor,
     SceneInGroupInEditor,
   },
   props: {

+ 2 - 10
src/components/sceneInGroupInEditor.vue

@@ -16,19 +16,13 @@
       <div class="right-bottom">
         <span class="scene-type">{{translateSceneType(sceneInfo.type)}}</span>
         <div class="icons">
-          <i class="iconfont icon-editor_list_edit icon-edit" v-tool-tip-wrapper
+          <i class="iconfont icon-editor_list_edit icon-edit" v-tooltip="'重命名'"
             @click="onRequestForRename"
           >
-            <TooltipInEditor
-              :text="'重命名'"
-            ></TooltipInEditor>
           </i>
-          <i class="iconfont icon-editor_list_delete icon-delete" v-tool-tip-wrapper
+          <i class="iconfont icon-editor_list_delete icon-delete" v-tooltip="'删除'"
             @click="onRequestForDelete"
           >
-            <TooltipInEditor
-              :text="'删除'"
-            ></TooltipInEditor>
           </i>
         </div>
       </div>
@@ -45,13 +39,11 @@
 </template>
 
 <script>
-import TooltipInEditor from '@/components/TooltipInEditor.vue'
 import { ossImagePreviewUrlSuffix } from '@/utils/other.js'
 
 export default {
   name: 'SceneInGroupInEditor', 
   components: {
-    TooltipInEditor,
   },
   props: {
     sceneInfo: {

+ 0 - 16
src/directives/vToolTipWrapper.js

@@ -1,16 +0,0 @@
-import Vue from 'vue'
-
-Vue.directive('tool-tip-wrapper', {
-  bind: function (el, binding) {
-    el.style.position = 'relative'
-    let tooltipWrapper = el.querySelector('.tooltip-wrapper')
-    if (tooltipWrapper) {
-      el.addEventListener('mouseenter', function () {
-        tooltipWrapper.style.display = 'block'
-      })
-      el.addEventListener('mouseleave', function () {
-        tooltipWrapper.style.display = 'none'
-      })
-    }
-  }
-})

+ 81 - 0
src/directives/vTooltip.js

@@ -0,0 +1,81 @@
+import Vue from 'vue'
+import {computePosition, offset, flip, shift, arrow} from '@floating-ui/dom';
+ 
+Vue.directive('tooltip', {
+  bind: function (el, binding) {
+    if (!binding.value) {
+      return
+    }
+    let tooltipNode = null
+    el.addEventListener('mouseenter', function(e) {
+      tooltipNode = document.createElement('div')
+      tooltipNode.style.position = 'fixed'
+      tooltipNode.style.zIndex = 100
+      tooltipNode.style.backgroundColor = '#191A1C'
+      tooltipNode.style.border = '1px solid rgba(151, 151, 151, 0.2)'
+      tooltipNode.style.borderRadius = '3px'
+      tooltipNode.style.border = '1px solid rgba(151, 151, 151, 0.2)'
+      tooltipNode.style.boxShadow = '0px 2px 12px 0px rgba(0, 0, 0, 0.06)'
+      tooltipNode.style.padding = '8px 8px'
+      tooltipNode.style.fontSize = '12px'
+      tooltipNode.style.cursor = 'default'
+      tooltipNode.style.pointerEvents = 'none'
+      tooltipNode.style.wordBreak = 'keep-all'
+      tooltipNode.style.whiteSpace = 'pre'
+      tooltipNode.style.fontSize = '12px'
+      tooltipNode.style.lineHeight = '17px'
+      tooltipNode.style.color = 'rgba(255, 255, 255, 0.6)'
+      tooltipNode.innerText = binding.value
+
+      const arrowNode = document.createElement('div')
+      arrowNode.style.position = 'absolute'
+      arrowNode.style.backgroundColor = 'inherit'
+      arrowNode.style.boxSizing = 'border-box'
+      arrowNode.style.width = '12px'
+      arrowNode.style.height = '12px'
+      arrowNode.style.border = '1px solid transparent'
+      arrowNode.style.borderRight = 'inherit'
+      arrowNode.style.borderBottom = 'inherit'
+      arrowNode.style.transform = 'rotate(45deg)'
+      
+      tooltipNode.appendChild(arrowNode)
+      document.body.appendChild(tooltipNode)
+
+      computePosition(el, tooltipNode, {
+        placement: 'top',
+        middleware: [
+          offset(13),
+          flip(),
+          shift({padding: 12}),
+          arrow({
+            element: arrowNode,
+            padding: 3,
+          }),
+        ],
+      }).then(({x, y, placement, middlewareData}) => {
+        Object.assign(tooltipNode.style, {
+          left: `${x}px`,
+          top: `${y}px`,
+        });
+
+        const {x: arrowX, y: arrowY} = middlewareData.arrow;
+        const staticSide = {
+          top: 'bottom',
+          right: 'left',
+          bottom: 'top',
+          left: 'right',
+        }[placement.split('-')[0]];
+       
+        Object.assign(arrowNode.style, {
+          left: arrowX != null ? `${arrowX}px` : '',
+          [staticSide]: '-6px',
+        });
+      });
+    }, {
+      passive: false,
+    })
+    el.addEventListener('mouseleave', function () {
+      document.body.removeChild(tooltipNode)
+    })
+  },
+})

+ 1 - 1
src/pages/edit.js

@@ -6,7 +6,7 @@ import store from '../Store'
 import 'viewerjs/dist/viewer.css'
 import Viewer from 'v-viewer'
 import '@/directives/vTitle.js'
-import '@/directives/vToolTipWrapper.js'
+import '@/directives/vTooltip.js'
 
 Vue.use(Viewer,{
   defaultOptions: {

+ 4 - 18
src/views/base/customButtonSettings.vue

@@ -3,10 +3,7 @@
     <span class="title">自定义按钮</span>
 
 
-    <i class="iconfont icon-material_prompt tool-tip-for-editor" v-tool-tip-wrapper>
-      <TooltipInEditor
-        :text="'自定义按钮可为作品添加联系方式或网站链接等,设置可见后即可在作品显示。'"
-      ></TooltipInEditor>
+    <i class="iconfont icon-material_prompt tool-tip-for-editor" v-tooltip="'自定义按钮可为作品添加联系方式或网站链接等,设置可见后即可在作品显示。'">
     </i>
     <br/>
     
@@ -27,37 +24,28 @@
           <i
             class="iconfont icon-editor_list_edit btn-edit"
             @click="onRequestForEdit(index)"
-            v-tool-tip-wrapper
+            v-tooltip="'编辑'"
           >
-            <TooltipInEditor
-              :text="'编辑'"
-            ></TooltipInEditor>
           </i>
           <div
             class="btn-show"
             v-show="info.customButton[index].value && info.customButton[index].isShow"
-            v-tool-tip-wrapper
+            v-tooltip="'显示'"
           >
             <img
               class="eye-on" :src="require('@/assets/images/icons/eye_on.png')" alt=""
               @click="info.customButton[index].isShow = !info.customButton[index].isShow"
             >
-            <TooltipInEditor
-              :text="'显示'"
-            ></TooltipInEditor>
           </div>
           <div
             class="btn-hide"
             v-show="info.customButton[index].value && !info.customButton[index].isShow"
-            v-tool-tip-wrapper
+            v-tooltip="'隐藏'"
           >
             <img
               class="eye-off" :src="require('@/assets/images/icons/eye_off.png')" alt=""
               @click="info.customButton[index].isShow = !info.customButton[index].isShow"
             >
-            <TooltipInEditor
-              :text="'隐藏'"
-            ></TooltipInEditor>
           </div>
         </div>
       </div>
@@ -139,14 +127,12 @@
 
 <script>
 import { mapGetters } from "vuex";
-import TooltipInEditor from '@/components/TooltipInEditor.vue'
 import PulldownMenuInEditor from "@/components/pulldownMenuInEditor.vue";
 import { isValidPhoneNumber } from "@/utils/other.js";
 import Popup from "@/components/shared/popup/index.vue";
 
 export default {
   components: {
-    TooltipInEditor,
     PulldownMenuInEditor,
     Popup,
   },

+ 1 - 6
src/views/base/customMaskSettings.vue

@@ -1,10 +1,7 @@
 <template>
   <div class="custom-mask-settings">
     <span class="title">遮罩设置</span>
-    <i class="iconfont icon-material_prompt tool-tip-for-editor" v-tool-tip-wrapper>
-      <TooltipInEditor
-        :text="'天空遮罩显示在场景的顶部,地面遮罩显示在场景的底部。'"
-      ></TooltipInEditor>
+    <i class="iconfont icon-material_prompt tool-tip-for-editor" v-tooltip="'天空遮罩显示在场景的顶部,地面遮罩显示在场景的底部。'">
     </i>
     <br>
     <div class="image-selection">
@@ -56,7 +53,6 @@
 </template>
 
 <script>
-import TooltipInEditor from '@/components/TooltipInEditor.vue'
 import MaterialSelectorForEditor from "@/components/materialSelectorForEditor.vue";
 import { mapGetters } from "vuex";
 import SelectedImage from "@/components/selectedImageInEditor.vue";
@@ -64,7 +60,6 @@ import { getUserInfo } from "@/api";
 
 export default {
   components: {
-    TooltipInEditor,
     MaterialSelectorForEditor,
     SelectedImage,
   },

+ 1 - 6
src/views/base/openingTipSettings.vue

@@ -1,10 +1,7 @@
 <template>
   <div class="opening-tip-settings">
     <span class="title">提示设置</span>
-    <i class="iconfont icon-material_prompt tool-tip-for-editor" v-tool-tip-wrapper>
-      <TooltipInEditor
-        :text="'开场提示仅适用于全景图。若初始场景为三维模\n型,以下开场提示不适用。'"
-      ></TooltipInEditor>
+    <i class="iconfont icon-material_prompt tool-tip-for-editor" v-tooltip="'开场提示仅适用于全景图。若初始场景为三维模\n型,以下开场提示不适用。'">
     </i>
     <br>
     <div class="image-selection">
@@ -57,7 +54,6 @@
 </template>
 
 <script>
-import TooltipInEditor from '@/components/TooltipInEditor.vue'
 import MaterialSelectorForEditor from "@/components/materialSelectorForEditor.vue";
 import { mapGetters } from "vuex";
 import Switcher from "@/components/shared/Switcher";
@@ -66,7 +62,6 @@ import SelectedImage from "@/components/selectedImageInEditor.vue";
 
 export default {
   components: {
-    TooltipInEditor,
     MaterialSelectorForEditor,
     Switcher,
     RangeItem,

+ 1 - 8
src/views/navigation/groupSettings.vue

@@ -1,12 +1,7 @@
 <template>
   <div class="group-settings">
     <div class="ui-title-big">场景导航
-      <i class="iconfont icon-material_prompt tool-tip-for-editor" v-tool-tip-wrapper>
-        <TooltipInEditor
-          :text="'场景素材包括全景图和三维场景,您可自定义分组及场景的排列顺序。'"
-          :frameCenterPos="'172px'"
-          :arrowCenterPos="'29px'"
-        />
+      <i class="iconfont icon-material_prompt tool-tip-for-editor" v-tooltip="'场景素材包括全景图和三维场景,您可自定义分组及场景的排列顺序。'">
       </i>
     </div>
     <button class="ui-button create-group-btn"
@@ -178,7 +173,6 @@
 </template>
 
 <script>
-import TooltipInEditor from '@/components/TooltipInEditor.vue'
 import tabList from "@/components/tablist/index.vue";
 import browser from "@/utils/browser";
 import draggable from "vuedraggable";
@@ -189,7 +183,6 @@ import Popup from "@/components/shared/popup/index.vue";
 
 export default {
   components: {
-    TooltipInEditor,
     draggable,
     tabList,
     SceneGroupInEditor,

+ 1 - 8
src/views/navigation/initialSceneSettings.vue

@@ -2,12 +2,7 @@
   <div class="initial-scene-settings" app-border dir-left>
     <div class="initial-scene-settings__title">
       初始场景
-      <i class="iconfont icon-material_prompt tool-tip-for-editor" v-tool-tip-wrapper>
-        <TooltipInEditor
-          :text="'初始场景为查看链接时进入的第一个场景,未设\n置时,不固定从某一场景打开。'"
-          :frameCenterPos="'-100px'"
-          :arrowCenterPos="'240px'"
-        ></TooltipInEditor>
+      <i class="iconfont icon-material_prompt tool-tip-for-editor" v-tooltip="'初始场景为查看链接时进入的第一个场景,未设\n置时,不固定从某一场景打开。'">
       </i>
     </div>
     <div class="preview">
@@ -47,12 +42,10 @@
 <script>
 import { mapGetters } from "vuex";
 import Select from "@/components/select";
-import TooltipInEditor from '@/components/TooltipInEditor.vue'
 
 export default {
   components:{
     Select,
-    TooltipInEditor,
   },
   data(){
     return {