Vue3 根据点击位置,实现一个用户头像弹框定位
**开篇:**
在Web开发中,响应式UI设计一直是提升用户体验的关键所在。Vue3以其优秀的响应式机制和简洁的API深受开发者喜爱。本文将详细介绍如何利用Vue3的功能特性,结合DOM事件处理和CSS定位,实现一个可以根据点击位置动态显示用户头像弹框的功能。为了确保文章具有实践指导意义,我们将按照实际操作流程,逐步解析并提供核心代码示例。
---
### **一、搭建Vue3项目与基础布局**
**标题:** 初始化项目与页面结构设定
**内容:**
首先,使用Vue CLI创建一个新的Vue3项目,并在主页面上设置基础布局,包括一个用于触发头像弹框显示的用户头像区域和一个隐藏的弹框组件。
```html
<template>
<div id="app">
<!-- 用户列表或其他包含头像的区域 -->
<div @click="showAvatarPopup($event)">
<img :src="user.avatarUrl" alt="User Avatar" class="avatar" />
</div>
<!-- 头像弹框组件,初始状态为隐藏 -->
<AvatarPopup v-if="isPopupVisible" :position="popupPosition" :user="user" @close="hideAvatarPopup" />
</div>
</template>
<script>
import AvatarPopup from '@/components/AvatarPopup.vue';
export default {
components: {
AvatarPopup,
},
data() {
return {
isPopupVisible: false,
user: { // 示例用户数据
avatarUrl: 'path/to/avatar.jpg',
// 其他用户信息...
},
popupPosition: { x: 0, y: 0 }, // 弹框初始位置
};
},
methods: {
showAvatarPopup(event) {
this.popupPosition={ x: event.clientX, y: event.clientY }; // 获取点击位置
this.isPopupVisible=true; // 显示弹框
},
hideAvatarPopup() {
this.isPopupVisible=false; // 隐藏弹框
},
},
};
</script>
```
### **二、创建并样式化头像弹框组件**
**标题:** 设计并实现自定义的`AvatarPopup`组件
**内容:**
在`AvatarPopup.vue`组件中,我们需要接收传递过来的位置坐标,并使用CSS绝对定位来使弹框跟随鼠标点击位置展示。
```html
<!-- AvatarPopup.vue -->
<template>
<div class="avatar-popup" :style="{ top: position.y + 'px', left: position.x + 'px' }">
<img :src="user.avatarUrl" alt="Popup Avatar" class="popup-avatar" />
<!-- 其他用户信息展示... -->
<button @click="emitClose">关闭</button>
</div>
</template>
<script>
export default {
props: {
position: Object,
user: Object,
},
emits: ['close'],
methods: {
emitClose() {
this.$emit('close');
},
},
};
</script>
<style scoped>
.avatar-popup {
position: absolute;
width: fit-content;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
padding: 1rem;
z-index: 1000; /* 确保弹框位于顶层 */
}
.popup-avatar {
width: 100px;
height: 100px;
object-fit: cover;
}
</style>
```
### **三、优化弹框显示逻辑**
**标题:** 考虑边界情况,确保弹框始终在可视区域内
**内容:**
为了防止弹框超出浏览器窗口范围,我们需要对计算出的弹框位置进行适当的调整:
```javascript
// 在App.vue中的methods内
showAvatarPopup(event) {
const viewportWidth=document.documentElement.clientWidth;
const viewportHeight=document.documentElement.clientHeight;
const popupWidth=document.querySelector('.avatar-popup').offsetWidth;
const popupHeight=document.querySelector('.avatar-popup').offsetHeight;
const x=Math.min(Math.max(event.clientX, popupWidth / 2), viewportWidth - popupWidth / 2);
const y=Math.min(Math.max(event.clientY, popupHeight / 2), viewportHeight - popupHeight / 2);
this.popupPosition={ x, y };
this.isPopupVisible=true;
}
```
### **四、添加过渡动画效果**
**标题:** 使用Vue Transition实现弹框显示/隐藏动画
**内容:**
为了让弹框的出现和消失更加流畅自然,我们可以使用Vue的Transition组件包裹AvatarPopup,为其添加CSS过渡动画。
```html
<!-- App.vue -->
<transition name="fade" appear>
<AvatarPopup v-if="isPopupVisible" :position="popupPosition" :user="user" @close="hideAvatarPopup" />
</transition>
<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity .3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
```
---
**总结:**
通过以上步骤,我们成功地在Vue3项目中实现了根据点击位置动态定位用户头像弹框的功能。这一功能在社交网络、评论区以及其他需要展现用户详细信息的场景中非常实用,既提升了用户体验,也展现了Vue3强大而灵活的应用能力。随着进一步实践,你可以尝试增加更多高级功能,如自动调整弹框方向以适应屏幕边界,或是集成拖拽移动等功能,从而使得弹框组件更为完善和人性化。
最近在做直播后台,涉及到对用户的一些操作,比如关注/取关/禁言/踢出直播间。多个地方都要用,需要封装一个弹框组件
根据 点击事件event参数,来获取位置,根据需要来实际计算位置
获取元素top/left,其实直接用getBoundingClientRect 里的bottom / right 即可
export const getCurrentDialogXY=(event: Event)=> {
const target=event.target as HTMLElement
const { bottom, right }=target.getBoundingClientRect()
return { bottom, right }
}
调用
```js
const avatarHandler=(event: Event)=> {
const { right, bottom }=getCurrentDialogXY(event)
currentX.value=right
currentY.value=bottom
}
传入子组件,在子组件内接收到left/top 重新定位即可
<user-info-dialog
:left="currentX"
:top="currentY"
/>
<div ref="userInfoRef" class="dialog-wrap" :style="{ top: top + 'px', left: left + 'px' }"></div>
通过监听弹框的ref(弹框有显示隐藏逻辑,所以监听弹框的ref即可,然后动态设置位置),
watchEffect(()=> {
const userInfoRefValue=userInfoRef.value
if (userInfoRefValue) {
const offsetHeight=userInfoRefValue.offsetHeight // 获取弹框的高度
const offsetWidth=userInfoRefValue.offsetWidth // 获取元素的宽度
// 不管弹框显示是左侧还是右侧,根据需求 都需要 减去 弹框的高度 - 用户头像高度的一半 进行定位
propTop.value=props.top - offsetHeight - userAvatarWidth.value / 2
// 如果是弹框显示在左侧,需要减去弹框的宽度 - 头像的宽度
if (props.roleEnumType===1) {
propLeft.value=props.left - offsetWidth - userAvatarWidth.value
}
}
})
你会发现,其实我们的整个元素,是直接在根节点上,根常规里的,每个弹框,必须要绑定在循环里,才能做一一对应的关系,怎么不太一样呢? 这里是用到的
vue3中的Teleport:将其插槽内容渲染到 DOM 中的另一个位置 这对于我们层级比较多,做全局定位,脱离当前元素,非常好用!!!
目中经常会出现点击跳转锚点的方法,比如给一个a标签一个href=“#锚点”,然后要跳的锚点给个id=“锚点”,这样就实现简单的跳转,但是这样在url地址栏后面都会出现一个诸如www.csdn.net#锚点,然后你点击给一次后退都是退回上一个选择的锚点url,这里总结一些跳转锚点的方法。
<!DOCTYPE html>
<html>
<head>
<style>
div {
height: 800px;
width: 400px;
border: 2px solid black;
}
h2 {
position: fixed;
margin:50px 500px;
}
</style>
</head>
<body>
<h2>
<a href="#div1">to div1</a>
<a href="#div2">to div2</a>
<a href="#div3">to div3</a>
</h2>
<div id="div1">div1</div>
<div id="div2">div2</div>
<div id="div3">div3</div>
</body>
</html>
这种方法的缺点是点击锚点之后,浏览器的URL会发生变化,如果刷新可能会出现问题。
<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.0.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#div1Link").click(function() {
$("html, body").animate({
scrollTop: $("#div1").offset().top }, {duration: 500,easing: "swing"});
return false;
});
$("#div2Link").click(function() {
$("html, body").animate({
scrollTop: $("#div2").offset().top }, {duration: 500,easing: "swing"});
return false;
});
$("#div3Link").click(function() {
$("html, body").animate({
scrollTop: $("#div3").offset().top }, {duration: 500,easing: "swing"});
return false;
});
});
</script>
注意:运行上面的脚本的之前,先将为锚点增加相应的id,同时去掉href属性。
$("html, body")可以替换为响应的div,如果不起作用,试着给该div增加overflow:scroll属性。
另外,脚本可以进一步优化,自己来试试
这样做的好处是:URL地址不会变,同时点击锚点时会自动响应scroll事件,不需要重新绑定。
缺点是:如果页面复杂的话,偏移值可能会发生变化需要算法辅助。
document.getElementById("divId").scrollIntoView();
比如:
document.querySelector("#roll1").onclick=function(){
document.querySelector("#roll1_top").scrollIntoView(true);
}
这里就是点击id是#roll1的元素可以滚动到id是#roll1_top的地方,这里的#roll1和#roll1_top最好是一一对应的,
这种方法的好处,是URL不会变,同时能够响应相应的scroll事件,不需要算法什么的。代码如下:
<html>
<head>
<title>HTML5_ScrollInToView方法</title>
<meta charset="utf-8">
<script type="text/javascript">
window.onload=function(){
/*
如果滚动页面也是DOM没有解决的一个问题。为了解决这个问题,浏览器实现了一下方法,
以方便开发人员如何更好的控制页面的滚动。在各种专有方法中,HTML5选择了scrollIntoView()
作为标准方法。
scrollIntoView()可以在所有的HTML元素上调用,通过滚动浏览器窗口或某个容器元素,
调用元素就可以出现在视窗中。如果给该方法传入true作为参数,或者不传入任何参数,那么
窗口滚动之后会让调动元素顶部和视窗顶部尽可能齐平。如果传入false作为参数,调用元素
会尽可能全部出现在视口中(可能的话,调用元素的底部会与视口的顶部齐平。)不过顶部
不一定齐平,例如:
//让元素可见
document.forms[0].scrollIntoView();
当页面发生变化时,一般会用这个方法来吸引用户注意力。实际上,为某个元素设置焦点也
会导致浏览器滚动显示获得焦点的元素。
支持该方法的浏览器有 IE、Firefox、Safari和Opera。
*/
document.querySelector("#roll1").onclick=function(){
document.querySelector("#roll_top").scrollIntoView(false);
}
document.querySelector("#roll2").onclick=function(){
document.querySelector("#roll_top").scrollIntoView(true);
}
}
</script>
<style type="text/css">
#myDiv{
height:900px;
background-color:gray;
}
#roll_top{
height:900px;
background-color:green;
color:#FFF;
font-size:50px;
position:relative;
}
#bottom{
position:absolute;
display:block;
left;0;bottom:0;
}
</style>
</head>
<body>
<button id="roll1">scrollIntoView(false)</button>
<button id="roll2">scrollIntoView(true)</button>
<div id="myDiv"></div>
<div id="roll_top">
scrollIntoView(ture)元素上边框与视窗顶部齐平
<span id="bottom">scrollIntoView(false)元素下边框与视窗底部齐平</span>
</div>
</body>
</html>
个人建议使用第四种方法。
*请认真填写需求信息,我们会在24小时内与您取得联系。