diff --git a/src/notice-bar/index.js b/src/notice-bar/index.js index b088bc36d..8b3f9c080 100644 --- a/src/notice-bar/index.js +++ b/src/notice-bar/index.js @@ -1,5 +1,7 @@ +import { ref, reactive, nextTick, onActivated, watch } from 'vue'; import { createNamespace, isDef } from '../utils'; import { doubleRaf } from '../utils/dom/raf'; +import { useWidth } from '../composition/use-rect'; import Icon from '../icon'; const [createComponent, bem] = createNamespace('notice-bar'); @@ -28,158 +30,149 @@ export default createComponent({ emits: ['close', 'replay'], - data() { - return { + setup(props, { emit, slots }) { + let wrapWidth = 0; + let contentWidth = 0; + + const wrapRef = ref(); + const contentRef = ref(); + + const state = reactive({ show: true, offset: 0, duration: 0, - wrapWidth: 0, - contentWidth: 0, - }; - }, + }); - watch: { - scrollable() { - this.start(); - }, - text: { - handler() { - this.start(); - }, - immediate: true, - }, - }, - - activated() { - this.start(); - }, - - methods: { - onClickIcon(event) { - if (this.mode === 'closeable') { - this.show = false; - this.$emit('close', event); - } - }, - - onTransitionEnd() { - this.offset = this.wrapWidth; - this.duration = 0; - - // wait for Vue to render offset - this.$nextTick(() => { - // use double raf to ensure animation can start - doubleRaf(() => { - this.offset = -this.contentWidth; - this.duration = (this.contentWidth + this.wrapWidth) / this.speed; - this.$emit('replay'); - }); - }); - }, - - reset() { - this.offset = 0; - this.duration = 0; - this.wrapWidth = 0; - this.contentWidth = 0; - }, - - start() { - const delay = isDef(this.delay) ? this.delay * 1000 : 0; - - this.reset(); - - setTimeout(() => { - const { wrap, content } = this.$refs; - if (!wrap || !content || this.scrollable === false) { - return; - } - - const wrapWidth = wrap.getBoundingClientRect().width; - const contentWidth = content.getBoundingClientRect().width; - - if (this.scrollable || contentWidth > wrapWidth) { - doubleRaf(() => { - this.offset = -contentWidth; - this.duration = contentWidth / this.speed; - this.wrapWidth = wrapWidth; - this.contentWidth = contentWidth; - }); - } - }, delay); - }, - }, - - render() { - const slots = this.$slots; - const { mode, leftIcon, onClickIcon } = this; - - const barStyle = { - color: this.color, - background: this.background, - }; - - const contentStyle = { - transform: this.offset ? `translateX(${this.offset}px)` : '', - transitionDuration: this.duration + 's', - }; - - function LeftIcon() { + const renderLeftIcon = () => { if (slots['left-icon']) { return slots['left-icon'](); } - - if (leftIcon) { - return ; + if (props.leftIcon) { + return ; } - } + }; - function RightIcon() { + const getRightIconName = () => { + if (props.mode === 'closeable') { + return 'cross'; + } + if (props.mode === 'link') { + return 'arrow'; + } + }; + + const onClickRightIcon = (event) => { + if (props.mode === 'closeable') { + state.show = false; + emit('close', event); + } + }; + + const renderRightIcon = () => { if (slots['right-icon']) { return slots['right-icon'](); } - let iconName; - if (mode === 'closeable') { - iconName = 'cross'; - } else if (mode === 'link') { - iconName = 'arrow'; - } - - if (iconName) { + const name = getRightIconName(); + if (name) { return ( ); } - } + }; - return ( -