This commit is contained in:
2025-08-12 15:04:01 +08:00
parent df3f5f5269
commit 6708fb8eeb
544 changed files with 75169 additions and 17 deletions
@@ -0,0 +1,50 @@
export default {
props: {
// 内容
label: {
type: String,
default: () => uni.$u.props.sidebarItem.label
},
// 值,用于标识该项
value: {
type: [String, Number],
default: ''
},
// 图标名称
icon: {
type: String,
default: () => uni.$u.props.sidebarItem.icon
},
// 图标大小
iconSize: {
type: [String, Number],
default: () => uni.$u.props.sidebarItem.iconSize
},
// 图标颜色
iconColor: {
type: String,
default: () => uni.$u.props.sidebarItem.iconColor
},
// 图标位置,支持 left 和 top
iconPosition: {
type: String,
default: () => uni.$u.props.sidebarItem.iconPosition,
validator: (value) => ['left', 'top'].includes(value)
},
// 右上角的角标提示信息
badge: {
type: [String, Number, Object],
default: () => uni.$u.props.sidebarItem.badge
},
// 是否显示圆点,将会覆盖badge参数
dot: {
type: Boolean,
default: () => uni.$u.props.sidebarItem.dot
},
// 是否禁用该项
disabled: {
type: Boolean,
default: () => uni.$u.props.sidebarItem.disabled
}
}
}
@@ -0,0 +1,260 @@
<template>
<view
class="u-sidebar-item"
:class="[`u-sidebar-item-${index}`]"
:style="[itemStyle]"
@click="handleClick"
hover-class="none"
>
<view class="u-sidebar-item__content" :class="[`u-sidebar-item__icon-${iconPosition}`]">
<slot>
<u-icon
v-if="icon"
:name="icon"
:size="iconSize"
:color="iconColor"
class="u-sidebar-item__icon"
></u-icon>
<text class="u-sidebar-item__text" >
{{ label }}
</text>
<u-badge
:isDot="propsBadge.isDot"
:value="propsBadge.value"
:type="propsBadge.type"
:max="propsBadge.max"
:showZero="propsBadge.showZero"
:bgColor="propsBadge.bgColor"
:color="propsBadge.color"
:shape="propsBadge.shape"
:numberType="propsBadge.numberType"
:inverted="propsBadge.inverted"
:customStyle="{
position: 'absolute',
right: '0',
top: '0',
transform: 'translate(50%, -50%)'
}"
></u-badge>
</slot>
</view>
<view
v-if="active && parentData.showLine"
class="u-sidebar-item__line"
:style="[lineStyle]"
></view>
</view>
</template>
<script>
import props from './props.js';
import mixin from '../../libs/mixin/mixin'
import mpMixin from '../../libs/mixin/mpMixin';
/**
* SidebarItem 侧边栏项
* @description 侧边栏的子组件,用于定义侧边栏的每一项
* @tutorial https://uview.d3u.cn/components/sidebar.html
*
* @property {String} label 内容
* @property {String | Number} value 值,用于标识该项
* @property {String} icon 图标名称
* @property {String | Number} iconSize 图标大小
* @property {String} iconColor 图标颜色
* @property {String} iconPosition 图标位置,支持 left 和 top
* @property {String | Number | Object} badge 右上角的角标提示信息,支持字符串、数字、对象类型
* @property {Boolean} dot 是否显示圆点,将会覆盖badge参数
* @property {Boolean} disabled 是否禁用该项
*
* @example
* <u-sidebar-item
* label="标签名称"
* icon="home"
* iconPosition="top"
* :badge="{ isDot: true, value: '5', type: 'error' }"
* />
*/
export default {
name: 'u-sidebar-item',
mixins: [mpMixin, mixin, props],
data() {
return {
index: 0,
parent: false, // 父组件实例
propsBadge: {
isDot: false,
value: '',
type: 'error',
max: 99,
showZero: false,
bgColor: '',
color: '',
shape: 'circle',
numberType: 'number',
inverted: false,
},
parentData: {
innerCurrent: 0,
width: '100px',
fontSize: '14px',
lineHeight: '22px',
textColor: '',
disabledColor: '',
disabledBgColor: '',
bgColor: '',
activeColor: '',
activeBgColor: 'white',
activeBold: true,
activeStyle: {},
inactiveStyle: {},
lineWidth: '4px',
lineHeight: '16px',
lineColor: '#1677ff',
lineBgSize: 'cover',
showLine: true,
}
}
},
watch: {
'parentData'(newValue, oldValue) {
// 父组件数据变化时的处理
},
badge: {
immediate: true,
handler(newVal) {
if (uni.$u.test.object(this.badge)) {
this.propsBadge = uni.$u.deepMerge(uni.$u.props.badge, this.badge);
} else {
this.propsBadge.value = this.badge || '';
}
}
}
},
created() {
// 父组件的实例
this.parent = false;
},
computed: {
active() {
return this.index === this.parentData.innerCurrent
},
itemStyle() {
const style = {}
if (this.disabled) {
// 禁用状态样式
if (this.parentData.disabledColor) style.color = this.parentData.disabledColor
if (this.parentData.disabledBgColor) style.backgroundColor = this.parentData.disabledBgColor
} else if (this.active) {
// 激活状态样式
if (this.parentData.activeBold) style.fontWeight = 'bold'
if (this.parentData.activeColor) style.color = this.parentData.activeColor
if (this.parentData.activeBgColor) style.backgroundColor = this.parentData.activeBgColor
return uni.$u.deepMerge(style, uni.$u.addStyle(this.parentData.activeStyle));
} else {
// 非激活状态样式
if (this.parentData.textColor) style.color = this.parentData.textColor
return uni.$u.deepMerge(style, uni.$u.addStyle(this.parentData.inactiveStyle));
}
return style
},
lineStyle() {
const style = {}
style.width = this.$u.addUnit(this.parentData.lineWidth)
style.height = this.$u.addUnit(this.parentData.lineHeight )
style.backgroundColor = this.parentData.lineColor
if (this.parentData.lineBgSize) {
style.backgroundSize = this.parentData.lineBgSize
}
return style
}
},
mounted() {
this.init();
},
methods: {
init() {
// 获取父组件u-sidebar
let parent = this.$u.$parent.call(this, 'u-sidebar');
if (parent) {
this.parent = parent;
// 将本组件的this,放入到父组件的children数组中,让父组件可以操作本(子)组件的方法和属性
// push进去前,显判断是否已经存在了本实例,因为在子组件内部数据变化时,会通过父组件重新初始化子组件
let exist = parent.children.find(val => {
return this === val;
})
if (!exist) parent.children.push(this);
// 更新父组件数据
this.updateParentData();
// 设置当前项的索引
this.index = parent.children.indexOf(this);
} else {
uni.$u.error('u-sidebar-item必须要搭配u-sidebar组件使用');
}
},
updateParentData() {
// 此方法在mixin中
this.getParentData('u-sidebar');
},
// 父组件数据发生变化
updateFromParent() {
this.init();
},
handleClick() {
if (this.disabled) return
// 优先使用value,如果没有value则使用index
const clickValue = this.value !== '' ? this.value : this.index;
// 通知父组件,参考u-dropdown-item的实现方式
if (this.parent && this.parent.handleItemClick) {
this.parent.handleItemClick(this.index);
}
}
}
}
</script>
<style lang="scss" scoped>
.u-sidebar-item {
position: relative;
padding: 20px 10px;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
user-select: none;
&__content {
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
&__icon {
flex-shrink: 0;
}
&__icon-top {
flex-direction: column;
}
&__icon-left {
flex-direction: row;
}
&__text {
text-align: center;
}
&__line {
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 16px;
border-radius: 2px;
}
}
</style>