123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- <!--
- * @FileDescription: 公用工具 - 【白板/批注】
- * @Author: 王新雷
- * @Date:2024年10月14日10:03:11
- -->
- <template>
- <div class="globalTools" :class="[isPlay ? 'isPlay' : '', isHidden ? 'isHidden' : '']">
- <div class="mask" v-if="isMask"></div>
- <div :class="['iconTools', toolOpen ? 'hideTools' : '']" ref="iconToolsDom">
- <img @click="openTool" src="@/img/layout/icon-tool.png" />
- </div>
- <div :class="['expendTools', toolOpen ? 'showTools' : '']" ref="expendToolsDom">
- <img @click="openType('note')" src="@/img/layout/icon-note.png" />
- <img @click="openType('whiteboard')" class="iconWhiteboard" src="@/img/layout/icon-whiteboard.png" />
- <img @click="openTool" class="iconArrow" src="@/img/layout/g-arrow-right.png" />
- </div>
- </div>
- <pen
- :close="
- () => {
- penShow = false
- isHidden = false
- }
- "
- v-model="penShow"
- />
- <pen
- :is-white="true"
- :close="
- () => {
- whitePenShow = false
- isHidden = false
- }
- "
- v-model="whitePenShow"
- />
- </template>
- <script setup lang="ts">
- import { baseSize, baseWidth, size } from "@/libs/rem"
- import pen from "@/views/coursewarePlay/components/pen"
- import { toolOpen, whitePenShow, penShow, isPlay, isHidden } from "./globalTools"
- import { onMounted, onUnmounted, ref, watch } from "vue"
- import { useRoute } from "vue-router"
- const isMask = ref(false) // 是否显示遮罩层,为了处理云教练里面拖动不了的问题
- const route = useRoute()
- watch(
- () => route.path,
- () => {
- handleStatus()
- }
- )
- const iconToolsDom = ref<HTMLDivElement>()
- const expendToolsDom = ref<HTMLDivElement>()
- function openTool() {
- if (isLock) return
- toolOpen.value = !toolOpen.value
- }
- function openType(type: "note" | "whiteboard") {
- if (isLock) return
- if (type === "note") {
- penShow.value = true
- isHidden.value = true
- } else if (type === "whiteboard") {
- whitePenShow.value = true
- isHidden.value = true
- }
- }
- function handleStatus() {
- isHidden.value = route.path === "/login" ? true : false
- }
- function computePos(type: "width" | "height", value: number | string) {
- const clientNum = type == "width" ? baseWidth : document.documentElement.clientHeight
- return typeof value === "string"
- ? {
- pos:
- type == "width"
- ? ((clientNum - (parseInt(value) / 100) * clientNum) / 2 / baseSize).toFixed(5)
- : (clientNum - (parseInt(value) / 100) * clientNum) / 2,
- unit: value
- }
- : {
- pos: type == "width" ? ((clientNum - value) / 2 / baseSize).toFixed(5) : (clientNum - value * (size / baseSize)) / 2,
- unit: (value / baseSize).toFixed(5) + "rem"
- }
- }
- /* 拖拽还没有兼容rem */
- let isLock = false
- let toolMoveY = 0 // 移动的距离
- function drag(el: HTMLElement) {
- function mousedown(e: MouseEvent | TouchEvent) {
- const isTouchEv = isTouchEvent(e)
- const event = isTouchEv ? e.touches[0] : e
- isLock = false
- isMask.value = true
- const parentElement = el
- const parentElementRect = parentElement.getBoundingClientRect()
- const downX = event.clientX
- const downY = event.clientY
- // const clientWidth = document.documentElement.clientWidth
- const clientHeight = document.documentElement.clientHeight
- // const minLeft = 0
- const minTop = 0
- // const maxLeft = clientWidth - parentElementRect.width
- const maxTop = clientHeight - parentElementRect.height
- function onMousemove(e: MouseEvent | TouchEvent) {
- const event = isTouchEvent(e) ? e.touches[0] : e
- // let moveX = parentElementRect.left + (e.clientX - downX)
- let moveY = parentElementRect.top + (event.clientY - downY)
- // let moveY = e.clientY - downY
- // moveX = moveX < minLeft ? minLeft : moveX > maxLeft ? maxLeft : moveX
- moveY = moveY < minTop ? minTop : moveY > maxTop ? maxTop : moveY
- toolMoveY = moveY
- document.documentElement.style.setProperty("--toolTranslateY", `${moveY}px`)
- // 计算移动的距离
- const cX = event.clientX - downX
- const cY = event.clientY - downY
- // 如果移动距离超过一定阈值,则认为是拖动
- if (Math.abs(cX) > 3 || Math.abs(cY) > 3) {
- isLock = true // 设置为拖动状态
- }
- }
- function onMouseup() {
- document.removeEventListener(isTouchEv ? "touchmove" : "mousemove", onMousemove)
- document.removeEventListener(isTouchEv ? "touchend" : "mouseup", onMouseup)
- isMask.value = false
- }
- document.addEventListener(isTouchEv ? "touchmove" : "mousemove", onMousemove)
- document.addEventListener(isTouchEv ? "touchend" : "mouseup", onMouseup)
- }
- el.addEventListener("mousedown", mousedown)
- el.addEventListener("touchstart", mousedown)
- }
- function isTouchEvent(e: MouseEvent | TouchEvent): e is TouchEvent {
- return window.TouchEvent && e instanceof window.TouchEvent
- }
- //重新计算位置 居中
- function refreshPos() {
- const posHeight = computePos("height", iconToolsDom.value?.clientHeight || 0)
- if (iconToolsDom.value) {
- document.documentElement.style.setProperty("--toolTranslateY", `${posHeight.pos}px`)
- }
- }
- let rect: any
- function onResize() {
- rect = rect ? rect : iconToolsDom.value?.getBoundingClientRect()
- const clientHeight = document.documentElement.clientHeight
- const maxTop = clientHeight - rect.height
- if (toolMoveY >= maxTop) {
- document.documentElement.style.setProperty("--toolTranslateY", `${maxTop}px`)
- }
- }
- onMounted(() => {
- drag(iconToolsDom.value!)
- drag(expendToolsDom.value!)
- refreshPos()
- window.addEventListener("resize", onResize)
- })
- onUnmounted(() => {
- window.removeEventListener("resize", onResize)
- })
- </script>
- <style lang="scss" scoped>
- .globalTools {
- &.isPlay {
- .iconTools,
- .expendTools {
- opacity: $opacity-disabled;
- }
- }
- &.isHidden {
- .iconTools,
- .expendTools {
- opacity: 0;
- display: none;
- }
- }
- .mask {
- position: fixed;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
- background-color: transparent;
- z-index: 2998;
- }
- .iconTools,
- .expendTools {
- position: fixed;
- right: -6px;
- top: 0;
- transform: translateY(var(--toolTranslateY));
- // margin-top: -29px;
- z-index: 2999;
- // padding: 0 5px;
- background: rgba(0, 0, 0, 0.4);
- border-radius: 200px 0px 0px 200px;
- border: 2px solid rgba(255, 255, 255, 0.3);
- border-right-width: 0;
- cursor: pointer;
- font-size: 0;
- // transition: transform 0.2s ease;
- img {
- padding: 8px 15px;
- width: 34px;
- height: 34px;
- box-sizing: content-box;
- -moz-user-select: none;
- /* 火狐浏览器 */
- -webkit-user-drag: none;
- /* 谷歌、Safari和Opera浏览器 */
- -webkit-user-select: none;
- /* 谷歌、Safari和Opera浏览器 */
- -ms-user-select: none;
- /* IE10+浏览器 */
- user-select: none;
- /* 通用 */
- -webkit-touch-callout: none;
- /* iOS Safari */
- &:hover {
- opacity: $opacity-hover;
- }
- }
- }
- .iconTools {
- // transition-delay: 0.2s;
- }
- .expendTools {
- // transform: translateX(100%);
- display: none;
- img {
- cursor: pointer;
- }
- .iconWhiteboard {
- // margin: 0 30px;
- }
- .iconArrow {
- padding: 7px 15px;
- width: 28px;
- height: 28px;
- }
- }
- .hideTools {
- // transition: transform 0.2s ease;
- transform: translateY(var(--toolTranslateY));
- display: none;
- }
- .showTools {
- // transition: transform 0.2s ease;
- // transition-delay: 0.2s;
- transform: translateY(var(--toolTranslateY));
- display: flex;
- align-items: center;
- }
- }
- </style>
|