<!--* 手机预览* @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>
vue3--手写手机屏组件
2025/4/26 3:49:23
来源:https://blog.csdn.net/weixin_39256994/article/details/140547528
浏览:
次
关键词:vue3--手写手机屏组件
版权声明:
本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。
我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com
-
蜜罐管理和数据收集服务器:Modern Honey Network (MHN)
-
IT人力外包定义-优势-服务流程介绍
-
基于javaweb的SSM+Maven红酒朔源管理系统设计与实现(源码+文档+部署讲解)
热文排行
- 华为 海思22AP10(SS524)H.265 编解码处理器用户指南
- 数据库物理结构设计
- 基于重要抽样的主动学习不平衡分类方法ALIS
- 《缺失MRI模态下的脑肿瘤分割的潜在相关表示学习》| 文献速递-深度学习肿瘤自动分割
- npm install puppeteer 报错 npm ERR! PUPPETEER_DOWNLOAD_HOST is deprecated解决办法
- 如何在 Mac 上清空硬盘后恢复丢失的数据?
- 开源模型时代的 AI 开发革命:Dify 技术深度解析
- (2)Django生产环境数据库的切换以及环境配置python-dotenv方案
- 【微信小程序】自定义组件 - 组件的生命周期
- 概率图模型在自然语言处理中的应用
最新新闻
- 蜜罐管理和数据收集服务器:Modern Honey Network (MHN)
- Excel 实现文本拼接方法
- 2025蓝桥杯python A组省赛 题解
- IT人力外包定义-优势-服务流程介绍
- Docker入门
- 升级Oracle SQLcl
- Vue 90 ,Element 13 ,Vue + Element UI 中 el-switch 使用小细节解析,避免入坑(获取后端的数据类型自动转变)
- 如何从 Keycloak 的 keycloak-themes.jar 中提取原生主题并自定义设置
- 【SQL Server】华中农业大学空间数据库实验报告 实验一 数据库
- Python制作动态颜色变换:颜色渐变动效
推荐新闻
- 蜜罐管理和数据收集服务器:Modern Honey Network (MHN)
- Excel 实现文本拼接方法
- 2025蓝桥杯python A组省赛 题解
- IT人力外包定义-优势-服务流程介绍
- Docker入门
- 升级Oracle SQLcl
- Vue 90 ,Element 13 ,Vue + Element UI 中 el-switch 使用小细节解析,避免入坑(获取后端的数据类型自动转变)
- 如何从 Keycloak 的 keycloak-themes.jar 中提取原生主题并自定义设置
- 【SQL Server】华中农业大学空间数据库实验报告 实验一 数据库
- Python制作动态颜色变换:颜色渐变动效