feat: Grid component
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
// Utils
|
||||
import { createNamespace, addUnit } from '../utils';
|
||||
import { BORDER } from '../utils/constant';
|
||||
import { route, routeProps } from '../utils/router';
|
||||
|
||||
// Mixins
|
||||
import { ChildrenMixin } from '../mixins/relation';
|
||||
|
||||
// Components
|
||||
import Info from '../info';
|
||||
import Icon from '../icon';
|
||||
|
||||
const [createComponent, bem] = createNamespace('grid-item');
|
||||
|
||||
export default createComponent({
|
||||
mixins: [ChildrenMixin('vanGrid')],
|
||||
|
||||
props: {
|
||||
...routeProps,
|
||||
dot: Boolean,
|
||||
text: String,
|
||||
icon: String,
|
||||
iconPrefix: String,
|
||||
badge: [Number, String],
|
||||
},
|
||||
|
||||
emits: ['click'],
|
||||
|
||||
computed: {
|
||||
style() {
|
||||
const { square, gutter, columnNum } = this.parent;
|
||||
const percent = `${100 / columnNum}%`;
|
||||
|
||||
const style = {
|
||||
flexBasis: percent,
|
||||
};
|
||||
|
||||
if (square) {
|
||||
style.paddingTop = percent;
|
||||
} else if (gutter) {
|
||||
const gutterValue = addUnit(gutter);
|
||||
style.paddingRight = gutterValue;
|
||||
|
||||
if (this.index >= columnNum) {
|
||||
style.marginTop = gutterValue;
|
||||
}
|
||||
}
|
||||
|
||||
return style;
|
||||
},
|
||||
|
||||
contentStyle() {
|
||||
const { square, gutter } = this.parent;
|
||||
|
||||
if (square && gutter) {
|
||||
const gutterValue = addUnit(gutter);
|
||||
|
||||
return {
|
||||
right: gutterValue,
|
||||
bottom: gutterValue,
|
||||
height: 'auto',
|
||||
};
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClick(event) {
|
||||
this.$emit('click', event);
|
||||
route(this.$router, this);
|
||||
},
|
||||
|
||||
genIcon() {
|
||||
if (this.$slots.icon) {
|
||||
return (
|
||||
<div class={bem('icon-wrapper')}>
|
||||
{this.$slots.icon()}
|
||||
<Info dot={this.dot} info={this.badge} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.icon) {
|
||||
return (
|
||||
<Icon
|
||||
name={this.icon}
|
||||
dot={this.dot}
|
||||
info={this.badge}
|
||||
size={this.parent.iconSize}
|
||||
class={bem('icon')}
|
||||
classPrefix={this.iconPrefix}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
getText() {
|
||||
if (this.$slots.text) {
|
||||
return this.$slots.text();
|
||||
}
|
||||
|
||||
if (this.text) {
|
||||
return <span class={bem('text')}>{this.text}</span>;
|
||||
}
|
||||
},
|
||||
|
||||
genContent() {
|
||||
if (this.$slots.default) {
|
||||
return this.$slots.default();
|
||||
}
|
||||
|
||||
return [this.genIcon(), this.getText()];
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
const {
|
||||
center,
|
||||
border,
|
||||
square,
|
||||
gutter,
|
||||
direction,
|
||||
clickable,
|
||||
} = this.parent;
|
||||
|
||||
return (
|
||||
<div class={[bem({ square })]} style={this.style}>
|
||||
<div
|
||||
style={this.contentStyle}
|
||||
role={clickable ? 'button' : null}
|
||||
tabindex={clickable ? 0 : null}
|
||||
class={[
|
||||
bem('content', [
|
||||
direction,
|
||||
{
|
||||
center,
|
||||
square,
|
||||
clickable,
|
||||
surround: border && gutter,
|
||||
},
|
||||
]),
|
||||
{ [BORDER]: border },
|
||||
]}
|
||||
onClick={this.onClick}
|
||||
>
|
||||
{this.genContent()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
@import '../style/var';
|
||||
|
||||
.van-grid-item {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
|
||||
&--square {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
font-size: @grid-item-icon-size;
|
||||
}
|
||||
|
||||
&__icon-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&__text {
|
||||
color: @grid-item-text-color;
|
||||
font-size: @grid-item-text-font-size;
|
||||
line-height: 1.5;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
&__icon + &__text {
|
||||
margin-top: @padding-xs;
|
||||
}
|
||||
|
||||
&__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;
|
||||
}
|
||||
|
||||
&--square {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&--center {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&--horizontal {
|
||||
flex-direction: row;
|
||||
|
||||
.van-grid-item__icon + .van-grid-item__text {
|
||||
margin-top: 0;
|
||||
margin-left: @padding-xs;
|
||||
}
|
||||
}
|
||||
|
||||
&--surround {
|
||||
&::after {
|
||||
border-width: @border-width-base;
|
||||
}
|
||||
}
|
||||
|
||||
&--clickable {
|
||||
cursor: pointer;
|
||||
|
||||
&:active {
|
||||
background-color: @grid-item-content-active-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user