update: [Tooltip] unsolved animation & transition

This commit is contained in:
wanlei 2017-11-02 19:40:49 +08:00
parent f4fb4fedbb
commit 5b44c18d41
8 changed files with 459 additions and 1 deletions

View File

@ -3,6 +3,7 @@ import './checkbox/style'
import './icon/style'
import './radio/style'
import './grid/style'
import './tooltip/style'
export { default as Button } from './button'
@ -13,3 +14,5 @@ export { default as Icon } from './icon'
export { default as Radio } from './radio'
export { default as Grid } from './grid'
export { default as ToolTip } from './tooltip'

View File

@ -0,0 +1,3 @@
import ToolTip from './tooltip.vue'
export default ToolTip

View File

@ -0,0 +1,2 @@
import '../../style/index.less'
import './index.less'

View File

@ -0,0 +1,207 @@
@import "../../style/themes/default";
@import "../../style/mixins/index";
@tooltip-prefix-cls: ~"@{ant-prefix}-tooltip";
// Base class
.@{tooltip-prefix-cls} {
position: absolute;
z-index: @zindex-tooltip;
display: block;
visibility: visible;
font-size: @font-size-base;
line-height: @line-height-base;
&-hidden {
display: none;
}
&-placement-top,
&-placement-topLeft,
&-placement-topRight {
padding-bottom: @tooltip-distance;
}
&-placement-right,
&-placement-rightTop,
&-placement-rightBottom {
padding-left: @tooltip-distance;
}
&-placement-bottom,
&-placement-bottomLeft,
&-placement-bottomRight {
padding-top: @tooltip-distance;
}
&-placement-left,
&-placement-leftTop,
&-placement-leftBottom {
padding-right: @tooltip-distance;
}
}
// Wrapper for the tooltip content
.@{tooltip-prefix-cls}-inner {
max-width: @tooltip-max-width;
padding: 8px 10px;
color: @tooltip-color;
text-align: left;
text-decoration: none;
background-color: @tooltip-bg;
border-radius: @border-radius-base;
box-shadow: @box-shadow-base;
min-height: 34px;
}
// Arrows
.@{tooltip-prefix-cls}-arrow {
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
}
.@{tooltip-prefix-cls} {
&-placement-top &-arrow,
&-placement-topLeft &-arrow,
&-placement-topRight &-arrow {
bottom: @tooltip-distance - @tooltip-arrow-width;
border-width: @tooltip-arrow-width @tooltip-arrow-width 0;
border-top-color: @tooltip-arrow-color;
}
&-placement-top &-arrow {
left: 50%;
margin-left: -@tooltip-arrow-width;
}
&-placement-topLeft &-arrow {
left: 16px;
}
&-placement-topRight &-arrow {
right: 16px;
}
&-placement-right &-arrow,
&-placement-rightTop &-arrow,
&-placement-rightBottom &-arrow {
left: @tooltip-distance - @tooltip-arrow-width;
border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;
border-right-color: @tooltip-arrow-color;
}
&-placement-right &-arrow {
top: 50%;
margin-top: -@tooltip-arrow-width;
}
&-placement-rightTop &-arrow {
top: 8px;
}
&-placement-rightBottom &-arrow {
bottom: 8px;
}
&-placement-left &-arrow,
&-placement-leftTop &-arrow,
&-placement-leftBottom &-arrow {
right: @tooltip-distance - @tooltip-arrow-width;
border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;
border-left-color: @tooltip-arrow-color;
}
&-placement-left &-arrow {
top: 50%;
margin-top: -@tooltip-arrow-width;
}
&-placement-leftTop &-arrow {
top: 8px;
}
&-placement-leftBottom &-arrow {
bottom: 8px;
}
&-placement-bottom &-arrow,
&-placement-bottomLeft &-arrow,
&-placement-bottomRight &-arrow {
top: @tooltip-distance - @tooltip-arrow-width;
border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;
border-bottom-color: @tooltip-arrow-color;
}
&-placement-bottom &-arrow {
left: 50%;
margin-left: -@tooltip-arrow-width;
}
&-placement-bottomLeft &-arrow {
left: 16px;
}
&-placement-bottomRight &-arrow {
right: 16px;
}
}
/**
modified part ,remove these if needed
*/
.vc-fade-enter-active, .vc-fade-leave-active {
transition: all 3s;
}
.vc-fade-enter, .vc-fade-leave-to /* .fade-leave-active in below version 2.1.8 */ {
opacity: 0;
}
.box {
background: red;
width: 100px;
height: 100px;
}
.fade-enter {
opacity: 0;
animation-duration: 0.3s;
animation-fill-mode: both;
animation-timing-function: cubic-bezier(0.55, 0, 0.55, 0.2);
animation-play-state: paused;
}
.fade-leave {
animation-duration: 0.3s;
animation-fill-mode: both;
animation-timing-function: cubic-bezier(0.55, 0, 0.55, 0.2);
animation-play-state: paused;
}
.fade-enter.fade-enter-active {
animation-name: rcDialogFadeIn;
animation-play-state: running;
}
.fade-leave.fade-leave-active {
animation-name: rcDialogFadeOut;
animation-play-state: running;
}
@keyframes rcDialogFadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes rcDialogFadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}

View File

@ -0,0 +1,179 @@
<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>

View File

@ -3,13 +3,15 @@ import Checkbox from './checkbox.vue'
import Button from './button.vue'
import Radio from './radio.vue'
import Grid from './grid.vue'
import ToolTip from './tooltip.vue'
// import Dialog from './dialog.vue'
import './index.less'
new Vue({
window.root = new Vue({
el: '#app',
template: `
<div>
<Grid />
<ToolTip />
<Checkbox />
<AntButton />
<Radio />
@ -21,5 +23,6 @@ new Vue({
Checkbox,
Grid,
Radio,
ToolTip,
},
})

29
examples/tooltip.vue Normal file
View File

@ -0,0 +1,29 @@
<template>
<tool-tip
placement="top"
title="nihaoaaaaaaaaaaaaaaaaaaaaa">
<h1 @click="boom" style="display: inline-block">This is just a test, put your cursor here</h1>
</tool-tip>
</template>
<script>
import { ToolTip } from '../components'
export default {
name: '',
data() {
return {}
},
methods: {
boom() {
console.info(23333)
}
},
components: {
ToolTip
}
}
</script>
<style scoped>
</style>

32
utils/ant-transition.vue Normal file
View File

@ -0,0 +1,32 @@
<template>
<transition
:name="name"
:enter-to-class="enterTo"
:enter-active-class="enterActive"
:leave-to-class="leaveTo"
>
<slot></slot>
</transition>
</template>
<script>
export default {
name: 'ant-transition',
props: {
name: {
required: true,
}
},
computed: {
enterTo() {
return this.name + '-enter'
},
enterActive() {
return `${this.name}-enter ${this.name}-enter-active`
},
leaveTo() {
return this.name + '-leave'
}
}
}
</script>