globalTools.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. <!--
  2. * @FileDescription: 公用工具 - 【白板/批注】
  3. * @Author: 王新雷
  4. * @Date:2024年10月14日10:03:11
  5. -->
  6. <template>
  7. <div class="globalTools" :class="[isPlay ? 'isPlay' : '', isHidden ? 'isHidden' : '']">
  8. <div class="mask" v-if="isMask"></div>
  9. <div :class="['iconTools', toolOpen ? 'hideTools' : '']" ref="iconToolsDom">
  10. <img @click="openTool" src="@/img/layout/icon-tool.png" />
  11. </div>
  12. <div :class="['expendTools', toolOpen ? 'showTools' : '']" ref="expendToolsDom">
  13. <img @click="openType('note')" src="@/img/layout/icon-note.png" />
  14. <img @click="openType('whiteboard')" class="iconWhiteboard" src="@/img/layout/icon-whiteboard.png" />
  15. <img @click="openTool" class="iconArrow" src="@/img/layout/g-arrow-right.png" />
  16. </div>
  17. </div>
  18. <pen
  19. :close="
  20. () => {
  21. penShow = false
  22. isHidden = false
  23. }
  24. "
  25. v-model="penShow"
  26. />
  27. <pen
  28. :is-white="true"
  29. :close="
  30. () => {
  31. whitePenShow = false
  32. isHidden = false
  33. }
  34. "
  35. v-model="whitePenShow"
  36. />
  37. </template>
  38. <script setup lang="ts">
  39. import { baseSize, baseWidth, size } from "@/libs/rem"
  40. import pen from "@/views/coursewarePlay/components/pen"
  41. import { toolOpen, whitePenShow, penShow, isPlay, isHidden } from "./globalTools"
  42. import { onMounted, onUnmounted, ref, watch } from "vue"
  43. import { useRoute } from "vue-router"
  44. const isMask = ref(false) // 是否显示遮罩层,为了处理云教练里面拖动不了的问题
  45. const route = useRoute()
  46. watch(
  47. () => route.path,
  48. () => {
  49. handleStatus()
  50. }
  51. )
  52. const iconToolsDom = ref<HTMLDivElement>()
  53. const expendToolsDom = ref<HTMLDivElement>()
  54. function openTool() {
  55. if (isLock) return
  56. toolOpen.value = !toolOpen.value
  57. }
  58. function openType(type: "note" | "whiteboard") {
  59. if (isLock) return
  60. if (type === "note") {
  61. penShow.value = true
  62. isHidden.value = true
  63. } else if (type === "whiteboard") {
  64. whitePenShow.value = true
  65. isHidden.value = true
  66. }
  67. }
  68. function handleStatus() {
  69. isHidden.value = route.path === "/login" ? true : false
  70. }
  71. function computePos(type: "width" | "height", value: number | string) {
  72. const clientNum = type == "width" ? baseWidth : document.documentElement.clientHeight
  73. return typeof value === "string"
  74. ? {
  75. pos:
  76. type == "width"
  77. ? ((clientNum - (parseInt(value) / 100) * clientNum) / 2 / baseSize).toFixed(5)
  78. : (clientNum - (parseInt(value) / 100) * clientNum) / 2,
  79. unit: value
  80. }
  81. : {
  82. pos: type == "width" ? ((clientNum - value) / 2 / baseSize).toFixed(5) : (clientNum - value * (size / baseSize)) / 2,
  83. unit: (value / baseSize).toFixed(5) + "rem"
  84. }
  85. }
  86. /* 拖拽还没有兼容rem */
  87. let isLock = false
  88. let toolMoveY = 0 // 移动的距离
  89. function drag(el: HTMLElement) {
  90. function mousedown(e: MouseEvent) {
  91. e.stopPropagation()
  92. e.preventDefault()
  93. isLock = false
  94. isMask.value = true
  95. const parentElement = el
  96. const parentElementRect = parentElement.getBoundingClientRect()
  97. const downX = e.clientX
  98. const downY = e.clientY
  99. // const clientWidth = document.documentElement.clientWidth
  100. const clientHeight = document.documentElement.clientHeight
  101. // const minLeft = 0
  102. const minTop = 0
  103. // const maxLeft = clientWidth - parentElementRect.width
  104. const maxTop = clientHeight - parentElementRect.height
  105. function onMousemove(e: MouseEvent) {
  106. // let moveX = parentElementRect.left + (e.clientX - downX)
  107. let moveY = parentElementRect.top + (e.clientY - downY)
  108. // let moveY = e.clientY - downY
  109. // moveX = moveX < minLeft ? minLeft : moveX > maxLeft ? maxLeft : moveX
  110. moveY = moveY < minTop ? minTop : moveY > maxTop ? maxTop : moveY
  111. toolMoveY = moveY
  112. document.documentElement.style.setProperty("--toolTranslateY", `${moveY}px`)
  113. // 计算移动的距离
  114. const cX = e.clientX - downX
  115. const cY = e.clientY - downY
  116. // 如果移动距离超过一定阈值,则认为是拖动
  117. if (Math.abs(cX) > 3 || Math.abs(cY) > 3) {
  118. isLock = true // 设置为拖动状态
  119. }
  120. }
  121. function onMouseup() {
  122. document.removeEventListener("mousemove", onMousemove)
  123. document.removeEventListener("mouseup", onMouseup)
  124. isMask.value = false
  125. }
  126. document.addEventListener("mousemove", onMousemove)
  127. document.addEventListener("mouseup", onMouseup)
  128. }
  129. el.addEventListener("mousedown", mousedown, true)
  130. }
  131. //重新计算位置 居中
  132. function refreshPos() {
  133. const posHeight = computePos("height", iconToolsDom.value?.clientHeight || 0)
  134. if (iconToolsDom.value) {
  135. document.documentElement.style.setProperty("--toolTranslateY", `${posHeight.pos}px`)
  136. }
  137. }
  138. let rect: any
  139. function onResize() {
  140. rect = rect ? rect : iconToolsDom.value?.getBoundingClientRect()
  141. const clientHeight = document.documentElement.clientHeight
  142. const maxTop = clientHeight - rect.height
  143. if (toolMoveY >= maxTop) {
  144. document.documentElement.style.setProperty("--toolTranslateY", `${maxTop}px`)
  145. }
  146. }
  147. onMounted(() => {
  148. drag(iconToolsDom.value!)
  149. drag(expendToolsDom.value!)
  150. refreshPos()
  151. window.addEventListener("resize", onResize)
  152. })
  153. onUnmounted(() => {
  154. window.removeEventListener("resize", onResize)
  155. })
  156. </script>
  157. <style lang="scss" scoped>
  158. .globalTools {
  159. &.isPlay {
  160. .iconTools,
  161. .expendTools {
  162. opacity: $opacity-disabled;
  163. }
  164. }
  165. &.isHidden {
  166. .iconTools,
  167. .expendTools {
  168. opacity: 0;
  169. display: none;
  170. }
  171. }
  172. .mask {
  173. position: fixed;
  174. left: 0;
  175. right: 0;
  176. top: 0;
  177. bottom: 0;
  178. background-color: transparent;
  179. z-index: 2998;
  180. }
  181. .iconTools,
  182. .expendTools {
  183. position: fixed;
  184. right: -6px;
  185. top: 0;
  186. transform: translateY(var(--toolTranslateY));
  187. // margin-top: -29px;
  188. z-index: 2999;
  189. // padding: 0 5px;
  190. background: rgba(0, 0, 0, 0.4);
  191. border-radius: 200px 0px 0px 200px;
  192. border: 2px solid rgba(255, 255, 255, 0.3);
  193. border-right-width: 0;
  194. cursor: pointer;
  195. font-size: 0;
  196. // transition: transform 0.2s ease;
  197. img {
  198. padding: 8px 15px;
  199. width: 34px;
  200. height: 34px;
  201. box-sizing: content-box;
  202. -moz-user-select: none;
  203. /* 火狐浏览器 */
  204. -webkit-user-drag: none;
  205. /* 谷歌、Safari和Opera浏览器 */
  206. -webkit-user-select: none;
  207. /* 谷歌、Safari和Opera浏览器 */
  208. -ms-user-select: none;
  209. /* IE10+浏览器 */
  210. user-select: none;
  211. /* 通用 */
  212. -webkit-touch-callout: none;
  213. /* iOS Safari */
  214. &:hover {
  215. opacity: $opacity-hover;
  216. }
  217. }
  218. }
  219. .iconTools {
  220. // transition-delay: 0.2s;
  221. }
  222. .expendTools {
  223. // transform: translateX(100%);
  224. display: none;
  225. img {
  226. cursor: pointer;
  227. }
  228. .iconWhiteboard {
  229. // margin: 0 30px;
  230. }
  231. .iconArrow {
  232. padding: 7px 15px;
  233. width: 28px;
  234. height: 28px;
  235. }
  236. }
  237. .hideTools {
  238. // transition: transform 0.2s ease;
  239. transform: translateY(var(--toolTranslateY));
  240. display: none;
  241. }
  242. .showTools {
  243. // transition: transform 0.2s ease;
  244. // transition-delay: 0.2s;
  245. transform: translateY(var(--toolTranslateY));
  246. display: flex;
  247. align-items: center;
  248. }
  249. }
  250. </style>