自制弹出框组件
一. VUE
没有使用vue-popover插件,因为功能不需要太多,只需要上下左右弹出
ww 视口宽
elm.offsetLeft 这div的左侧偏移量,不算margin;(也没margin)
elm.clientWidth 这div的宽,不包括border和margin;是用按钮撑开宽
this.width 设置弹出窗口的宽
<template>
<div
class="zoehis_popover"
>
<div ref="popRef" :placement="placement" @mouseenter="mouseenterEvn" @mouseleave="mouseleaveEvn" v-clickoutside="() => clickEvt(false)" @click="clickEvt(true)" class="zoehis_popover_el">
<slot name="reference"></slot>
</div>
<div class="zoehis_popover_content" v-show="contMenu.isShowContMenu"
:style="{left:contMenu.offsetX+'px',top:contMenu.offsetY+'px',width:newWidth,height:newHeight }"
@mouseenter="popMouseenterEvt" @mouseleave="hidePop" @click="clickEvt(true)">
<slot></slot>
</div>
</div>
</template>
<script type="text/babel">
export default {
name: 'ZoehisPopover',
data () {
return {
contMenu: {
offsetX: 0,//弹窗与左侧距离
offsetY: 0,//弹窗与顶部距离
isShowContMenu: false//弹窗显示
},
}
},
props: {
width:{
type:[Number,String],
default:80
},
height:{
type:[Number,String],
default:60
},
trigger:{// 触发方式hover/click
type:String,
default:'hover'
},
placement:{// 弹出位置right/left/bottom/top
type:String,
default:'right'
}
},
computed: {
newWidth() {
const re = /^[0-9]+\.?[0-9]*$/;
if (re.test(this.width)) {
return `${this.width}px`
}
return this.width
},
newHeight() {
const re = /^[0-9]+\.?[0-9]*$/;
if (re.test(this.height)) {
return `${this.height}px`
}
return this.height
},
nWidth() {
const re = /^\d+px$/
if (re.test(this.width)) {
return this.width.substring(0,this.width.length - 2)
}
return this.width
},
nHeight() {
const re = /^\d+px$/
if (re.test(this.height)) {
return this.height.substring(0,this.height.length - 2)
}
return this.height
}
},
methods: {
mouseenterEvn() {
if(this.trigger==='hover'){
this.show()
}
},
mouseleaveEvn() {
if(this.trigger==='hover'){
this.hide()
}
},
clickEvt(flag) {
if(this.trigger==='click'){
flag?this.show():this.hide()
}
},
show() {
const elm = this.$refs.popRef
let offsetWw, offsetWh
let ww = document.body.clientWidth
let wh = document.body.clientHeight
if (this.placement === 'right') {
offsetWw = ww - elm.offsetLeft - elm.clientWidth < this.nWidth && elm.offsetLeft>=this.nWidth ? elm.offsetLeft - this.nWidth : elm.offsetLeft + elm.clientWidth
offsetWh = wh - elm.offsetTop < this.nHeight && elm.offsetTop>=this.nHeight ? elm.offsetTop - this.nHeight + elm.clientHeight : elm.offsetTop
} else if (this.placement === 'left') {
offsetWw = ww - elm.offsetLeft - elm.clientWidth >= this.nWidth && elm.offsetLeft < this.nWidth ? elm.offsetLeft + elm.clientWidth : elm.offsetLeft - this.nWidth
console.log(offsetWw)
offsetWh = wh - elm.offsetTop < this.nHeight && elm.offsetTop>=this.nHeight ? elm.offsetTop - this.nHeight + elm.clientHeight : elm.offsetTop
} else if (this.placement === 'top') {
offsetWw = ww - elm.offsetLeft < this.nWidth && elm.offsetLeft >= this.nWidth ? elm.offsetLeft - this.nWidth + elm.clientWidth : elm.offsetLeft
offsetWh = wh - elm.offsetTop < this.nHeight && elm.offsetTop>=this.nHeight ? elm.offsetTop + elm.clientHeight : elm.offsetTop - this.nHeight
} else if (this.placement === 'bottom') {
offsetWw = ww - elm.offsetLeft < this.nWidth && elm.offsetLeft >= this.nWidth ? elm.offsetLeft - this.nWidth + elm.clientWidth : elm.offsetLeft
offsetWh = wh - elm.offsetTop - elm.clientHeight < this.nHeight && elm.offsetTop>=this.nHeight ? elm.offsetTop - this.nHeight :elm.offsetTop + elm.clientHeight
}
this.contMenu = {
offsetX: offsetWw,
offsetY: offsetWh,
isShowContMenu: true
};
},
hide(){
if(this.trigger==='hover'){
if (this.hideTimer) {
clearTimeout(this.hideTimer);
}
this.hideTimer = setTimeout(() => {
this.contMenu = {
offsetX: 0,//弹窗与左侧距离
offsetY: 0,//弹窗与顶部距离
isShowContMenu: false//弹窗显示
};
}, 100);
}else {
this.contMenu.isShowContMenu=false
}
},
popMouseenterEvt() {
if (this.hideTimer) {
clearTimeout(this.hideTimer);
}
},
hidePop() {
if(this.trigger==='hover'){
this.contMenu.isShowContMenu=false
}
}
}
};
</script>
二. index
/**
* Created by liman on 2021/12/13.
*/
import ZoehisPopover from './src/popover.vue';
ZoehisPopover.install = function(Vue) {
Vue.component(ZoehisPopover.name,ZoehisPopover);
};
export default ZoehisPopover;
三. SCSS
.zoehis_popover {
.zoehis_popover_el {width: max-content;}
.zoehis_popover_content {
background: $MAINBG; box-sizing: border-box;box-shadow: $SHADOWVALUE;position: absolute;border-radius: 4px;z-index: 99;
}
}
本文来自博客园,作者:暗鸦08,转载请注明原文链接:https://www.cnblogs.com/DarkCrow/p/15709618.html

浙公网安备 33010602011771号