You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
3.8 KiB
158 lines
3.8 KiB
import PropTypes from '../_util/vue-types'
|
|
import Icon from '../icon'
|
|
import getTransitionProps from '../_util/getTransitionProps'
|
|
import omit from 'omit.js'
|
|
import Wave from '../_util/wave'
|
|
import { hasProp, getOptionProps } from '../_util/props-util'
|
|
import BaseMixin from '../_util/BaseMixin'
|
|
|
|
export default {
|
|
name: 'ATag',
|
|
mixins: [BaseMixin],
|
|
props: {
|
|
prefixCls: PropTypes.string.def('ant-tag'),
|
|
color: PropTypes.string,
|
|
closable: PropTypes.bool,
|
|
visible: PropTypes.bool,
|
|
afterClose: PropTypes.func,
|
|
},
|
|
model: {
|
|
prop: 'visible',
|
|
event: 'close.visible',
|
|
},
|
|
data () {
|
|
const props = getOptionProps(this)
|
|
let state = {}
|
|
if ('visible' in props) {
|
|
state = {
|
|
_visible: props.visible,
|
|
_closed: !props.visible,
|
|
}
|
|
}
|
|
state = {
|
|
_closing: false,
|
|
_closed: false,
|
|
_visible: true,
|
|
...state,
|
|
}
|
|
this.pre_visible = state._visible
|
|
return state
|
|
},
|
|
watch: {
|
|
visible (val) {
|
|
this.setState({
|
|
_visible: val,
|
|
})
|
|
},
|
|
},
|
|
updated () {
|
|
this.$nextTick(() => {
|
|
const preVisible = this.pre_visible
|
|
this.pre_visible = this.$data._visible
|
|
if (preVisible && !this.$data._visible) {
|
|
this.close()
|
|
} else if (!preVisible && this.$data._visible) {
|
|
this.show()
|
|
}
|
|
})
|
|
},
|
|
methods: {
|
|
handleIconClick (e) {
|
|
this.$emit('close', e)
|
|
this.$emit('close.visible', false)
|
|
if (e.defaultPrevented || hasProp(this, 'visible')) {
|
|
return
|
|
}
|
|
this.setState({ _visible: false })
|
|
this.$forceUpdate()
|
|
},
|
|
close () {
|
|
if (this.$data._closing || this.$data._closed) {
|
|
return
|
|
}
|
|
const dom = this.$el
|
|
dom.style.width = `${dom.getBoundingClientRect().width}px`
|
|
// It's Magic Code, don't know why
|
|
dom.style.width = `${dom.getBoundingClientRect().width}px`
|
|
this.setState({
|
|
_closing: true,
|
|
})
|
|
},
|
|
|
|
show () {
|
|
this.setState({
|
|
_closed: false,
|
|
})
|
|
},
|
|
|
|
animationEnd (_, existed) {
|
|
if (!existed && !this.$data._closed) {
|
|
this.setState({
|
|
_closed: true,
|
|
_closing: false,
|
|
})
|
|
|
|
const afterClose = this.afterClose
|
|
if (afterClose) {
|
|
afterClose()
|
|
}
|
|
} else {
|
|
this.setState({
|
|
_closed: false,
|
|
})
|
|
}
|
|
},
|
|
|
|
isPresetColor (color) {
|
|
if (!color) { return false }
|
|
return (
|
|
/^(pink|red|yellow|orange|cyan|green|blue|purple|geekblue|magenta|volcano|gold|lime)(-inverse)?$/
|
|
.test(color)
|
|
)
|
|
},
|
|
},
|
|
|
|
render () {
|
|
const { prefixCls, closable, color } = this.$props
|
|
const closeIcon = closable ? <Icon type='close' onClick={this.handleIconClick} /> : ''
|
|
const isPresetColor = this.isPresetColor(color)
|
|
const cls = {
|
|
[`${prefixCls}`]: true,
|
|
[`${prefixCls}-${color}`]: isPresetColor,
|
|
[`${prefixCls}-has-color`]: (color && !isPresetColor),
|
|
[`${prefixCls}-close`]: this.$data._closing,
|
|
}
|
|
|
|
const tagStyle = {
|
|
backgroundColor: (color && !isPresetColor) ? color : null,
|
|
}
|
|
const tag =
|
|
<div
|
|
v-show={!this.$data._closing}
|
|
data-show={!this.$data._closing}
|
|
{...{ on: omit(this.$listeners, ['close']) }}
|
|
class={cls}
|
|
style={tagStyle}
|
|
>
|
|
{this.$slots.default}
|
|
{closeIcon}
|
|
</div>
|
|
const transitionProps = getTransitionProps(`${prefixCls}-zoom`, {
|
|
afterLeave: () => this.animationEnd(undefined, false),
|
|
afterEnter: () => this.animationEnd(undefined, true),
|
|
})
|
|
return (
|
|
<Wave>
|
|
{this.$data._closed ? <span/>
|
|
: <transition
|
|
{...transitionProps}
|
|
>
|
|
{tag}
|
|
</transition>
|
|
}
|
|
</Wave>
|
|
)
|
|
},
|
|
}
|
|
|