添加bar组件
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
@import '@/uni_modules/lime-style/index.scss';
|
||||
@import '@/uni_modules/lime-style/mixins/ellipsis.scss';
|
||||
|
||||
/* #ifdef uniVersion >= 4.75 */
|
||||
$use-css-var: true;
|
||||
/* #endif */
|
||||
|
||||
$item: #{$prefix}-tabbar-item;
|
||||
|
||||
// 尺寸变量
|
||||
$tabbar-height: create-var(tabbar-height, 40px);
|
||||
$tabbar-font-size: create-var(tabbar-font-size, $font-size-md);
|
||||
$tabbar-min-font-size: create-var(tabbar-font-size, $font-size-sm);
|
||||
|
||||
// 颜色变量
|
||||
$tabbar-color: create-var(tabbar-color, $text-color-1);
|
||||
$tabbar-bg-color: create-var(tabbar-bg-color, $bg-color-container);
|
||||
$tabbar-active-color: create-var(tabbar-active-color, $primary-color);
|
||||
$tabbar-active-bg-color: create-var(tabbar-active-bg-color, $primary-color-1);
|
||||
|
||||
// 间距变量(新增)
|
||||
$tabbar-item-margin-x: create-var(tabbar-item-margin-x, 0); // 水平margin
|
||||
$tabbar-item-margin-y: create-var(tabbar-item-margin-y, 8px); // 垂直margin
|
||||
$tabbar-item-padding-x: create-var(tabbar-item-padding-x, 12px); // 水平padding
|
||||
$tabbar-item-padding-y: create-var(tabbar-item-padding-y, 0); // 垂直padding
|
||||
$tabbar-item-crowded-padding-x: create-var(tabbar-item-crowded-padding-x, 8px); // 拥挤状态水平padding
|
||||
|
||||
/* #ifdef MP */
|
||||
:host {
|
||||
flex: 1;
|
||||
}
|
||||
/* #endif */
|
||||
|
||||
.#{$item} {
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
box-sizing: border-box;
|
||||
user-select: none;
|
||||
display: flex;
|
||||
/* #endif */
|
||||
|
||||
flex: 1;
|
||||
height: $tabbar-height;
|
||||
position: relative;
|
||||
// margin: $tabbar-item-margin-y $tabbar-item-margin-x; // 使用拆分后的margin变量
|
||||
@include margin($tabbar-item-margin-y $tabbar-item-margin-x);
|
||||
background-color: $tabbar-bg-color;
|
||||
// padding: $tabbar-item-padding-y $tabbar-item-padding-x; // 使用拆分后的padding变量
|
||||
@include padding($tabbar-item-padding-y $tabbar-item-padding-x);
|
||||
overflow: visible;
|
||||
|
||||
&__icon {
|
||||
&-wrap {
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
|
||||
&--crowded {
|
||||
// padding: $tabbar-item-padding-y $tabbar-item-crowded-padding-x; // 拥挤状态使用专用变量
|
||||
@include padding($tabbar-item-padding-y $tabbar-item-padding-x);
|
||||
}
|
||||
|
||||
&--round {
|
||||
border-radius: 99px;
|
||||
}
|
||||
|
||||
&__content {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 16rpx;
|
||||
overflow: visible;
|
||||
|
||||
&--checked {
|
||||
/* #ifndef UNI-APP-X && APP */
|
||||
color: $tabbar-active-color;
|
||||
/* #endif */
|
||||
/* #ifndef UNI-APP-X */
|
||||
.l-tabbar-item__text {
|
||||
color: $tabbar-active-color;
|
||||
font-weight: 700;
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
&--disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
&--tag {
|
||||
border-radius: 99px;
|
||||
}
|
||||
|
||||
&--tag#{&}--checked {
|
||||
background-color: $tabbar-active-bg-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
color: $tabbar-color;
|
||||
}
|
||||
|
||||
&__text {
|
||||
color: $tabbar-color;
|
||||
&--small {
|
||||
font-size: $tabbar-min-font-size;
|
||||
padding-top: 4px;
|
||||
}
|
||||
&--only {
|
||||
font-size: $tabbar-font-size;
|
||||
}
|
||||
&--checked {
|
||||
color: $tabbar-active-color;
|
||||
font-weight: 700;
|
||||
}
|
||||
&--ellipsis {
|
||||
@include ellipsisLn(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<view class="l-tabbar-item" :class="classes">
|
||||
<view :class="contentClass" :style="[contentStyle]" @click="toggle">
|
||||
<view class="l-tabbar-item__icon-wrap" :style="[iconStyle]" v-if="icon != null || $slots['icon'] != null">
|
||||
<template v-if="(icon != null || $slots['icon'] != null) && badgeProps?.['dot'] == true || badgeProps?.['content'] != null">
|
||||
<l-badge
|
||||
:dot="badgeProps?.['dot'] == true"
|
||||
:max="badgeProps?.['max'] ?? 99"
|
||||
:offset="badgeProps?.['offset'] ?? [0, 0]"
|
||||
:content="badgeProps?.['content']">
|
||||
<slot name="icon">
|
||||
<l-icon class="l-tabbar-item__icon"
|
||||
:class="{'l-tabbar-item__text--checked': isChecked}"
|
||||
:name="icon" :size="iconSize" :color="colorStyle['color']">
|
||||
</l-icon>
|
||||
</slot>
|
||||
</l-badge>
|
||||
</template>
|
||||
<template v-else-if="(icon != null || $slots['icon'] != null)">
|
||||
<slot name="icon">
|
||||
<l-icon class="l-tabbar-item__icon"
|
||||
:class="{'l-tabbar-item__text--checked': isChecked}"
|
||||
:name="icon" :size="iconSize" :color="colorStyle['color']">
|
||||
</l-icon>
|
||||
</slot>
|
||||
</template>
|
||||
</view>
|
||||
<text
|
||||
v-if="label != null || $slots['default'] != null"
|
||||
class="l-tabbar-item__text"
|
||||
:class="{
|
||||
'l-tabbar-item__text--small': icon != null,
|
||||
'l-tabbar-item__text--only': icon == null,
|
||||
'l-tabbar-item__text--checked': isChecked,
|
||||
'l-tabbar-item__text--ellipsis': ellipsis
|
||||
}"
|
||||
:style="[colorStyle, textStyle]">
|
||||
<slot>{{label}}</slot>
|
||||
</text>
|
||||
<slot name="extra"></slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="uts" setup>
|
||||
/**
|
||||
* TabbarItem 底部导航项组件
|
||||
* @description 用于构建Tabbar的单个导航项,必须作为Tabbar的子组件使用
|
||||
* <br>插件类型:LTabbarItemComponentPublicInstance
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-tabbar
|
||||
*
|
||||
* @property {Object} badgeProps 徽标配置(支持uni-badge所有属性)
|
||||
* @property {string} icon 图标名称(支持uni-icons或自定义图标)
|
||||
* @property {string} value 唯一标识符(用于v-model绑定)
|
||||
* @property {string} label 文本标签
|
||||
* @property {boolean} disabled 是否禁用(默认:false)
|
||||
* @property {boolean} ellipsis 是否超一行省略(默认:false)
|
||||
*/
|
||||
|
||||
|
||||
import { TabbarProvide } from '../l-tabbar/type';
|
||||
import { TabbarItemProps } from './type';
|
||||
import {addUnit} from '@/uni_modules/lime-shared/addUnit'
|
||||
const themeVars = inject('limeConfigProviderThemeVars', computed(()=> ({})))
|
||||
|
||||
const name = 'l-tabbar-item';
|
||||
const props = withDefaults(defineProps<TabbarItemProps>(), {
|
||||
disabled: false,
|
||||
ellipsis: false
|
||||
})
|
||||
|
||||
const instance = getCurrentInstance()!
|
||||
const parent = inject<TabbarProvide|null>('limeTabbar', null);
|
||||
const index = ref(0)
|
||||
const currentName = computed(():string=> props.value ?? `${index.value}`)
|
||||
|
||||
|
||||
// @ts-ignore
|
||||
const crowded = computed((): boolean => parent != null && parent.children.value.length > 3)
|
||||
const isChecked = computed((): boolean => currentName.value == parent?.activeValue.value);
|
||||
|
||||
const classes = computed(():Map<string, any>=>{
|
||||
const cls = new Map<string, any>()
|
||||
const split = parent?.props.split ?? false;
|
||||
const shape = parent?.props.shape ?? false;
|
||||
cls.set(`${name}--split`, split);
|
||||
cls.set(`${name}--${shape}`, true);
|
||||
cls.set(`${name}--text-only`, props.icon == null)
|
||||
cls.set(`${name}--crowded`, crowded.value)
|
||||
|
||||
return cls
|
||||
})
|
||||
const contentClass = computed(():Map<string, any>=> {
|
||||
const cls = new Map<string, any>()
|
||||
const theme = parent?.props.theme;
|
||||
cls.set(`${name}__content`, true)
|
||||
cls.set(`${name}__content--checked`, isChecked.value)
|
||||
cls.set(`${name}__content--disabled`, props.disabled)
|
||||
cls.set(`${name}__content--${theme}`, true)
|
||||
return cls
|
||||
})
|
||||
const contentStyle = computed(():UTSJSONObject=>{
|
||||
const style = {}
|
||||
const activeBgColor = parent?.props.activeBgColor;
|
||||
|
||||
if(activeBgColor != null && isChecked.value){
|
||||
style.set('background', activeBgColor)
|
||||
}
|
||||
return style
|
||||
})
|
||||
const colorStyle = computed(():UTSJSONObject => {
|
||||
const style = {}
|
||||
// #ifdef APP
|
||||
// 安卓 深层文本样式不生效 bug https://issues.dcloud.net.cn/pages/issues/detail?id=11930
|
||||
const activeColor:any|null = parent?.props.activeColor ?? themeVars.value['tabbarActiveColor'] ?? '#3283ff'
|
||||
const color:any|null = parent?.props.color ?? themeVars.value['tabbarColor'] ?? 'rgba(0,0,0,0.88)'
|
||||
// #endif
|
||||
// #ifndef APP
|
||||
const activeColor = parent?.props.activeColor
|
||||
const color = parent?.props.color
|
||||
// #endif
|
||||
|
||||
if(activeColor != null && isChecked.value){
|
||||
style.set('color', `${activeColor}`)
|
||||
}
|
||||
if(color != null && !isChecked.value){
|
||||
style.set('color', `${color}`)
|
||||
}
|
||||
return style
|
||||
})
|
||||
const textStyle = computed(():UTSJSONObject=>{
|
||||
const style = {}
|
||||
const fontSize = parent?.props.fontSize
|
||||
if(fontSize != null){
|
||||
style.set('font-size', fontSize)
|
||||
}
|
||||
return style
|
||||
})
|
||||
// @ts-ignore
|
||||
const iconSize = computed(():string => addUnit(parent?.props.iconSize ?? (props.icon !=null && instance.slots['default'] == null ? 24 : 20))!)
|
||||
const iconStyle = computed(():Map<string, any> =>{
|
||||
const style = new Map<string, any>()
|
||||
style.set('height', iconSize.value);
|
||||
return style
|
||||
})
|
||||
|
||||
const toggle = ()=>{
|
||||
if(props.disabled || isChecked.value || parent == null) return
|
||||
parent.updateChild(currentName.value)
|
||||
// parent!.activeValue.value = currentName.value
|
||||
}
|
||||
onMounted(()=>{
|
||||
if(parent == null) return
|
||||
parent.defaultIndex.value +=1;
|
||||
index.value = parent.defaultIndex.value;
|
||||
parent.children.value.push(instance.proxy! as LTabbarItemComponentPublicInstance)
|
||||
})
|
||||
onUnmounted(()=>{
|
||||
// @ts-ignore
|
||||
if(parent == null) return
|
||||
const _index = parent.children.value.indexOf(instance.proxy! as LTabbarItemComponentPublicInstance);
|
||||
parent.children.value.splice(_index, 1);
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import './index-u';
|
||||
</style>
|
||||
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<view class="l-tabbar-item" :class="classes">
|
||||
<view :class="contentClass" :style="[contentStyles]" @click="toggle">
|
||||
<view class="l-tabbar-item__icon-wrap" :style="[iconStyle]" v-if="icon">
|
||||
<!-- <l-badge
|
||||
v-if="(icon || $slots.icon) && (badgeProps.dot || badgeProps.content)"
|
||||
:dot="badgeProps.dot || false"
|
||||
:max="badgeProps.max || 99"
|
||||
:content="badgeProps.content || 0">
|
||||
<slot icon="icon"></slot>
|
||||
<l-icon :name="icon"></l-icon>
|
||||
</l-badge>
|
||||
<slot icon="icon" v-else-if="$slots.icon"></slot>
|
||||
<l-icon v-else-if="icon" :name="icon"></l-icon> -->
|
||||
|
||||
|
||||
<template v-if="(icon || $slots.icon) && (badgeProps.dot || badgeProps.content)" >
|
||||
<l-badge
|
||||
:dot="badgeProps.dot || false"
|
||||
:max="badgeProps.max || 99"
|
||||
:offset="badgeProps.offset || [0, 0]"
|
||||
:content="badgeProps.content || 0">
|
||||
<slot name="icon">
|
||||
<l-icon :name="icon" ></l-icon>
|
||||
</slot>
|
||||
</l-badge>
|
||||
</template>
|
||||
<template v-else-if="icon || $slots.icon">
|
||||
<slot name="icon">
|
||||
<l-icon :name="icon"></l-icon>
|
||||
</slot>
|
||||
</template>
|
||||
|
||||
</view>
|
||||
<view class="l-tabbar-item__text"
|
||||
:class="{
|
||||
'l-tabbar-item__text--small': !!icon,
|
||||
'l-tabbar-item__text--only': !icon,
|
||||
'l-tabbar-item__text--ellipsis': ellipsis
|
||||
}">
|
||||
<slot>{{label}}</slot>
|
||||
</view>
|
||||
<slot name="extra"></slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* TabbarItem 底部导航项组件
|
||||
* @description 用于构建Tabbar的单个导航项,必须作为Tabbar的子组件使用
|
||||
* <br>插件类型:LTabbarItemComponentPublicInstance
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-tabbar
|
||||
*
|
||||
* @property {Object} badgeProps 徽标配置(支持uni-badge所有属性)
|
||||
* @property {string} icon 图标名称(支持uni-icons或自定义图标)
|
||||
* @property {string} value 唯一标识符(用于v-model绑定)
|
||||
* @property {string} label 文本标签
|
||||
* @property {boolean} disabled 是否禁用(默认:false)
|
||||
* @property {boolean} ellipsis 是否超一行省略(默认:false)
|
||||
*/
|
||||
|
||||
import {ref, defineComponent, computed, inject, getCurrentInstance, onUnmounted} from '@/uni_modules/lime-shared/vue';
|
||||
import tabbarProps from './props'
|
||||
import {addUnit} from '@/uni_modules/lime-shared/addUnit'
|
||||
const name = `l-tabbar-item`
|
||||
export default defineComponent({
|
||||
name,
|
||||
props: tabbarProps,
|
||||
setup(props) {
|
||||
const context = getCurrentInstance()
|
||||
const { split, shape, theme, defaultIndex, activeValue, updateChild, children, activeColor, color, activeBgColor, iconSize, fontSize } = inject('tab-bar');
|
||||
defaultIndex.value += 1
|
||||
const currentName = props.value || defaultIndex.value
|
||||
children.value.push(context.uid)
|
||||
// 拥挤
|
||||
const crowded = computed(() => children.value.length > 3)
|
||||
const isChecked = computed(() => {
|
||||
return currentName === activeValue.value;
|
||||
});
|
||||
const classes = computed(() => {
|
||||
const cls = [`${name}--${shape.value}`];
|
||||
if(split.value) {
|
||||
cls.push(`${name}--split`)
|
||||
}
|
||||
if(!props.icon) {
|
||||
cls.push(`${name}--text-only`)
|
||||
}
|
||||
if(crowded.value) {
|
||||
cls.push(`${name}--crowded`)
|
||||
}
|
||||
return cls.join(' ')
|
||||
// return {
|
||||
// // [`${name}`]: true,
|
||||
// [`${name}--split`]: split.value,
|
||||
// [`${name}--text-only`]: !props.icon,
|
||||
// [`${name}--crowded`]: crowded.value,
|
||||
// [`${name}--${shape.value}`]: true,
|
||||
// }
|
||||
})
|
||||
const contentClass = computed(() => {
|
||||
const cls = [`${name}__content`, `${name}__content--${theme.value}`];
|
||||
if(isChecked.value) {
|
||||
cls.push(`${name}__content--checked`)
|
||||
}
|
||||
if(props.disabled) {
|
||||
cls.push(`${name}__content--disabled`)
|
||||
}
|
||||
return cls.join(' ')
|
||||
// return {
|
||||
// [`${name}__content`]: true,
|
||||
// [`${name}__content--checked`]: isChecked.value,
|
||||
// [`${name}__content--disabled`]: props.disabled,
|
||||
// [`${name}__content--${theme.value}`]: true,
|
||||
// }
|
||||
})
|
||||
const contentStyles = computed(() => {
|
||||
const style:Record<string, string> = {}
|
||||
if(fontSize.value) {
|
||||
style['font-size'] = fontSize.value
|
||||
}
|
||||
if(activeBgColor.value) {
|
||||
style['background'] = activeBgColor.value
|
||||
}
|
||||
|
||||
if(activeColor.value || color.value) {
|
||||
style['color'] = isChecked.value ? activeColor.value : color.value
|
||||
}
|
||||
if(activeColor.value) {
|
||||
style['--l-tabbar-active-color'] = activeColor.value
|
||||
}
|
||||
if(color.value) {
|
||||
style['--l-tabbar-color'] = color.value
|
||||
}
|
||||
return style
|
||||
})
|
||||
const iconStyle = computed(() => {
|
||||
const size = addUnit(iconSize.value || (props.icon && !context.slots.default ? 24 : 20))
|
||||
return {
|
||||
height: size,
|
||||
fontSize: size
|
||||
}
|
||||
})
|
||||
const toggle = () => {
|
||||
if(props.disabled) return
|
||||
updateChild(currentName);
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
const index = children.value.indexOf(context.uid);
|
||||
children.value.splice(index, 1);
|
||||
})
|
||||
return {
|
||||
classes,
|
||||
contentClass,
|
||||
contentStyles,
|
||||
iconStyle,
|
||||
|
||||
toggle
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import './index-u';
|
||||
</style>
|
||||
@@ -0,0 +1,28 @@
|
||||
// @ts-nocheck
|
||||
export default {
|
||||
/** 图标右上角提示信息 */
|
||||
badgeProps: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
/** 图标名称 */
|
||||
icon: {
|
||||
type: String,
|
||||
},
|
||||
/** 标识符 */
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: null
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
label: {
|
||||
type: String
|
||||
},
|
||||
ellipsis: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
// @ts-nocheck
|
||||
// #ifndef UNI-APP-X
|
||||
type UTSJSONObject = Object
|
||||
// #endif
|
||||
|
||||
|
||||
export interface TabbarItemProps {
|
||||
/**
|
||||
* 图标右上角提示信息
|
||||
*/
|
||||
badgeProps?: UTSJSONObject;
|
||||
/**
|
||||
* 图标名称
|
||||
*/
|
||||
icon?: string;
|
||||
/**
|
||||
* 标识符
|
||||
*/
|
||||
value?: string;
|
||||
label?: string;
|
||||
disabled: boolean;
|
||||
/**
|
||||
* 文本超过时是否显示省略号
|
||||
*/
|
||||
ellipsis: boolean;
|
||||
}
|
||||
Reference in New Issue
Block a user