货无忧
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

237 lines
5.3 KiB

<template>
<view :class="rootClass" :style="rootStyle" @click="onClick">
<view :class="contentClass" :style="contentStyle">
<block v-if="$slots.default">
<slot />
</block>
<block v-else>
<view class="hd-grid-item-icon">
<hd-icon v-if="icon" :name="icon" :color="iconColor" :class-prefix="iconPrefix" :size="iconSize" />
<slot v-else name="icon"></slot>
</view>
<view class="hd-grid-item-text">
<text v-if="text">{{ text }}</text>
<slot v-else name="text"></slot>
</view>
</block>
</view>
</view>
</template>
<script lang="ts" setup>
import { computed, inject, onBeforeMount, ref, Ref } from 'vue'
import { CommonUtil } from '../..'
/**
* GridItem 宫格布局项
*/
type LinkType = 'navigateTo' | 'redirectTo' | 'switchTab' | 'reLaunch'
interface Props {
// 图标名称或图片链接,可选值见 Icon 组件
icon?: string
// 图标颜色
iconColor?: string
// 第三方图标前缀
iconPrefix?: string
// 文字
text?: string
// 点击后跳转的链接地址
url?: string
// 链接跳转类型,可选值为 redirectTo switchTab reLaunch
linkType?: LinkType
}
const props = withDefaults(defineProps<Props>(), {
iconPrefix: 'fant-icon',
linkType: 'navigateTo'
})
const grid: any = inject('$grid')
const children: Ref<string[]> | undefined = inject('children')
const uid = ref<string>(CommonUtil.s4() + Math.random())
onBeforeMount(() => {
children && children.value && children.value.push(uid.value)
})
/**
* 文字字体大小
*/
const iconSize = computed(() => {
const { iconSize } = grid
return iconSize || '56rpx'
})
/**
* 最外层样式
*/
const rootStyle = computed(() => {
const { columnNum, square, gutter } = grid
const width = 100 / columnNum + '%'
let index: number = -1
if (children && children.value && children.value.length) {
index = children.value.indexOf(uid.value)
}
return CommonUtil.style({
width: width,
'padding-top': square ? width : null,
'padding-right': CommonUtil.addUnit(gutter),
'margin-top': index >= columnNum && !square ? CommonUtil.addUnit(gutter) : null
})
})
// 最外层类
const rootClass = computed(() => {
const { square } = grid
let rootClass = 'hd-grid-item'
if (square) {
rootClass = `${rootClass} hd-grid-item--square`
}
return rootClass
})
/**
* 内容样式
*/
const contentStyle = computed(() => {
const { square, gutter } = grid
return square
? CommonUtil.style({
right: CommonUtil.addUnit(CommonUtil.getPx(gutter), 'px'),
bottom: CommonUtil.addUnit(CommonUtil.getPx(gutter), 'px'),
height: 'auto'
})
: ''
})
/**
* 内容类
*/
const contentClass = computed(() => {
const { direction, center, square, reverse, gutter, clickable, border } = grid
const surround = border && gutter
let contentClass = 'hd-grid-item-content'
if (surround) {
contentClass = `${contentClass} hd-grid-item-content--surround`
}
if (center) {
contentClass = `${contentClass} hd-grid-item-content--center`
}
if (square) {
contentClass = `${contentClass} hd-grid-item-content--square`
}
if (reverse) {
contentClass = `${contentClass} hd-grid-item-content--reverse`
}
if (clickable) {
contentClass = `${contentClass} hd-grid-item-content--clickable`
}
if (border) {
contentClass = `${contentClass} hd-hairline--surround`
}
contentClass = `${contentClass} hd-grid-item-content--${direction}`
return contentClass
})
const emit = defineEmits(['click'])
function onClick() {
/**
* 点击格子时触发
*/
emit('click')
if (props.url) {
if (props.linkType === 'navigateTo' && getCurrentPages().length > 9) {
uni.redirectTo({ url: props.url })
} else {
uni[props.linkType]({ url: props.url })
}
}
}
</script>
<style lang="scss" scoped>
@import '../../libs/css/index.scss';
.hd-grid-item {
position: relative;
float: left;
box-sizing: border-box;
&--square {
height: 0;
}
&-content {
display: flex;
flex-direction: column;
box-sizing: border-box;
height: 100%;
padding: $grid-item-content-padding;
background-color: $grid-item-content-background-color;
&::after {
z-index: 1;
border-width: 0 $border-width-base $border-width-base 0;
}
&--surround {
&::after {
border-width: $border-width-base;
}
}
&--center {
align-items: center;
justify-content: center;
}
&--square {
position: absolute;
top: 0;
right: 0;
left: 0;
}
&--horizontal {
flex-direction: row;
.hd-grid-item-text {
margin: 0 0 0 $padding-xs !important;
}
}
&--reverse {
flex-direction: column-reverse;
.hd-grid-item-text {
margin: 0 0 $padding-xs;
}
}
&--horizontal,
&--reverse {
flex-direction: row-reverse;
.hd-grid-item-text {
margin: 0 $padding-xs 0 0;
}
}
&--clickable:active {
background-color: $grid-item-content-active-color;
}
}
&-icon {
display: flex;
align-items: center;
font-size: $grid-item-icon-size;
height: $grid-item-icon-size;
}
&-text {
word-wrap: break-word;
color: $grid-item-text-color;
font-size: $grid-item-text-font-size;
}
&-icon + &-text {
margin-top: 8px;
}
}
</style>