当前位置: 首页 > backend >正文

vue3--手写手机屏组件

在这里插入图片描述

<!--* 手机预览* @Author: Hanyang* @Date: 2022-12-09 09:13:00* @LastEditors: Hanyang* @LastEditTime: 2023-01-12 15:37:00
-->
<template><divclass="public-preview-mobile"ref="previewMobileRef":class="showMobile ? 'animation-show-mobile' : 'animation-hide-mobile'":style="{ ...mobileStyle, height: props.height }"><divv-show="showMask"class="priveiew-mask"ref="previewMaskRef"@mousedown="showMask = true"@mouseup="maskDisapear"@mouseleave="maskDisapear"@mousemove="maskMoveFn ? maskMoveFn($event) : () => {}"></div><divclass="switch":title="showMobile ? '点击收起手机' : '点击显示手机'"@click="switchMobile"></div><div class="liu-hair-wrap"><divclass="liu-hair"@mousedown="(showMask = true), (maskMoveFn = mobileMouseMove)"></div></div><divclass="mobile-fixed-container":class="{'fixed-container': props.isFixedContainer,}":style="{ width: props.width }"><divclass="mobile-wrap"@scroll="scrollMobile":class="{'hidden-scroll': !canScroll,}"><divclass="liu-hair-head":style="getStatusBarStyle(isImmersive, statusBarBg)"></div><slot></slot></div></div></div>
</template><script lang="ts" setup>
import { ref, watch } from "vue";
type MobileStatusInfo = "on" | "off";const props = defineProps({isOn: {//手机是否显示type: Boolean,default: true,},isImmersive: {//是否是沉浸式状态栏type: Boolean,default: false,},statusBarBg: {type: String,default: "#fff",},canScroll: {type: Boolean,default: true,},isFixedContainer: {//是否将手机内屏作为position:fixed;的屏幕视口type: Boolean,default: true,},width: {//手机宽度type: String,default: "300px",},height: {//手机高度type: String,default: "600px",},
});
const emit = defineEmits(["scroll"]);const previewMobileRef = ref();
const showMask = ref(false);
const maskMoveFn = ref<any>(null);
const showMobile = ref(true);
const mobileStyle = ref<any>(null);const getStatusBarStyle = (isImmersive: boolean, statusBarBg: string) => {const s: any = {};if (isImmersive == false) {s.background = statusBarBg;}return s;
};
const maskDisapear = () => {showMask.value = false;maskMoveFn.value = null;
};
const mobileMouseMove = (e: MouseEvent) => {const dom = previewMobileRef.value;let x_dis = parseFloat(window.getComputedStyle(dom).right) - e.movementX;let y_dis = parseFloat(window.getComputedStyle(dom).top) + e.movementY;(previewMobileRef.value as any).style.right = x_dis + "px";(previewMobileRef.value as any).style.top = y_dis + "px";showMobile.value = true;
};
const switchMobile = () => {showMobile.value = !showMobile.value;
};
//组件触发事件:删除事件
const scrollMobile = (e: any) => {emit("scroll", e);
};
/*** 外部调用方法:用于组件内鼠标按住移动所要执行的动作* maskMoveFn:执行的动作*/
const maskApear = (fn?: (event: MouseEvent) => void) => {showMask.value = true;if (fn) maskMoveFn.value = fn;
};
/*** 外部调用方法:获取手机状态 on-开机 off-关机*/
const getMobileStatus = (): MobileStatusInfo => {return showMobile.value ? "on" : "off";
};
/*** 外部调用方法:切换手机状态*/
const switchMobileStatus = (status: MobileStatusInfo, style?: any) => {return new Promise((resolve, reject) => {try {if ((status === "on" && showMobile.value) ||(status === "off" && !showMobile.value)) {resolve(1);} else {const dom = previewMobileRef.value as any;dom?.addEventListener("animationend",() => {resolve(1);},{once: true,});switch (status) {case "on":showMobile.value = true;break;case "off":showMobile.value = false;break;default:showMobile.value = true;}if (style) {mobileStyle.value = style;}}} catch (e) {reject(e);}});
};
watch(() => props.isOn,(val: Boolean) => {showMobile.value = !!val;},{ immediate: true }
);
</script>
<style lang="scss">
@use "sass:math";
.public-preview-mobile {cursor: pointer;position: fixed;display: block;top: 180px;right: 10px;z-index: 10;$LH_H: 20px; //刘海高度$M_B: 4px; //手机边框border: $M_B solid #000;border-radius: 12px;height: 600px;@keyframes hide-mobile {from {// top: 0px;}to {top: 97vh;}}@keyframes show-mobile {from {// top: 0px;}to {top: 97vh;}}&.animation-hide-mobile {animation-name: hide-mobile;animation-duration: 0.2s;animation-fill-mode: forwards;filter: brightness(0.2);}&.animation-show-mobile {animation-name: show-mobile;animation-duration: 0.2s;animation-fill-mode: forwards;animation-direction: reverse;}.priveiew-mask {position: fixed;cursor: pointer;z-index: 4023;top: 0;left: 0;right: 0;bottom: 0;}.switch {width: 60px;height: 25px;background: pink;position: absolute;right: 20px;top: -7px;border-radius: 6px;background: #000;transition: all 0.2s;&::before {content: "";position: absolute;top: -16px;left: -8px;right: -8px;bottom: 0px;z-index: 12;}&:hover {top: -9px;}&:active {top: -6px;}}.liu-hair-wrap {position: absolute;height: 20px;width: 36%;overflow: hidden;z-index: 4013;left: 50%;transform: translateX(-50%);margin-top: 0px;.liu-hair {cursor: move;display: inline-block;height: $LH_H;width: 100%;background: #000;border-radius: math.div($LH_H, 2);transform: translateY(-50%);}}.mobile-fixed-container {width: 300px;height: inherit;display: inline-block;overflow: hidden;user-select: none;background: transparent;box-sizing: border-box;&.fixed-container {transform: scale(1);}.mobile-wrap {position: relative;width: inherit;height: inherit;display: inline-block;border: $M_B solid #000;border-radius: 12px;overflow: auto;background: #fff;user-select: none;margin: -$M_B;&::-webkit-scrollbar {width: 2px;/*滚动条宽度*/height: 2px;/*滚动条高度*/cursor: pointer;}scrollbar-width: none;&.hidden-scroll {overflow-y: hidden !important;}.liu-hair-head {position: sticky;top: 0;left: 0px;right: 0px;z-index: 11;height: $LH_H;}}}
}
</style>
http://www.xdnf.cn/news/1683.html

相关文章:

  • 【工具】使用 MCP Inspector 调试服务的完全指南
  • 关于nginx,负载均衡是什么?它能给我们的业务带来什么?怎么去配置它?
  • 服务器的演进与应用:从物理设备到云端革命
  • 前端出现的一些新技术或者升级的技术汇总
  • Git多人协作与企业级开发模型
  • 两段文本比对,高亮出差异部分
  • 【多智能体系统】特点解析与高效组织策略
  • Milvus(6):Collection 管理分区、管理别名
  • 深度解析 Kubernetes 配置管理:如何安全使用 ConfigMap 和 Secret
  • 字典与集合——测试界的黑话宝典与BUG追捕术
  • C语言编程--16.删除链表的倒数第n个节点
  • 触觉智能RK3506核心板,工业应用之RK3506 RT-Linux实时性测试
  • arm64适配系列文章-第九章-arm64环境上sentinel的部署
  • 【mysql】windows mysql命令
  • Verilog 语法 (一)
  • springboot在eclipse里面运行 run as 是Java Application还是 Maven
  • Java面试场景篇:分布式锁的实现与组件详解
  • MCP‌和LangGraph‌结合2
  • 基于Vue3 的 h5监听从左到右手滑返回上一页
  • 开源模型应用落地-语音合成-MegaTTS3-零样本克隆与多语言生成的突破
  • 从工作到娱乐:Codigger Desktop 让桌面环境更智能
  • c#-命名和书写规范
  • k8s基于角色的访问控制(RBAC)
  • GPT-4o最新图像生成完全指南:10大应用场景与提示词模板
  • opencv--图像变换
  • 悟空统计:小而美的网站流量统计工具,免费好用
  • 【金仓数据库征文】从云计算到区块链:金仓数据库的颠覆性创新之路
  • ThreadLocal
  • 医学图像(DICOM数据)读取及显示(横断面、冠状面、矢状面、3D显示)为什么用ITK+VTK,单独用ITK或者VTK能实一样功能吗?
  • centos离线安装ssh