add notification and fix tag bug
							parent
							
								
									f8f3bcd008
								
							
						
					
					
						commit
						bb9ca79311
					
				|  | @ -1,7 +1,7 @@ | |||
| export default { | ||||
|   methods: { | ||||
|     setState (state, callback) { | ||||
|       Object.assign(this.$data, state) | ||||
|       Object.assign(this.$data, typeof state === 'function' ? state(this.$data) : state) | ||||
|       this.$nextTick(() => { | ||||
|         callback && callback() | ||||
|       }) | ||||
|  |  | |||
|  | @ -0,0 +1,22 @@ | |||
| /** | ||||
|  * Safe chained function | ||||
|  * | ||||
|  * Will only create a new function if needed, | ||||
|  * otherwise will pass back existing functions or null. | ||||
|  * | ||||
|  * @returns {function|null} | ||||
|  */ | ||||
| export default function createChainedFunction () { | ||||
|   const args = [].slice.call(arguments, 0) | ||||
|   if (args.length === 1) { | ||||
|     return args[0] | ||||
|   } | ||||
| 
 | ||||
|   return function chainedFunction () { | ||||
|     for (let i = 0; i < args.length; i++) { | ||||
|       if (args[i] && args[i].apply) { | ||||
|         args[i].apply(this, arguments) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,28 @@ | |||
| import animate from './css-animation' | ||||
| const noop = () => {} | ||||
| const getTransitionProps = (transitionName, opt = {}) => { | ||||
|   const { beforeEnter, enter, leave, afterLeave, appear = true, tag } = opt | ||||
|   const transitionProps = { | ||||
|     props: { | ||||
|       appear, | ||||
|       css: false, | ||||
|     }, | ||||
|     on: { | ||||
|       beforeEnter: beforeEnter || noop, | ||||
|       enter: enter || ((el, done) => { | ||||
|         animate(el, `${transitionName}-enter`, done) | ||||
|       }), | ||||
|       leave: leave || ((el, done) => { | ||||
|         animate(el, `${transitionName}-leave`, done) | ||||
|       }), | ||||
|       afterLeave: afterLeave || noop, | ||||
|     }, | ||||
|   } | ||||
|   // transition-group
 | ||||
|   if (tag) { | ||||
|     transitionProps.tag = tag | ||||
|   } | ||||
|   return transitionProps | ||||
| } | ||||
| 
 | ||||
| export default getTransitionProps | ||||
|  | @ -0,0 +1,64 @@ | |||
| <script> | ||||
| import PropTypes from '../../_util/vue-types' | ||||
| import { getStyle } from '../../_util/vnode' | ||||
| import BaseMixin from '../../_util/BaseMixin' | ||||
| 
 | ||||
| export default { | ||||
|   mixins: [BaseMixin], | ||||
|   props: { | ||||
|     duration: PropTypes.number.def(1.5), | ||||
|   }, | ||||
| 
 | ||||
|   mounted () { | ||||
|     this.startCloseTimer() | ||||
|   }, | ||||
| 
 | ||||
|   beforeDestory () { | ||||
|     this.clearCloseTimer() | ||||
|   }, | ||||
|   methods: { | ||||
|     close () { | ||||
|       this.clearCloseTimer() | ||||
|       this._emit('close') | ||||
|     }, | ||||
| 
 | ||||
|     startCloseTimer () { | ||||
|       if (this.duration) { | ||||
|         this.closeTimer = setTimeout(() => { | ||||
|           this.close() | ||||
|         }, this.duration * 1000) | ||||
|       } | ||||
|     }, | ||||
| 
 | ||||
|     clearCloseTimer () { | ||||
|       if (this.closeTimer) { | ||||
|         clearTimeout(this.closeTimer) | ||||
|         this.closeTimer = null | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
| 
 | ||||
|   render () { | ||||
|     const { prefixCls, closable, clearCloseTimer, startCloseTimer, $slots, close } = this | ||||
|     const componentClass = `${prefixCls}-notice` | ||||
|     const className = { | ||||
|       [`${componentClass}`]: 1, | ||||
|       [`${componentClass}-closable`]: closable, | ||||
|     } | ||||
|     const style = getStyle(this) | ||||
|     return ( | ||||
|       <div class={className} style={style || { right: '50%' } } onMouseenter={clearCloseTimer} | ||||
|         onMouseleave={startCloseTimer} | ||||
|       > | ||||
|         <div class={`${componentClass}-content`}>{$slots.default}</div> | ||||
|         {closable | ||||
|           ? <a tabIndex='0' onClick={close} class={`${componentClass}-close`}> | ||||
|             <span class={`${componentClass}-close-x`}></span> | ||||
|           </a> : null | ||||
|         } | ||||
|       </div> | ||||
|     ) | ||||
|   }, | ||||
| } | ||||
| 
 | ||||
| </script> | ||||
|  | @ -0,0 +1,145 @@ | |||
| <script> | ||||
| import Vue from 'vue' | ||||
| import PropTypes from '../../_util/vue-types' | ||||
| import { getStyle } from '../../_util/vnode' | ||||
| import BaseMixin from '../../_util/BaseMixin' | ||||
| import createChainedFunction from '../../_util/createChainedFunction' | ||||
| import getTransitionProps from '../../_util/getTransitionProps' | ||||
| import Notice from './Notice' | ||||
| 
 | ||||
| let seed = 0 | ||||
| const now = Date.now() | ||||
| 
 | ||||
| function getUuid () { | ||||
|   return `rcNotification_${now}_${seed++}` | ||||
| } | ||||
| 
 | ||||
| const Notification = { | ||||
|   mixins: [BaseMixin], | ||||
|   props: { | ||||
|     prefixCls: PropTypes.string.def('rc-notification'), | ||||
|     transitionName: PropTypes.string, | ||||
|     animation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).def('fade'), | ||||
|   }, | ||||
|   data () { | ||||
|     return { | ||||
|       notices: [], | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getTransitionName () { | ||||
|       const props = this.$props | ||||
|       let transitionName = props.transitionName | ||||
|       if (!transitionName && props.animation) { | ||||
|         transitionName = `${props.prefixCls}-${props.animation}` | ||||
|       } | ||||
|       return transitionName | ||||
|     }, | ||||
| 
 | ||||
|     add (notice) { | ||||
|       const key = notice.key = notice.key || getUuid() | ||||
|       this.setState(previousState => { | ||||
|         const notices = previousState.notices | ||||
|         if (!notices.filter(v => v.key === key).length) { | ||||
|           return { | ||||
|             notices: notices.concat(notice), | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
| 
 | ||||
|     remove (key) { | ||||
|       this.setState(previousState => { | ||||
|         return { | ||||
|           notices: previousState.notices.filter(notice => notice.key !== key), | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|   }, | ||||
| 
 | ||||
|   render () { | ||||
|     const { prefixCls, notices, remove, getTransitionName } = this | ||||
|     const noticeNodes = notices.map((notice) => { | ||||
|       const onClose = createChainedFunction(remove.bind(this, notice.key), notice.on.close) | ||||
|       const noticeProps = { | ||||
|         ...notice, | ||||
|         props: { | ||||
|           prefixCls, | ||||
|           ...notice.props, | ||||
|         }, | ||||
|         on: { | ||||
|           ...notice.on, | ||||
|           close: onClose, | ||||
|         }, | ||||
|       } | ||||
|       return (<Notice | ||||
|         {...noticeProps} | ||||
|       > | ||||
|         {notice.content} | ||||
|       </Notice>) | ||||
|     }) | ||||
|     const className = { | ||||
|       [prefixCls]: 1, | ||||
|     } | ||||
|     const style = getStyle(this) | ||||
|     return ( | ||||
|       <div class={className} style={style || { | ||||
|         top: '65px', | ||||
|         left: '50%', | ||||
|       }}> | ||||
|         <transition-group {...getTransitionProps(getTransitionName(), { tag: 'div' })}>{noticeNodes}</transition-group> | ||||
|       </div> | ||||
|     ) | ||||
|   }, | ||||
| } | ||||
| 
 | ||||
| Notification.newInstance = function newNotificationInstance (properties, callback) { | ||||
|   const { getContainer, style, class: className, on = {}, ...props } = properties || {} | ||||
|   const div = document.createElement('div') | ||||
|   if (getContainer) { | ||||
|     const root = getContainer() | ||||
|     root.appendChild(div) | ||||
|   } else { | ||||
|     document.body.appendChild(div) | ||||
|   } | ||||
|   const notificationInstance = new Vue({ | ||||
|     el: div, | ||||
|     mounted () { | ||||
|       const self = this | ||||
|       this.$nextTick(() => { | ||||
|         callback({ | ||||
|           notice (noticeProps) { | ||||
|             self.$refs.notification.add(noticeProps) | ||||
|           }, | ||||
|           removeNotice (key) { | ||||
|             self.$refs.notification.remove(key) | ||||
|           }, | ||||
|           component: self, | ||||
|           destroy () { | ||||
|             // self.$destroy() | ||||
|             notificationInstance.$destroy() | ||||
|             div.parentNode.removeChild(div) | ||||
|           }, | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|     render () { | ||||
|       const p = { | ||||
|         props, | ||||
|         on, | ||||
|         ref: 'notification', | ||||
|         style, | ||||
|         class: className, | ||||
|       } | ||||
|       return ( | ||||
|         <Notification | ||||
|           {...p} | ||||
|         /> | ||||
|       ) | ||||
|     }, | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
| export default Notification | ||||
| 
 | ||||
| </script> | ||||
|  | @ -0,0 +1,2 @@ | |||
| import Notification from './Notification' | ||||
| export default Notification | ||||
|  | @ -1,25 +1,10 @@ | |||
| <template> | ||||
|   <transition | ||||
|     :name="`${prefixCls}-zoom`" | ||||
|     appear | ||||
|     @after-leave="animationEnd" | ||||
|   > | ||||
|     <div | ||||
|       v-if="!closed" | ||||
|       :class="classes" | ||||
|       :style="tagStyle" | ||||
|     > | ||||
|       <slot></slot> | ||||
|       <Icon v-if="closable" type="cross" @click="close" /> | ||||
|     </div> | ||||
|   </transition> | ||||
| </template> | ||||
| <script> | ||||
| import Icon from '../icon' | ||||
| import getTransitionProps from '../_util/getTransitionProps' | ||||
| import omit from 'omit.js' | ||||
| 
 | ||||
| export default { | ||||
|   name: 'Tag', | ||||
|   components: { Icon }, | ||||
|   props: { | ||||
|     prefixCls: { | ||||
|       default: 'ant-tag', | ||||
|  | @ -27,22 +12,20 @@ export default { | |||
|     }, | ||||
|     color: String, | ||||
|     closable: Boolean, | ||||
|     styles: { | ||||
|       default: () => ({}), | ||||
|       type: Object, | ||||
|     }, | ||||
|   }, | ||||
|   data () { | ||||
|     const isPresetColor = (color) => { | ||||
|       if (!color) { return false } | ||||
|       return /^(pink|red|yellow|orange|cyan|green|blue|purple)(-inverse)?$/.test(color) | ||||
|     } | ||||
|     return { | ||||
|       closed: false, | ||||
|       isPresetColor: isPresetColor(this.color), | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     isPresetColor () { | ||||
|       const isPresetColor = (color) => { | ||||
|         if (!color) { return false } | ||||
|         return /^(pink|red|yellow|orange|cyan|green|blue|purple)(-inverse)?$/.test(color) | ||||
|       } | ||||
|       return isPresetColor(this.color) | ||||
|     }, | ||||
|     classes () { | ||||
|       const { prefixCls, color, isPresetColor } = this | ||||
|       return { | ||||
|  | @ -52,16 +35,16 @@ export default { | |||
|       } | ||||
|     }, | ||||
|     tagStyle () { | ||||
|       const { color, styles, isPresetColor } = this | ||||
|       const { color, isPresetColor } = this | ||||
|       console.log(color, isPresetColor) | ||||
|       return { | ||||
|         backgroundColor: (color && !isPresetColor) ? color : null, | ||||
|         ...styles, | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     animationEnd () { | ||||
|       this.$emit('after-close') | ||||
|       this.$emit('afterClose') | ||||
|     }, | ||||
|     close (e) { | ||||
|       this.$emit('close', e) | ||||
|  | @ -71,5 +54,31 @@ export default { | |||
|       this.closed = true | ||||
|     }, | ||||
|   }, | ||||
|   render () { | ||||
|     const { prefixCls, animationEnd, classes, tagStyle, closable, close, closed, $slots, $listeners } = this | ||||
|     const transitionProps = getTransitionProps(`${prefixCls}-zoom`, { | ||||
|       afterLeave: animationEnd, | ||||
|     }) | ||||
|     // const tagProps = { | ||||
|     //   on | ||||
|     // } | ||||
|     return ( | ||||
|       <transition | ||||
|         {...transitionProps} | ||||
|       > | ||||
|         {!closed | ||||
|           ? <div | ||||
| 
 | ||||
|             class={classes} | ||||
|             style={tagStyle} | ||||
|             {...{ on: omit($listeners, ['close', 'afterClose']) }} | ||||
|           > | ||||
|             {$slots.default} | ||||
|             {closable ? <Icon type='cross' onClick={close} /> : null} | ||||
|           </div> : null | ||||
|         } | ||||
|       </transition> | ||||
|     ) | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  |  | |||
|  | @ -2,11 +2,11 @@ | |||
|   <div> | ||||
|     <template v-for="(tag, index) in tags"> | ||||
|       <Tooltip v-if="tag.length > 20" :key="tag" :title="tag"> | ||||
|         <Tag :key="tag" :closable="index !== 0" @after-close="() => handleClose(tag)"> | ||||
|         <Tag :key="tag" :closable="index !== 0" @afterClose="() => handleClose(tag)"> | ||||
|           {{`${tag.slice(0, 20)}...`}} | ||||
|         </Tag> | ||||
|       </Tooltip> | ||||
|       <Tag v-else :key="tag" :closable="index !== 0" @after-close="() => handleClose(tag)"> | ||||
|       <Tag v-else :key="tag" :closable="index !== 0" @afterClose="() => handleClose(tag)"> | ||||
|         {{tag}} | ||||
|       </Tag> | ||||
|     </template> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 tangjinzhou
						tangjinzhou