首次提交:初始化项目代码
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
<template>
|
||||
<view class="empty-state" :class="['type-' + type, { compact: compact }]" :style="wrapperStyle">
|
||||
<view class="empty-illustration" :style="illustrationStyle">
|
||||
<!-- 圆形光晕背景 -->
|
||||
<view class="illustration-halo" :style="haloStyle"></view>
|
||||
<!-- emoji 图标(微信小程序兼容方案) -->
|
||||
<text class="illustration-emoji">{{ emojiIcon }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="title" class="empty-title">{{ title }}</view>
|
||||
<view v-if="desc" class="empty-desc">{{ desc }}</view>
|
||||
|
||||
<view v-if="actionText" class="empty-action btn btn--primary btn--pill" @tap="onAction">
|
||||
<text class="action-text">{{ actionText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import themeMixin from '@/mixins/themeMixin.js'
|
||||
import { THEME_CHANGE_EVENT } from '@/utils/theme'
|
||||
|
||||
// 类型→emoji 映射(微信小程序不支持 inline SVG,使用 emoji 替代)
|
||||
const EMOJI_MAP = {
|
||||
'default': '📂',
|
||||
'no-data': '📂',
|
||||
'no-network': '📡',
|
||||
'no-search': '🔍',
|
||||
'mood': '📅',
|
||||
'bill': '💰',
|
||||
'todo': '📋',
|
||||
'review': '✍️',
|
||||
'growth': '🏆',
|
||||
'error': '⚠️'
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'EmptyState',
|
||||
mixins: [themeMixin],
|
||||
props: {
|
||||
// 缺省类型:default / no-data / no-network / no-search / mood / bill / todo / review / growth / error
|
||||
type: { type: String, default: 'default' },
|
||||
title: { type: String, default: '暂无数据' },
|
||||
desc: { type: String, default: '' },
|
||||
actionText: { type: String, default: '' },
|
||||
compact: { type: Boolean, default: false }
|
||||
},
|
||||
computed: {
|
||||
emojiIcon() {
|
||||
return EMOJI_MAP[this.type] || EMOJI_MAP['default']
|
||||
},
|
||||
wrapperStyle() {
|
||||
return {
|
||||
backgroundColor: this.themeConfig.bgColor
|
||||
}
|
||||
},
|
||||
illustrationStyle() {
|
||||
return {}
|
||||
},
|
||||
haloStyle() {
|
||||
const primary = this.themeConfig.primaryColor
|
||||
return {
|
||||
background: `radial-gradient(circle, ${primary}33 0%, ${primary}0D 70%, transparent 100%)`
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 组件级钩子:EmptyState 不是 page,themeMixin 的 onLoad/onShow 不会触发
|
||||
// 这里手动监听主题变更事件,实时同步主题色
|
||||
if (typeof this.syncThemeConfig === 'function') {
|
||||
this.syncThemeConfig()
|
||||
}
|
||||
if (typeof this.watchThemeChange === 'function') {
|
||||
this.watchThemeChange()
|
||||
}
|
||||
},
|
||||
beforeUnmount() {
|
||||
// 组件销毁时清理监听(避免内存泄漏)
|
||||
if (this.themeChangeHandler) {
|
||||
uni.$off && uni.$off(THEME_CHANGE_EVENT, this.themeChangeHandler)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onAction() {
|
||||
this.$emit('action')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/uni.scss';
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40rpx;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
&.compact {
|
||||
padding: 40rpx 32rpx 32rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-illustration {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 16rpx;
|
||||
animation: emptyFloat 4s ease-in-out infinite;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 圆形光晕背景 */
|
||||
.illustration-halo {
|
||||
position: absolute;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 50%;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
/* emoji 图标 */
|
||||
.illustration-emoji {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
font-size: 50rpx;
|
||||
line-height: 1;
|
||||
text-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.compact .empty-illustration {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 8rpx;
|
||||
|
||||
.illustration-halo {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
}
|
||||
|
||||
.illustration-emoji {
|
||||
font-size: 72rpx;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes emptyFloat {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-6rpx); }
|
||||
}
|
||||
|
||||
.empty-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: v-bind('themeConfig.textPrimary');
|
||||
margin-top: 12rpx;
|
||||
letter-spacing: 0.5rpx;
|
||||
}
|
||||
|
||||
.empty-desc {
|
||||
font-size: 24rpx;
|
||||
color: v-bind('themeConfig.textSecondary');
|
||||
margin-top: 12rpx;
|
||||
text-align: center;
|
||||
line-height: 1.6;
|
||||
max-width: 480rpx;
|
||||
}
|
||||
|
||||
.empty-action {
|
||||
margin-top: 36rpx;
|
||||
}
|
||||
|
||||
.action-text {
|
||||
font-size: 28rpx;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user