You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

244 lines
6.5 KiB

<template>
<transition name="fade">
<div v-if="visible" :class="['position-message', type, position]" id="qq" :style="positionStyle">
<!-- <i :class="iconClass"></i>/ -->
<img :src="defaultImages[type]" class="message-image" />
<span>{{ message }}</span>
</div>
</transition>
</template>
<script>
export default {
props: {
type: {
type: String,
default: 'info',
validator: val => ['info', 'success', 'error'].includes(val)
},
position: {
type: String,
default: 'top',
validator: val => ['top', 'bottom'].includes(val)
},
message: String,
target: null, // 目标元素/DOM选择器
offset: {
type: Number,
default: 10
}
},
data() {
return {
visible: false,
positionStyle: {},
defaultImages:{
success: require('@/assets/message_Success.png'),
info: require('@/assets/message_Warning.png'),
warning: require('@/assets/message_Warning.png'),
error: require('@/assets/message_error.png')
}
}
},
computed: {
iconClass() {
return {
info: 'el-icon-info',
success: 'el-icon-success',
error: 'el-icon-error'
}[this.type]
}
},
methods: {
show() {
this.visible = true
this.$nextTick(() => {
this.calculatePosition(); // 确保 DOM 更新后计算
});
console.log('zoulma???????', this.visible);
return this // 支持链式调用
},
hide() {
this.visible = false
},
calculatePosition() {
const targetEl = typeof this.target === 'string'
? document.querySelector(this.target)
: this.target?.$el || this.target;
if (!targetEl?.getBoundingClientRect) {
console.error('Invalid target:', this.target);
return;
}
const targetRect = targetEl.getBoundingClientRect();
const messageWidth = this.$el.offsetWidth;
const viewportWidth = window.innerWidth;
const messageHeight = this.$el.offsetHeight;
// 默认居中位置
let left = targetRect.left + targetRect.width / 2 - messageWidth / 2;
let top = 0;
// 边界检测
if (left < 0) {
left = targetRect.left; // 左侧贴边
} else if (left + messageWidth > viewportWidth) {
left = viewportWidth - messageWidth - (viewportWidth -targetRect.right); // 右侧贴边
}
if(this.position == 'top'){
top =`${targetRect.top + window.scrollY - this.offset - messageHeight}px`
}else{
top = `${targetRect.top + window.scrollY + this.offset + messageHeight}px`
}
this.positionStyle = {
top,
left: `${left}px`,
right: 'auto', // 清除 right 定位
};
},
},
}
</script>
<style scoped lang="scss">
.position-message {
position: absolute;
min-width: 100px;
padding: 14px 21px;
border-radius: 4px;
z-index: 9999;
display: flex;
align-items: center;
background: #FFFFFF;
box-sizing: border-box;
box-shadow: 0px 3px 8px 0px rgba(0, 0, 0, 0.16);
span{
letter-spacing: 0.08em;
color: #626573;
}
}
.message-image {
width: 18px;
height: 18px;
margin-right: 10px;
}
.position-message i {
margin-right: 6px;
font-size: 16px;
}
.position-message.info {
/* background-color: #f4f4f5;
color: #909399;
border: 1px solid #e9e9eb; */
}
.position-message.success {
/* background-color: #f0f9eb;
color: #67c23a;
border: 1px solid #e1f3d8; */
}
.position-message.error {
/* background-color: #fef0f0;
color: #f56c6c;
border: 1px solid #fde2e2; */
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>
<!-- <template>
<transition name="fade">
<div
v-if="visible"
:class="['position-message', type]"
:style="positionStyle"
>
<i :class="iconClass"></i>
<span>{{ message }}</span>
</div>
</transition>
</template>
<script>
export default {
computed: {
iconClass() {
return {
info: 'el-icon-info',
success: 'el-icon-success',
error: 'el-icon-error'
}[this.type]
}
},
props: {
type: {
type: String,
default: 'info',
validator: val => ['info', 'success', 'error'].includes(val)
},
position: {
type: String,
default: 'top',
validator: val => ['top', 'bottom'].includes(val)
},
message: String,
target: null, // 目标元素/DOM选择器
offset: {
type: Number,
default: 5
}
},
data() {
return {
visible: false,
positionStyle: {}
}
},
methods: {
hide() {
this.visible = false
},
calculatePosition() {
const targetEl = typeof this.target === 'string'
? document.querySelector(this.target)
: this.target?.$el || this.target;
if (!targetEl?.getBoundingClientRect) {
console.error('Invalid target:', this.target);
return;
}
const targetRect = targetEl.getBoundingClientRect();
const messageWidth = this.$el.offsetWidth;
if (this.position === 'bottom') {
this.positionStyle = {
top: `${targetRect.bottom + window.scrollY + this.offset}px`,
left: `${targetRect.left + targetRect.width / 2 - messageWidth / 2}px`,
};
} else {
// 默认显示在上方(原逻辑)
this.positionStyle = {
top: `${targetRect.top + window.scrollY - this.offset - this.$el.offsetHeight}px`,
left: `${targetRect.left + targetRect.width / 2 - messageWidth / 2}px`,
};
}
},
show() {
this.visible = true;
this.$nextTick(this.calculatePosition);
return this;
},
},
};
</script> -->