今天给大家搬运的是四角线框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>

「完结🎉🎉🎉」

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

相关推荐
智算菩萨2 分钟前
基于spaCy的英文自然语言处理系统:低频词提取与高级文本分析
前端·javascript·easyui
老华带你飞3 分钟前
个人网盘管理|基于springboot + vue个人网盘管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端
刘一说13 分钟前
Vue单页应用(SPA)开发全解析:从原理到最佳实践
前端·javascript·vue.js
疯狂成瘾者14 分钟前
前端vue核心知识点
前端·javascript·vue.js
Laravel技术社区1 小时前
用PHP8实现斗地主游戏,实现三带一,三带二,四带二,顺子,王炸功能(第二集)
前端·游戏·php
m0_738120722 小时前
应急响应——知攻善防Web-3靶机详细教程
服务器·前端·网络·安全·web安全·php
我是小路路呀9 小时前
element级联选择器:已选中一个二级节点,随后又点击了一个一级节点(仅浏览,未确认选择),此时下拉框失去焦点并关闭
javascript·vue.js·elementui
程序员爱钓鱼9 小时前
Node.js 编程实战:文件读写操作
前端·后端·node.js
PineappleCoder9 小时前
工程化必备!SVG 雪碧图的最佳实践:ID 引用 + 缓存友好,无需手动算坐标
前端·性能优化
JIngJaneIL10 小时前
基于springboot + vue古城景区管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端