You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
3.7 KiB
Vue
145 lines
3.7 KiB
Vue
<template>
|
|
<view v-if="show" :class="`wd-notice-bar ${customClass} ${noticeBarClass}`" :style="`color: ${color}; background: ${backgroundColor};`">
|
|
<wd-icon v-if="prefix" custom-class="wd-notice-bar__prefix" size="18px" :name="prefix"></wd-icon>
|
|
<slot v-else name="prefix"></slot>
|
|
<view class="wd-notice-bar__wrap">
|
|
<view class="wd-notice-bar__content" :animation="animation" @transitionend="animationEnd">
|
|
{{ text }}
|
|
<slot></slot>
|
|
</view>
|
|
</view>
|
|
<wd-icon v-if="closable" custom-class="wd-notice-bar__suffix" size="18px" name="close-bold" @click="handleClose"></wd-icon>
|
|
<slot v-else name="suffix"></slot>
|
|
</view>
|
|
</template>
|
|
<script lang="ts">
|
|
export default {
|
|
name: 'wd-notice-bar',
|
|
options: {
|
|
virtualHost: true,
|
|
addGlobalClass: true,
|
|
styleIsolation: 'shared'
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<script lang="ts" setup>
|
|
import { onBeforeMount, ref, watch } from 'vue'
|
|
import { getRect } from '../common/util'
|
|
import { getCurrentInstance } from 'vue'
|
|
import { nextTick } from 'vue'
|
|
|
|
const $wrap = '.wd-notice-bar__wrap'
|
|
const $content = '.wd-notice-bar__content'
|
|
|
|
type NoticeBarType = 'warning' | 'info' | 'danger' | ''
|
|
interface Props {
|
|
customClass?: string
|
|
text?: string
|
|
type?: NoticeBarType
|
|
scrollable?: boolean
|
|
delay?: number
|
|
speed?: number
|
|
closable?: boolean
|
|
wrapable?: boolean
|
|
prefix?: string
|
|
color?: string
|
|
backgroundColor?: string
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
customClass: '',
|
|
type: 'warning',
|
|
scrollable: true,
|
|
delay: 1,
|
|
speed: 50,
|
|
closable: false,
|
|
wrapable: false
|
|
})
|
|
|
|
const firstPlay = ref<boolean>(true)
|
|
const wrapWidth = ref<number>(0)
|
|
const contentWidth = ref<number>(0)
|
|
const show = ref<boolean>(true)
|
|
const duration = ref<number>(0)
|
|
const animation = ref<string>('')
|
|
const noticeBarClass = ref<string>('')
|
|
|
|
const { proxy } = getCurrentInstance() as any
|
|
|
|
watch(
|
|
[() => props.type, () => props.scrollable, () => props.wrapable],
|
|
() => {
|
|
computedClass()
|
|
},
|
|
{ deep: true, immediate: true }
|
|
)
|
|
|
|
watch(
|
|
[() => props.text],
|
|
() => {
|
|
nextTick(() => {
|
|
scroll()
|
|
})
|
|
},
|
|
{ deep: true, immediate: true }
|
|
)
|
|
|
|
onBeforeMount(() => {
|
|
computedClass()
|
|
})
|
|
|
|
const emit = defineEmits(['close'])
|
|
|
|
function computedClass() {
|
|
const { type, wrapable, scrollable } = props
|
|
let noticeBarClasses: string[] = []
|
|
type && noticeBarClasses.push(`is-${type}`)
|
|
!wrapable && !scrollable && noticeBarClasses.push('wd-notice-bar--ellipse')
|
|
wrapable && !scrollable && noticeBarClasses.push('wd-notice-bar--wrap')
|
|
noticeBarClass.value = noticeBarClasses.join(' ')
|
|
}
|
|
function handleClose() {
|
|
show.value = false
|
|
emit('close')
|
|
}
|
|
|
|
function initAnimation(duration, delay, translate) {
|
|
const ani = uni
|
|
.createAnimation({
|
|
duration,
|
|
delay
|
|
})
|
|
.translateX(translate)
|
|
ani.step()
|
|
return ani.export()
|
|
}
|
|
|
|
function scroll() {
|
|
Promise.all([getRect($wrap, false, proxy), getRect($content, false, proxy)]).then((rects) => {
|
|
const [wrapRect, contentRect] = rects as UniApp.NodeInfo[]
|
|
if (!wrapRect || !contentRect || !wrapRect.width || !contentRect.width) return
|
|
|
|
const wrapWidthTemp = wrapRect.width
|
|
const contentWidthTemp = contentRect.width
|
|
if (props.scrollable && contentWidthTemp > wrapWidthTemp) {
|
|
animation.value = initAnimation((contentWidthTemp / props.speed) * 1000, props.delay * 1000, -contentWidthTemp)
|
|
wrapWidth.value = wrapWidthTemp
|
|
contentWidth.value = contentWidthTemp
|
|
}
|
|
})
|
|
}
|
|
|
|
function animationEnd() {
|
|
animation.value = initAnimation(0, 0, wrapWidth.value)
|
|
const timer = setTimeout(() => {
|
|
animation.value = initAnimation(((wrapWidth.value + contentWidth.value) / props.speed) * 1000, 0, -contentWidth.value)
|
|
clearTimeout(timer)
|
|
}, 20)
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
@import './index.scss';
|
|
</style>
|