globalTools.vue 7.2 KB

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