Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Block): add block component #12281

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/vant/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,15 @@
"dependencies": {
"@vant/popperjs": "workspace:^",
"@vant/use": "workspace:^",
"@vue/shared": "^3.0.0"
"@vue/shared": "^3.0.0",
"transliteration": "^2.3.5"
chenjiahan marked this conversation as resolved.
Show resolved Hide resolved
},
"peerDependencies": {
"vue": "^3.0.0"
},
"devDependencies": {
"@types/node": "^18.16.3",
"@types/transliteration": "^1.6.6",
"@vant/area-data": "workspace:*",
"@vant/cli": "workspace:*",
"@vant/eslint-config": "workspace:*",
Expand Down
69 changes: 69 additions & 0 deletions packages/vant/src/block/Block.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import {
ExtractPropTypes,
computed,
defineComponent,
nextTick,
watch,
} from 'vue';
import { createNamespace } from '../utils';
import { slugify } from 'transliteration';

const [name, bem] = createNamespace('block');

export const blockProps = {
card: {
type: Boolean,
default: false,
},
title: {
type: String,
default: '',
},
};

export type BlockProps = ExtractPropTypes<typeof blockProps>;

export default defineComponent({
name,

props: blockProps,

setup(props, { slots }) {
const slugifyTitle = computed(() => (slugify ? slugify(props.title) : ''));

watch(
() => slugifyTitle.value,
(val) => {
if (val) {
nextTick(() => {
let hash = '';
if (top) {
hash = top.location.hash.split('#').pop() as string;
} else {
hash = location.hash.split('#').pop() as string;
}
const target = document.getElementById(val);
if (target && val === hash) {
target.scrollIntoView(true);
}
});
}
},
);

return () => (
<div class={bem()}>
{props.title ? (
<h2 class={bem('title')} id={slugifyTitle.value}>
{props.title}
</h2>
) : null}
{props.card ? (
<div class={bem('card')}>{slots.default?.()}</div>
) : (
slots.default?.()
)}
</div>
);
},
});
58 changes: 58 additions & 0 deletions packages/vant/src/block/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Button

### Intro

block components provide container like functionality.

### Install

Register component globally via `app.use`, refer to [Component Registration](#/en-US/advanced-usage#zu-jian-zhu-ce) for more registration ways.

```js
import { createApp } from 'vue';
import { Block } from 'vant';

const app = createApp();
app.use(Block);
```

## Usage

### Base

use as a container, passing in the 'title' attribute as the title.

```html
<van-block title="基础用法">
<van-button type="default">{{ t('default') }}</van-button>
<van-button type="primary">{{ t('primary') }}</van-button>
<van-button type="success">{{ t('success') }}</van-button>
</van-block>
```

### Card

set the container to card mode through the 'card' attribute.

```html
<van-block title="卡片模式">
<van-button type="default">{{ t('default') }}</van-button>
<van-button type="primary">{{ t('primary') }}</van-button>
<van-button type="success">{{ t('success') }}</van-button>
</van-block>
```

## API

### Props

| Attribute | Description | Type | Default |
| --------- | ----------- | --------- | ------- |
| title | Title | _string_ | `-` |
| card | Card mode | _boolean_ | `-` |

### Slots

| Name | Description |
| ------- | ------------ |
| default | Default slot |
58 changes: 58 additions & 0 deletions packages/vant/src/block/README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Block 块级组件

### 介绍

块级组件提供类似容器的功能

### 引入

通过以下方式来全局注册组件,更多注册方式请参考[组件注册](#/zh-CN/advanced-usage#zu-jian-zhu-ce)。

```js
import { createApp } from 'vue';
import { Block } from 'vant';

const app = createApp();
app.use(Block);
```

## 代码演示

### 基础用法

当作一个容器来使用,传入 `title` 属性作为标题。

```html
<van-block title="基础用法">
<van-button type="default">{{ t('default') }}</van-button>
<van-button type="primary">{{ t('primary') }}</van-button>
<van-button type="success">{{ t('success') }}</van-button>
</van-block>
```

### 卡片模式

通过 `card` 属性将容器设置为卡片模式。

```html
<van-block title="卡片模式">
<van-button type="default">{{ t('default') }}</van-button>
<van-button type="primary">{{ t('primary') }}</van-button>
<van-button type="success">{{ t('success') }}</van-button>
</van-block>
```

## API

### Props

| 参数 | 说明 | 类型 | 默认值 |
| ----- | -------- | --------- | ------ |
| title | 标题 | _string_ | `-` |
| card | 卡片模式 | _boolean_ | `-` |

### Slots

| 名称 | 说明 |
| ------- | -------- |
| default | 默认插槽 |
46 changes: 46 additions & 0 deletions packages/vant/src/block/demo/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<script setup lang="ts">
import VanBlock from '..';
import VanButton from '../../button';
import { useTranslate } from '../../../docs/site';

const t = useTranslate({
'zh-CN': {
base: '基础用法',
card: '卡片模式',
default: '默认按钮',
primary: '主要按钮',
success: '成功按钮',
},
'en-US': {
base: 'base',
card: 'card',
default: 'Default',
primary: 'Primary',
success: 'Success',
},
});
</script>

<template>
<van-block :title="t('base')">
<van-button type="default">{{ t('default') }}</van-button>
<van-button type="primary">{{ t('primary') }}</van-button>
<van-button type="success">{{ t('success') }}</van-button>
</van-block>

<van-block :title="t('card')" card>
<van-button type="default">{{ t('default') }}</van-button>
<van-button type="primary">{{ t('primary') }}</van-button>
<van-button type="success">{{ t('success') }}</van-button>
</van-block>
</template>

<style lang="less">
.van-block {
.van-button {
&--normal:not(:last-child) {
margin-right: var(--van-padding-md);
}
}
}
</style>
36 changes: 36 additions & 0 deletions packages/vant/src/block/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
:root {
--van-block-title-padding: var(--van-padding-xl) var(--van-padding-md)
var(--van-padding-md);
--van-block-title-color: var(--van-doc-text-color-4);
--van-block-title-fint-size: var(--van-font-size-md);
--van-block-title-line-height: 16px;
--van-block-card-margin: var(--van-padding-md) var(--van-padding-md) 0;
--van-block-card-border-radius: var(--van-radius-lg);
}

.van-block {
&__title {
margin: 0;
padding: var(--van-block-title-padding);
color: var(--van-block-title-color);
font-weight: normal;
font-size: var(--van-block-title-fint-size);
line-height: var(--van-block-title-line-height);
}

&__card {
margin: var(--van-block-card-margin);
overflow: hidden;
border-radius: var(--van-block-card-border-radius);
}

&__title + &__card {
margin-top: 0;
}

&:first-of-type {
.van-block__title {
padding-top: 20px;
}
}
}
14 changes: 14 additions & 0 deletions packages/vant/src/block/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { withInstall } from '../utils';
import _Block from './Block';

export const Block = withInstall(_Block);
export default Block;
export { blockProps } from './Block';
export type { BlockProps } from './Block';
export type { BlockThemeVars } from './types';

declare module 'vue' {
export interface GlobalComponents {
VanBlock: typeof Block;
}
}