货无忧
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.
 
 
 
 
 

382 lines
8.1 KiB

<template>
<view v-if="show" :class="['hd-notice', 'hd-' + type]" @click="onClick">
<image v-if="leftIcon" class="hd-image-32" :src="leftIcon" />
<view
class="hd-notice__content-wrapper"
:class="{
'hd-notice__content-wrapper--scrollable': scrollable,
'hd-notice__content-wrapper--single': !scrollable && single
}"
>
<view
:id="elIdBox"
class="hd-notice__content"
:class="{
'hd-notice__content--scrollable': scrollable,
'hd-notice__content--single': !scrollable && single
}"
>
<text
:id="elId"
ref="animationEle"
class="hd-notice__content-text"
:class="{
'hd-notice__content-text--scrollable': scrollable,
'hd-notice__content-text--single': !scrollable && single
}"
:style="{
width: wrapWidth + 'px',
animationDuration: animationDuration,
animationPlayState: webviewHide ? 'paused' : animationPlayState,
animationDelay: animationDelay
}"
>
{{ title }}
</text>
</view>
</view>
<view v-if="showRightIcon || getCount" class="hd-notice__more" @click="rightClick">
<text v-if="getCount" class="hd-notice__count">{{ getCount }}</text>
<text v-if="showRightIcon" class="hd-notice-icon" :class="rightIcon"></text>
</view>
</view>
</template>
<script lang="ts" setup>
import { computed, getCurrentInstance, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
import { CommonUtil } from '../..'
/**
* Notice 通知栏
*
*/
type NoticeType = 'default' | 'primary' | 'error' | 'warning' | 'success'
interface Props {
// 标题名称
title: string
// 类型
type?: NoticeType
// 背景色
backgroundColor?: string
// 文字滚动的速度px/s
speed?: number
// 左侧icon
leftIcon?: string
// 是否单行
single?: boolean
// 是否滚动,添加后控制单行效果取消
scrollable?: boolean
// 消息数量
count?: number
// 右侧icon
rightIcon?: string
// 是否显示右侧icon
showRightIcon?: boolean
}
const props = withDefaults(defineProps<Props>(), {
// 标题名称
title: '999999',
// 类型
type: 'default',
// 背景色
backgroundColor: '#E9F0FF',
// 文字滚动的速度px/s
speed: 100,
// 左侧icon
leftIcon: '',
// 是否单行
single: false,
// 是否滚动,添加后控制单行效果取消
scrollable: false,
// 消息数量
count: 0,
// 右侧icon
rightIcon: 'hdIcon-arrow-right',
// 是否显示右侧icon
showRightIcon: false
})
const textWidth = ref<number>(0)
const boxWidth = ref<number>(0)
const wrapWidth = ref<string>('')
const webviewHide = ref<boolean>(false)
// #ifdef APP-NVUE
const stopAnimation = ref<boolean>(false)
// #endif
const elId = ref<string>(`el_${CommonUtil.uuid()}`)
const elIdBox = ref<string>(`elbox_${CommonUtil.uuid()}`)
const show = ref<boolean>(true)
const animationDuration = ref<string>('none')
const animationPlayState = ref<string>('paused')
const animationDelay = ref<string>('0s')
onMounted(() => {
// #ifdef APP-PLUS
const pages = getCurrentPages()
const page = pages[pages.length - 1] as any
const currentWebview = page.$getAppWebview()
currentWebview.addEventListener('hide', () => {
webviewHide.value = true
})
currentWebview.addEventListener('show', () => {
webviewHide.value = false
})
// #endif
nextTick(() => {
initSize()
})
})
// #ifdef APP-NVUE
onBeforeUnmount(() => {
stopAnimation.value = true
})
// #endif
const getCount = computed(() => {
return props.count > 99 ? '99+' : props.count
})
const { proxy } = getCurrentInstance() as any
const emit = defineEmits(['right', 'left', 'click'])
function initSize() {
if (props.scrollable) {
// #ifndef APP-NVUE
const query: Promise<any>[] = []
const textQuery = new Promise((resolve, reject) => {
uni
.createSelectorQuery()
// #ifndef MP-ALIPAY
.in(proxy)
// #endif
.select(`#${elId.value}`)
.boundingClientRect()
.exec((ret) => {
textWidth.value = ret[0].width
resolve({})
})
})
const boxQuery = new Promise((resolve, reject) => {
uni
.createSelectorQuery()
// #ifndef MP-ALIPAY
.in(proxy)
// #endif
.select(`#${elIdBox.value}`)
.boundingClientRect()
.exec((ret) => {
boxWidth.value = ret[0].width
resolve({})
})
})
query.push(textQuery)
query.push(boxQuery)
Promise.all(query).then(() => {
animationDuration.value = `${textWidth.value / props.speed}s`
animationDelay.value = `-${boxWidth.value / props.speed}s`
setTimeout(() => {
animationPlayState.value = 'running'
}, 1000)
})
// #endif
}
}
function rightClick() {
/**
* 左图标被点击时触发
*/
emit('right')
}
function leftClick() {
/**
* 右图标被点击触发
*/
emit('left')
}
function onClick() {
/**
* Notice组件被点击时触发
*/
emit('click')
}
function close() {
show.value = false
}
</script>
<style lang="scss" scoped>
.hd-notice {
/* #ifndef APP-NVUE */
display: flex;
width: 100%;
box-sizing: border-box;
/* #endif */
flex-direction: row;
align-items: center;
padding: 8px 12px;
margin-bottom: 10px;
font-size: 0px;
color: $color-white;
}
.hd-notice-close {
margin-right: 5px;
}
.hd-notice-icon {
margin: 0 5px;
font-size: 18px;
font-weight: 500;
}
.hd-notice__content-wrapper {
flex: 1;
flex-direction: column;
overflow: hidden;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
.hd-notice__content-wrapper--single {
/* #ifndef APP-NVUE */
line-height: 18px;
/* #endif */
}
.hd-notice__content-wrapper--single,
.hd-notice__content-wrapper--scrollable {
flex-direction: row;
}
/* #ifndef APP-NVUE */
.hd-notice__content-wrapper--scrollable {
position: relative;
height: 18px;
}
/* #endif */
.hd-notice__content--scrollable {
/* #ifdef APP-NVUE */
flex: 0;
/* #endif */
/* #ifndef APP-NVUE */
flex: 1;
display: block;
overflow: hidden;
/* #endif */
}
.hd-notice__content--single {
/* #ifndef APP-NVUE */
display: flex;
flex: none;
width: 100%;
justify-content: center;
/* #endif */
}
.hd-notice__content-text {
font-size: 14px;
line-height: 18px;
font-weight: 500;
margin-left: 6px;
/* #ifndef APP-NVUE */
word-break: break-all;
/* #endif */
}
.hd-notice__content-text--single {
/* #ifndef APP-NVUE */
display: block;
width: 100%;
white-space: nowrap;
/* #endif */
overflow: hidden;
text-overflow: ellipsis;
}
.hd-notice__content-text--scrollable {
/* #ifndef APP-NVUE */
position: absolute;
display: block;
height: 18px;
line-height: 18px;
white-space: nowrap;
padding-left: 100%;
animation: notice 10s 0s linear infinite both;
animation-play-state: paused;
/* #endif */
}
.hd-notice__more {
/* #ifndef APP-NVUE */
display: inline-flex;
/* #endif */
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
padding-left: 5px;
}
.hd-notice__more-text {
font-size: 14px;
}
.hd-notice__count {
display: inline-block;
padding: 0 2rpx;
min-width: 32rpx;
height: 32rpx;
line-height: 32rpx;
background: linear-gradient(180deg, rgba(255, 121, 121, 1) 0%, rgba(252, 44, 74, 1) 100%);
border-radius: 16rpx;
color: #ffffff;
font-weight: bold;
text-align: center;
font-size: 18rpx;
}
@keyframes notice {
100% {
transform: translate3d(-100%, 0, 0);
}
}
.hd-image-32 {
width: 32rpx;
height: 32rpx;
}
.hd-default {
color: $color-text-primary;
background: $color-global-bg;
}
.hd-primary {
color: $color-primary;
background: $color-primary-extra-lighter;
}
.hd-success {
color: $color-success;
background: $color-success-extra-lighter;
}
.hd-info {
color: $color-info;
background: $color-info-extra-lighter;
}
.hd-warning {
color: $color-warning;
background: $color-warning-extra-lighter;
}
.hd-error {
color: $color-error;
background: $color-error-extra-lighter;
}
</style>