180 lines
5.1 KiB
Vue
180 lines
5.1 KiB
Vue
|
<script>
|
|||
|
import Vue from 'vue'
|
|||
|
import AntTransition from '../../utils/ant-transition.vue'
|
|||
|
|
|||
|
Vue.component('ant-transition', AntTransition)
|
|||
|
|
|||
|
export default {
|
|||
|
name: 'ToolTip',
|
|||
|
props: {
|
|||
|
title: [String, Vue.Component],
|
|||
|
prefixCls: {
|
|||
|
default: 'ant-tooltip',
|
|||
|
},
|
|||
|
placement: {
|
|||
|
default: 'top',
|
|||
|
validator: val => ['top', 'left', 'right', 'bottom', 'topLeft', 'topRight', 'bottomLeft', 'bottomRight', 'leftTop', 'leftBottom', 'rightTop', 'rightBottom'].includes(val)
|
|||
|
},
|
|||
|
transitionName: {
|
|||
|
default: 'zoom-big-fast',
|
|||
|
},
|
|||
|
mouseEnterDelay: {
|
|||
|
default: 0.1,
|
|||
|
},
|
|||
|
mouseLeaveDelay: {
|
|||
|
default: 0.1,
|
|||
|
},
|
|||
|
arrowPointAtCenter: {
|
|||
|
default: false,
|
|||
|
},
|
|||
|
autoAdjustOverflow: {
|
|||
|
default: true,
|
|||
|
},
|
|||
|
},
|
|||
|
data () {
|
|||
|
return {
|
|||
|
vnode: null,
|
|||
|
visible: false,
|
|||
|
left: 0,
|
|||
|
top: 0,
|
|||
|
}
|
|||
|
},
|
|||
|
computed: {
|
|||
|
classes () {
|
|||
|
const { prefixCls } = this
|
|||
|
return {
|
|||
|
[`${prefixCls}`]: true,
|
|||
|
}
|
|||
|
},
|
|||
|
},
|
|||
|
created() {
|
|||
|
const div = document.createElement('div')
|
|||
|
document.body.appendChild(div)
|
|||
|
const that = this
|
|||
|
const vnode = new Vue({
|
|||
|
data() {
|
|||
|
return {
|
|||
|
left: 0,
|
|||
|
top: 0,
|
|||
|
}
|
|||
|
},
|
|||
|
render(h) {
|
|||
|
return (
|
|||
|
<ant-transition name="fade">
|
|||
|
<div
|
|||
|
v-show={that.visible}
|
|||
|
class={`ant-tooltip ant-tooltip-placement-${that.placement} ${that.visible ? '' : 'ant-tooltip-hidden'}`}
|
|||
|
style={{ left: this.left + 'px', top: this.top + 'px' }}
|
|||
|
>
|
|||
|
<div class="ant-tooltip-content">
|
|||
|
<div class="ant-tooltip-arrow"/>
|
|||
|
<div class="ant-tooltip-inner">
|
|||
|
<span>{that.title}</span>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</ant-transition>
|
|||
|
)
|
|||
|
}
|
|||
|
}).$mount(div)
|
|||
|
this.$nextTick(() => {
|
|||
|
this.vnode = vnode
|
|||
|
})
|
|||
|
},
|
|||
|
methods: {
|
|||
|
onPopupAlign: (placement, domNode, target, align) => {
|
|||
|
if (!placement) {
|
|||
|
return;
|
|||
|
}
|
|||
|
// 根据当前坐标设置动画点
|
|||
|
const rect = domNode.getBoundingClientRect()
|
|||
|
const transformOrigin = {
|
|||
|
top: '50%',
|
|||
|
left: '50%',
|
|||
|
};
|
|||
|
if (placement.indexOf('top') >= 0 || placement.indexOf('Bottom') >= 0) {
|
|||
|
transformOrigin.top = `${rect.height - align.offset[1]}px`;
|
|||
|
} else if (placement.indexOf('Top') >= 0 || placement.indexOf('bottom') >= 0) {
|
|||
|
transformOrigin.top = `${-align.offset[1]}px`;
|
|||
|
}
|
|||
|
if (placement.indexOf('left') >= 0 || placement.indexOf('Right') >= 0) {
|
|||
|
transformOrigin.left = `${rect.width - align.offset[0]}px`;
|
|||
|
} else if (placement.indexOf('right') >= 0 || placement.indexOf('Left') >= 0) {
|
|||
|
transformOrigin.left = `${-align.offset[0]}px`;
|
|||
|
}
|
|||
|
target.style.transformOrigin = `${transformOrigin.left} ${transformOrigin.top}`;
|
|||
|
},
|
|||
|
addEventHandle(old, fn) {
|
|||
|
if (!old) {
|
|||
|
return fn
|
|||
|
} else if (Array.isArray(old)) {
|
|||
|
return old.indexOf(fn) > -1 ? old : old.concat(fn)
|
|||
|
} else {
|
|||
|
return old === fn ? old : [old, fn]
|
|||
|
}
|
|||
|
},
|
|||
|
computeOffset(popup, text, placement) {
|
|||
|
let { width, height, top, left } = text
|
|||
|
// you cant change the properties of DOMRect
|
|||
|
top += window.scrollY
|
|||
|
left += window.scrollX
|
|||
|
const ret = { left, top }
|
|||
|
|
|||
|
if (/top/.test(placement)) ret.top -= popup.height
|
|||
|
if (/bottom/.test(placement)) ret.top += height
|
|||
|
if (/left/.test(placement)) ret.left -= popup.width
|
|||
|
if (/right/.test(placement)) ret.left += width
|
|||
|
|
|||
|
if (/Left/.test(placement)) {
|
|||
|
} else if(/Right/.test(placement)) {
|
|||
|
ret.left += (width - popup.width)
|
|||
|
} else if(/(top)|(bottom)/.test(placement)) {
|
|||
|
ret.left += (width - popup.width) / 2
|
|||
|
}
|
|||
|
if (/Top/.test(placement)) {
|
|||
|
} else if(/Bottom/.test(placement)) {
|
|||
|
ret.top += (height - popup.height)
|
|||
|
} else if(/(left)|(right)/.test(placement)) {
|
|||
|
ret.top += (height - popup.height) / 2
|
|||
|
}
|
|||
|
return ret
|
|||
|
},
|
|||
|
showNode() {
|
|||
|
this.visible = true
|
|||
|
this.$nextTick(() => {
|
|||
|
const popup = this.vnode.$el.getBoundingClientRect()
|
|||
|
const content = this.$el.getBoundingClientRect()
|
|||
|
const { left, top } = this.computeOffset(popup, content, this.placement)
|
|||
|
this.vnode.left = left
|
|||
|
this.vnode.top = top
|
|||
|
})
|
|||
|
this.onPopupAlign(this.placement, this.$el, this.vnode.$el, { offset: [0,0] })
|
|||
|
},
|
|||
|
hideNode() {
|
|||
|
this.visible = false
|
|||
|
}
|
|||
|
},
|
|||
|
render(h) {
|
|||
|
let node = this.vnode
|
|||
|
const inner = this.$slots.default[0]
|
|||
|
inner.data = inner.data || {}
|
|||
|
inner.data.on = inner.data.on || {}
|
|||
|
inner.data.on.mouseenter = this.addEventHandle(inner.data.on.mouseenter, this.showNode)
|
|||
|
inner.data.on.mouseleave = this.addEventHandle(inner.data.on.mouseleave, this.hideNode)
|
|||
|
// console.info(inner)
|
|||
|
return this.$slots.default[0]
|
|||
|
},
|
|||
|
mounted() {
|
|||
|
this.$nextTick(() => {
|
|||
|
})
|
|||
|
},
|
|||
|
beforeDestory() {
|
|||
|
console.info('没有成功清除实例,看vue panel')
|
|||
|
this.vnode.$destroy();
|
|||
|
},
|
|||
|
components: {
|
|||
|
'ant-transition': AntTransition
|
|||
|
}
|
|||
|
}
|
|||
|
</script>
|