放大镜原理 以及Vue+TypeScrip封装一个原生放大镜组件

本文介绍了如何在Vue项目中利用TypeScript封装一个原生放大镜组件,包括放大镜的工作原理、代码实现及关键属性的使用方法,为开发者提供了一个实用的开发参考。
摘要由CSDN通过智能技术生成

一图解释放大镜原理 以及 Vue+TypeScrip封装原生放大镜组件

效果图

放大镜动画

背景介绍

开发中需要一个放大镜功能,但翻遍内外网没有找到符合需求的放大镜组件,一些知名的组件库也没找到合适的组件,于是自己研究了一番放大镜的原理写了个组件。

放大镜的原理

假设放大比例为X,那么一张100 × 110的图片(称为小图),放大之后的图片(称为大图)就是x100 × x110, 那么,所谓的放大镜功能只是将,用户在小图范围内选中的阴影范围,在大图里面将按照x比例放大的大图框移动到成x比例移动的距离位置处即可这个大图框部分展示的大图的内容就是小图里面用户选定的范围放大的部分

放大镜原理图

代码以及注释

  1. 使用组件的方法
import MagnifyLens from './components/MagnifyLens.vue'<MagnifyLens :imgs :imgWidth="300" :imgHeight="300" :borderStyle="'1px solid red'" :scale="3"/>
//	这几个属性依次是 放大镜里面存放的图片数组(元素有src以及name属性), 小图的宽度(px)、小图的高度(px)、小图边框的样式、放大的比例
  1. 放大镜组件(MagnifyLens.vue)
<style scoped lang="scss">
.page-preview{
 display: flex;
 flex-direction: column;
 gap: 5px;
 .top-preview {
   border: 1px solid;
   position: relative;
   height: calc(100% - 30px);
   width: 100%;

   & > .event {
     position: absolute;
     width: 100%;
     height: 100%;
     top: 0;
     left: 0;
     z-index: 998;
   }

   > img {
     width: 100%;
     height: 100%;
   }

   > .mask {
     position: absolute;
     background-color: rgba(148, 152, 148, 0.3);
     left: 0;
     top: 0;
     display: none;
   }

   > .big {
     position: absolute;
     width: 100%;
     height: 100%;
     top: -1px;
     left: 102%;
     overflow: hidden;
     z-index: 998;
     display: none;

     > img {
       position: absolute;
       left: 0;
       top: 0;
       display: block;
     }
   }

   &:hover > .mask, &:hover > .big {
     display: block;
   }
 }
 .bottom-preview {
   height: 30px;
   display: flex;
   align-items: stretch;
   .a{
     width: 15px;
     border: solid 1px rgba(211, 211, 211, 0.41);
     display: flex;
     align-items: center;
     justify-content: center;
   }
   .ul {
     width: calc(100% - 30px);
     display: flex;
     gap: 5%;
     flex-wrap: nowrap;
     overflow-x: hidden;
     border-top: 1px solid gray;
     border-bottom: 1px solid gray;
     .li{
       flex: 0 0 100%;
       display: flex;
       justify-content: center;
       align-items: center;
     }
   }
 }
}
</style>

<template>
 <div class="page-preview" :style="{width: props.imgWidth+'px', height: props.imgHeight+'px'}">
   <div class="top-preview" :style="{border: props.borderStyle}">
     <!-- 底图层 -->
     <img :src="props.imgs[selectImgIdx].src"/>
     <!-- 事件层监听层,透明,用于监听鼠标移动事件,其内不设置子元素,因为如果有子元素,子元素也有自己的mousemove事件,其事件会冒泡到父元素中 -->
     <div class="event" @mousemove="magnify" ref="eventMask"></div>
     <!-- 遮罩层,灰色,用来模拟鼠标悬浮时的选定范围效果 -->
     <div class="mask" :style="{width: 100 / props.scale + '%', height: 100 / props.scale + '%'}" ref="mask"></div>
     <!-- 显示放大的图片 -->
     <div class="big">
       <img :style="{width: props.scale * 100 + '%', height: props.scale * 100 + '%'}" :src="props.imgs[selectImgIdx].src" ref="big"/>
     </div>
   </div>
   <div class="bottom-preview">
     <button class="a" @click="moveImg(true)">
       <span>&lt;</span>
     </button>
     <div class="ul" ref="ul">
       <span class="li">{{props?.imgs[selectImgIdx]?.name || '商品名称'}}</span>
     </div>
     <button class="a"  @click="moveImg(false)">
       <span>&gt;</span>
     </button>
   </div>
 </div>
</template>

<script setup lang="ts">
import {defineProps, ref} from 'vue';

const props = defineProps({
 imgs: {
   type: Array,
   required: true
 },
 imgWidth: {
   required: false,
   type: Number,
   default: 200
 },
 imgHeight: {
   required: false,
   type: Number,
   default: 400
 },
 borderStyle: {
   required: false,
   type: String,
   default: 'none'
 },
 scale: {
   required: false,
   type: Number,
   default: 2
 }
});

const selectImgIdx = ref(0);
const mask = ref(null);
const big = ref(null);
const eventMask = ref(null);

// 1. 缩略图的逻辑(小图里面小图框的位置(x和y)对应大图框在完整大图框的位置(x1和y1))
const magnify = function (event) {
 //计算遮罩的左值以及顶部的值
 let left = event.offsetX - mask.value.offsetWidth / 2
 let top = event.offsetY - mask.value.offsetHeight / 2
 if (left < 0) {
   //判断按照当前left绘制的小阴影框超出小图左边的情况, 小图遮罩对于小图的x偏移量<0,则说明: 现在计算出来的小图遮罩位置小图遮罩已经移出小图左侧外了,把小图遮罩设置成贴着左边
   left = 0
 } else if (left > (eventMask.value.offsetWidth - mask.value.offsetWidth)) {
   //判断按照当前left绘制的小阴影框超出小图右边的情况, 小图遮罩对于小图的x偏移量>(遮罩宽度 - 遮罩宽度),则说明: 现在计算出来的小图遮罩位置已经移出小图右侧外了,把小图遮罩设置成贴着右边
   left = eventMask.value.offsetWidth - mask.value.offsetWidth;
 }
 if (top < 0) {
   top = 0
 } else if (top > (eventMask.value.offsetHeight - mask.value.offsetHeight)) {
   top = eventMask.value.offsetHeight - mask.value.offsetHeight;
 }
 //将遮罩以及big图赋值定位  (此外big图为普通图的两倍大小 且方位为负值)
 mask.value.style.left = left + 'px';
 mask.value.style.top = top + 'px';
 big.value.style.left = -props.scale * left + 'px';
 big.value.style.top = -props.scale * top + 'px';
}

// 2. 左右无限切换图片的逻辑
function moveImg(isPre:boolean){
 if (isPre) {
   // 向左点击
   selectImgIdx.value = (selectImgIdx.value + props.imgs?.length - 1) % props.imgs?.length;
 } else {
   // 向右点击
   selectImgIdx.value = (selectImgIdx.value + props.imgs?.length + 1) % props.imgs?.length;
 }
}
</script>

tip: 推荐一个gif录制工具 screenToGif, 关注微信公众号【编程同行人】,回复【rj0-01】获取。

声明:文章内容均为原创,转载请注明出处,如有错误或晦涩的地方欢迎在下方评论区指正和讨论。欢迎移步我的微信公众号【编程同行人】,我也会在公众号上分享其他的一些提升编程效率的工具以及实际生产开发中的心得总结。

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue和Element可以一起使用来封装一个选人弹窗。首先,我们需要使用Vue框架来构建弹窗组件,然后使用Element UI库来实现弹窗的样式和组件。 在Vue中,我们可以使用组件的方式来封装选人弹窗。首先,我们需要创建一个组件文件,命名为"selectUserModal.vue"。然后,在该组件中,我们可以使用Element UI的Modal组件作为弹窗容器,使用Form组件和Table组件等来展示选择人员的界面。 在"selectUserModal.vue"中,我们可以定义一个data属性来存储选择的人员信息,以及一个visible属性来控制弹窗的显示和隐藏。我们还可以定义一些方法来处理用户的选择操作,如确定选择和取消选择等。 在弹窗的界面中,我们可以使用Form组件来展示与人员选择相关的输入框,如搜索框和筛选条件等。然后,在表格中展示人员列表,可以使用Table组件,并绑定数据源和列定义。 为了实现人员选择操作,我们可以提供一个确认按钮,当用户点击确认按钮时,我们可以触发一个自定义事件,并将选择的人员信息作为参数进行传递。其他的操作,如点击表格行即选中人员,我们也可以在相应的方法中进行处理。 当组件完成后,我们可以在其他Vue页面中引用该组件,并传递参数来控制弹窗的显示。通过监听自定义事件,我们可以在父组件中获取到选择的人员信息,并进行相应的操作。 总结起来,通过Vue和Element的配合,我们可以封装一个选人弹窗组件,使其能在Vue项目中方便地使用,并具有良好的交互和样式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值