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.
238 lines
5.3 KiB
238 lines
5.3 KiB
2 years ago
|
<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>
|