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

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>

相关文章:

  • java Springboot使用扣子Coze实现实时音频对话智能客服
  • dockercompose文件仓库
  • Ubuntu22学习记录
  • 部署本地deepseek并在调用的详细步骤以及解决一些可能出现的问题(Windows,Linux, WSL)
  • 【数据可视化-30】Netflix电影和电视节目数据集可视化分析
  • 【记录手贱bug日常】IDEA 配置vmoptions后打不开,重新安装,删注册表均无用
  • ESP32_IDF_VScode安装多版本共存
  • 解决VSCode每次SSH连接服务器时,都需要下载vscode-server
  • HTML5 详细学习笔记
  • 【AI】基于OllamaSharp与.NET Core API的高效LLM查询实现
  • Wan2.1和HunyuanVideo文生视频模型算法解析与功能体验丨前沿多模态模型开发与应用实战第六期
  • 针对 Spring Boot 应用中常见的查询场景 (例如:分页查询、关联查询、聚合查询) 如何进行 SQL 优化?
  • [论文阅读]REPLUG: Retrieval-Augmented Black-Box Language Models
  • centos离线安装ssh
  • 补4月22日23日
  • Pytorch中的Dataset和DataLoader
  • 倚光科技:微透镜阵列低成本加工新范式
  • 2025最新版扣子(Coze)AI智能体应用指南
  • .NETCore部署流程
  • 【前端】CSS 基础
  • 全国首例!上市公司董监高未履行公开增持承诺,投资者起诉获赔
  • 乐聚创始人:人形机器人当前要考虑泡沫问题,年底或将进入冷静期
  • 潘功胜:央行将实施好适度宽松的货币政策,推动中国经济高质量发展
  • 173.9亿人次!一季度我国交通出行火热
  • 国家发改委:将开展市场准入壁垒清理整治行动
  • 更好发挥汽车产业在扩投资促消费方面的带动作用!陈吉宁调研上海车展