update: [Tooltip] unsolved animation & transition
							parent
							
								
									89ac16c28a
								
							
						
					
					
						commit
						c0c2a1894c
					
				|  | @ -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' | ||||
|  |  | |||
|  | @ -0,0 +1,3 @@ | |||
| import ToolTip from './tooltip.vue' | ||||
| export default ToolTip | ||||
| 
 | ||||
|  | @ -0,0 +1,2 @@ | |||
| import '../../style/index.less' | ||||
| import './index.less' | ||||
|  | @ -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; | ||||
|   } | ||||
| } | ||||
|  | @ -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> | ||||
|  | @ -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, | ||||
|   }, | ||||
| }) | ||||
|  |  | |||
|  | @ -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> | ||||
|  | @ -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> | ||||
		Loading…
	
		Reference in New Issue
	
	 wanlei
						wanlei