123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- <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.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>
|