今天给大家搬运的是四角线框hover效果

「先看效果✨✨✨」

「具体实现思路💡💡💡」

1️⃣ 把四角边框看成一个设置定位的遮罩元素,动态设置其widthheightlefttop

2️⃣ 给图片添加鼠标移入事件,然后获取该图片的物理尺寸信息并计算后动态赋值给遮罩元素

「动手试试🚀🚀🚀」

准备几张陈年老图片,简单布局排列起来

js 复制代码
<template>
  <div ref="cssWrapRef" class="css_wrap">
    <div class="css_hover">
      <img
        v-for="(item, index) in imgList"
        :key="index"
        :src="getSrc(index + 1)"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
const imgList = Array.from({ length: 14 });
const cssWrapRef = ref<HTMLDivElement>();
const getSrc = (index: number) => {
  return new URL(`/src/assets/backgroundImg/${index}.jpg`, import.meta.url)
    .href;
};
</script>

<style lang="scss" scoped>
.css_wrap {
  height: 100%;
  overflow: scroll;
  padding: 30px;
  background: #000;
  position: relative;
}
.css_hover {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-gap: 20px 20px;
  grid-auto-flow: dense;
  img {
    width: 100%;
  }
}
</style>

这里我使用grid布局,只要让图片产生间隙好看点就行

「设计遮罩元素⚡⚡⚡」

上面已经简单分析了遮罩元素需要动态设置的属性,除了上面提到的4 个属性外,还需要有一个gap 表示遮罩元素距离图片的空隙以及lineWidth表示四边角的线宽

js 复制代码
<template>
  <div ref="cssWrapRef" class="css_wrap">
    <div class="css_hover">
      <img
        v-for="(item, index) in imgList"
        :key="index"
        :src="getSrc(index + 1)"
      />
    </div>
   <div :style="boxStyle" class="active_box"></div>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
const imgList = Array.from({ length: 14 });
const cssWrapRef = ref<HTMLDivElement>();
const boxLeft = ref(0); //遮罩元素left距离
const boxWidth = ref(0); //遮罩元素宽度
const boxHeigt = ref(0); //遮罩元素高度
const boxTop = ref(0); //遮罩元素top距离
const boxGap = ref(10);//gap距离
const lineWidth = computed(() => {
  return "30px";
});//四边角的线宽
const getSrc = (index: number) => {
  return new URL(`/src/assets/backgroundImg/${index}.jpg`, import.meta.url)
    .href;
};



</script>

<style lang="scss" scoped>
.css_wrap {
  height: 100%;
  overflow: scroll;
  padding: 30px;
  background: #000;
  position: relative;
}
.css_hover {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-gap: 20px 20px;
  grid-auto-flow: dense;
  img {
    width: 100%;
  }
}
.active_box {
  position: absolute;
  transition: all 0.5s;
  cursor: pointer;
  border: 3px solid #fff;
  background: #fff;
}
</style>

接着为img添加鼠标移入事件来确定遮罩元素的位置,这里我们方便观察吧遮罩元素的背景设为白色

js 复制代码
 const handleImgEnter = (e: MouseEvent) => {
  const target = e.target as HTMLImageElement;
  const { width, height, x, y } = target.getBoundingClientRect();
  boxWidth.value = width + 2 * boxGap.value;//遮罩元素宽高比图片大2*gap
  boxHeigt.value = height + 2 * boxGap.value;
  boxLeft.value = x - boxGap.value//保持元素居中;
  boxTop.value = y - boxGap.value;
};

「现在的效果」

「制作四边角」

思路使用渐变先在4个角绘制一个小块,这里我们使用conic-gradient渐变容易绘制

conic-gradient是锥形渐变

background: conic-gradient( at 30px 30px, red 75%, blue 75% ) ;

现在的效果

我们想产生4个角的,就只需要调整一下background-size大小就行了

background: conic-gradient(at 30px 30px, red 75%, blue 75%) 0 0 / calc(100% - 30px) calc(100% - 30px);

「为什么这样就行了?」

把background-repeat属性去掉你就知道了,实际剩余3个角就是背景图片repeat3次

我们把红色背景改为透明的

background: conic-gradient(at 30px 30px, transparent 75%, blue 75%) 0 0 / calc(100% - 30px) calc(100% - 30px);

好了,最后我们把这个背景图片就看成一个遮罩图片,在4个角的地方不透明,然后其余部分透明,把background改成mask就是我们想要的效果了!

bacground=>mask

「所有代码」

js 复制代码
<template>
  <div ref="cssWrapRef" class="css_wrap">
    <div class="css_hover">
      <img
        v-for="(item, index) in imgList"
        :key="index"
        @mouseenter="handleImgEnter"
        @click="handleClick(index)"
        :src="getSrc(index + 1)"
      />
    </div>
    <div :style="boxStyle" class="active_box"></div>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
onMounted(() => {
  window.onresize = () => {
    handleImgEnter(currentEvent.value);
  };
});
const imgList = Array.from({ length: 14 });
const boxGap = ref(10);
const lineWidth = ref('30px');
const boxLeft = ref(0);
const boxWidth = ref(0);
const boxHeigt = ref(0);
const cssWrapRef = ref<HTMLDivElement>();
const boxTop = ref(0);
const currentEvent = ref();
const boxStyle = computed(() => {
  return {
    left: boxLeft.value + "px",
    top: boxTop.value + "px",
    width: boxWidth.value + "px",
    height: boxHeigt.value + "px",
  };
});
const handleClick = (index) => {
  console.log(index);
};
const handleImgEnter = (e: MouseEvent) => {
  currentEvent.value = e;
  const target = e.target as HTMLImageElement;
  const { width, height, x, y } = target.getBoundingClientRect();
  boxWidth.value = width + 2 * boxGap.value;
  boxHeigt.value = height + 2 * boxGap.value;
  boxLeft.value = x - boxGap.value + cssWrapRef.value.scrollLeft;
  boxTop.value = y - boxGap.value + cssWrapRef.value.scrollTop;
};
const getSrc = (index: number) => {
  return new URL(`/src/assets/backgroundImg/${index}.jpg`, import.meta.url)
    .href;
};
</script>

<style lang="scss" scoped>
.css_wrap {
  height: 100%;
  overflow: scroll;
  padding: 30px;
  background: #000;
  position: relative;
}
.css_hover {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-gap: 20px 20px;
  grid-auto-flow: dense;
  img {
    width: 100%;
  }
}
.active_box {
  position: absolute;
  transition: all 0.5s;
  cursor: pointer;
  border: 3px solid #fff;
  mask: conic-gradient(
      at v-bind(lineWidth) v-bind(lineWidth),
      transparent 75%,
      blue 75%
    )
    0 0 / calc(100% - v-bind(lineWidth)) calc(100% - v-bind(lineWidth));
}
</style>

「完结🎉🎉🎉」

如果你觉得这篇文章对你有帮助,欢迎点赞 👍、收藏 ⭐、评论 💬

相关推荐
weixin_382395231 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__1 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.1 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~2 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华3 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子5 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅6 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni6 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学7 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端