261 lines
6.4 KiB
Vue
261 lines
6.4 KiB
Vue
<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>
|