chore: move vant to packages folder (#9384)
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
Chrome >= 51
|
||||
iOS >= 10
|
||||
@@ -0,0 +1,4 @@
|
||||
es
|
||||
lib
|
||||
dist
|
||||
node_modules
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": ["@vant"],
|
||||
"rules": {
|
||||
"prefer-object-spread": "off"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["src/**/*"],
|
||||
"excludedFiles": ["**/test/*", "**/demo/*"],
|
||||
"rules": {
|
||||
// since we target ES2015 for baseline support, we need to forbid object
|
||||
// rest spread usage (both assign and destructure)
|
||||
"no-restricted-syntax": [
|
||||
"error",
|
||||
"ObjectExpression > SpreadElement",
|
||||
"ObjectPattern > RestElement"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
dist
|
||||
lib
|
||||
*.tsx
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": ["@vant/stylelint-config"]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@vant/cli/preset',
|
||||
{
|
||||
loose: process.env.BUILD_TARGET === 'package',
|
||||
enableObjectSlots: false,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
Executable
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,145 @@
|
||||
# Advanced Usage
|
||||
|
||||
### Intro
|
||||
|
||||
Through this chapter, you can learn about some advanced usages of Vant.
|
||||
|
||||
## Component Usage
|
||||
|
||||
### Component Registration
|
||||
|
||||
Vant supports multiple ways to register components:
|
||||
|
||||
#### Global Registration
|
||||
|
||||
```js
|
||||
import { Button } from 'vant';
|
||||
import { createApp } from 'vue';
|
||||
|
||||
const app = createApp();
|
||||
|
||||
// Method 1. via app.use
|
||||
app.use(Button);
|
||||
|
||||
// Method 2. Register via app.component
|
||||
app.component(Button.name, Button);
|
||||
```
|
||||
|
||||
#### Local Registration
|
||||
|
||||
```js
|
||||
import { Button } from 'vant';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
[Button.name]: Button,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
> For more information, please refer to [Vue.js - Component Registration](https://v3.vuejs.org/guide/component-registration.html#component-registration)。
|
||||
|
||||
#### \<script setup\>
|
||||
|
||||
Vant components can be used directly in `<script setup>` without component registration.
|
||||
|
||||
```xml
|
||||
<script setup>
|
||||
import { Button } from 'vant';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button />
|
||||
</template>
|
||||
```
|
||||
|
||||
#### JSX/TSX
|
||||
|
||||
Vant components can be used directly in JSX and TSX without component registration.
|
||||
|
||||
```jsx
|
||||
import { Button } from 'vant';
|
||||
|
||||
export default {
|
||||
render() {
|
||||
return <Button />;
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Browser adaptation
|
||||
|
||||
### Viewport Units
|
||||
|
||||
Vant uses `px` unit by default,you can use tools such as [postcss--px-to-viewport](https://github.com/evrone/postcss-px-to-viewport) to transform `px` unit to viewport units (vw, vh, vmin, vmax).
|
||||
|
||||
#### PostCSS Config
|
||||
|
||||
PostCSS config example:
|
||||
|
||||
```js
|
||||
// postcss.config.js
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'postcss-px-to-viewport': {
|
||||
viewportWidth: 375,
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Rem Unit
|
||||
|
||||
You can use tools such as `postcss-pxtorem` to transform `px` unit to `rem` unit.
|
||||
|
||||
- [postcss-pxtorem](https://github.com/cuth/postcss-pxtorem)
|
||||
- [lib-flexible](https://github.com/amfe/lib-flexible)
|
||||
|
||||
#### PostCSS Config
|
||||
|
||||
PostCSS config example:
|
||||
|
||||
```js
|
||||
// postcss.config.js
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'postcss-pxtorem': {
|
||||
rootValue: 37.5,
|
||||
propList: ['*'],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Custom rootValue
|
||||
|
||||
If the size of the design draft is 750 or other sizes, you can adjust the `rootValue` to:
|
||||
|
||||
```js
|
||||
// postcss.config.js
|
||||
module.exports = {
|
||||
plugins: {
|
||||
// postcss-pxtorem version >= 5.0.0
|
||||
'postcss-pxtorem': {
|
||||
rootValue({ file }) {
|
||||
return file.indexOf('vant') !== -1 ? 37.5 : 75;
|
||||
},
|
||||
propList: ['*'],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Adapt to PC Browsers
|
||||
|
||||
Vant is a mobile-first component library, if you want to use Vant in PC browsers, you can use the [@vant/touch-emulator](https://github.com/youzan/vant/tree/dev/packages/vant-touch-emulator) module. This module will automatically convert the mouse events of the PC browser into the touch events of the mobile browser.
|
||||
|
||||
```bash
|
||||
# Install
|
||||
npm i @vant/touch-emulator -S
|
||||
```
|
||||
|
||||
```js
|
||||
// Just import this module, then Vant works in PC browser
|
||||
import '@vant/touch-emulator';
|
||||
```
|
||||
@@ -0,0 +1,226 @@
|
||||
# 进阶用法
|
||||
|
||||
### 介绍
|
||||
|
||||
通过本章节你可以了解到 Vant 的一些进阶用法,比如组件插槽用法、多种浏览器适配方式。
|
||||
|
||||
## 组件用法
|
||||
|
||||
### 组件注册
|
||||
|
||||
Vant 支持多种组件注册方式,请根据实际业务需要进行选择。
|
||||
|
||||
#### 全局注册
|
||||
|
||||
全局注册后,你可以在 app 下的任意子组件中使用注册的 Vant 组件。
|
||||
|
||||
```js
|
||||
import { Button } from 'vant';
|
||||
import { createApp } from 'vue';
|
||||
|
||||
const app = createApp();
|
||||
|
||||
// 方式一. 通过 app.use 注册
|
||||
// 注册完成后,在模板中通过 <van-button> 或 <VanButton> 标签来使用按钮组件
|
||||
app.use(Button);
|
||||
|
||||
// 方式二. 通过 app.component 注册
|
||||
// 注册完成后,在模板中通过 <van-button> 标签来使用按钮组件
|
||||
app.component(Button.name, Button);
|
||||
```
|
||||
|
||||
#### 局部注册
|
||||
|
||||
局部注册后,你可以在当前组件中使用注册的 Vant 组件。
|
||||
|
||||
```js
|
||||
import { Button } from 'vant';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
[Button.name]: Button,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
> 对于组件注册更详细的介绍,请参考 [Vue 官方文档 - 组件注册](https://v3.cn.vuejs.org/guide/component-registration.html#%E7%BB%84%E4%BB%B6%E6%B3%A8%E5%86%8C)。
|
||||
|
||||
#### \<script setup\>
|
||||
|
||||
在 `<script setup>` 中可以直接使用 Vant 组件,不需要进行组件注册。
|
||||
|
||||
```xml
|
||||
<script setup>
|
||||
import { Button } from 'vant';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button />
|
||||
</template>
|
||||
```
|
||||
|
||||
#### JSX/TSX
|
||||
|
||||
在 JSX 和 TSX 中可以直接使用 Vant 组件,不需要进行组件注册。
|
||||
|
||||
```jsx
|
||||
import { Button } from 'vant';
|
||||
|
||||
export default {
|
||||
render() {
|
||||
return <Button />;
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 组件插槽
|
||||
|
||||
Vant 提供了丰富的组件插槽,通过插槽可以对组件的某一部分进行个性化定制。如果你对 Vue 的插槽不太熟悉,可以阅读 Vue 官方文档中的[插槽章节](https://v3.cn.vuejs.org/guide/component-slots.html)。下面是通过插槽来定制 Checkbox 图标的示例:
|
||||
|
||||
```html
|
||||
<van-checkbox v-model="checked">
|
||||
<!-- 使用组件提供的 icon 插槽 -->
|
||||
<!-- 将默认图标替换为个性化图片 -->
|
||||
<template #icon="props">
|
||||
<img :src="props.checked ? activeIcon : inactiveIcon" />
|
||||
</template>
|
||||
</van-checkbox>
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
checked: true,
|
||||
activeIcon: 'https://img.yzcdn.cn/vant/user-active.png',
|
||||
inactiveIcon: 'https://img.yzcdn.cn/vant/user-inactive.png',
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 组件实例方法
|
||||
|
||||
Vant 中的许多组件提供了实例方法,调用实例方法时,我们需要通过 [ref](https://v3.cn.vuejs.org/guide/component-template-refs.html) 来注册组件引用信息,引用信息将会注册在父组件的`$refs`对象上。注册完成后,我们可以通过`this.$refs.xxx`访问到对应的组件实例,并调用上面的实例方法。
|
||||
|
||||
```html
|
||||
<!-- 通过 ref 属性将组件绑定到 this.$refs.checkbox 上 -->
|
||||
<van-checkbox v-model="checked" ref="checkbox"> 复选框 </van-checkbox>
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
checked: false,
|
||||
};
|
||||
},
|
||||
// 注意:组件挂载后才能访问到 ref 对象
|
||||
mounted() {
|
||||
this.$refs.checkbox.toggle();
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## 浏览器适配
|
||||
|
||||
### Viewport 布局
|
||||
|
||||
Vant 默认使用 `px` 作为样式单位,如果需要使用 `viewport` 单位 (vw, vh, vmin, vmax),推荐使用 [postcss-px-to-viewport](https://github.com/evrone/postcss-px-to-viewport) 进行转换。
|
||||
|
||||
[postcss-px-to-viewport](https://github.com/evrone/postcss-px-to-viewport) 是一款 PostCSS 插件,用于将 px 单位转化为 vw/vh 单位。
|
||||
|
||||
#### PostCSS PostCSS 示例配置
|
||||
|
||||
下面提供了一份基本的 PostCSS 示例配置,可以在此配置的基础上根据项目需求进行修改。
|
||||
|
||||
```js
|
||||
// postcss.config.js
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'postcss-px-to-viewport': {
|
||||
viewportWidth: 375,
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
> Tips: 在配置 postcss-loader 时,应避免 ignore node_modules 目录,否则将导致 Vant 样式无法被编译。
|
||||
|
||||
### Rem 布局适配
|
||||
|
||||
如果需要使用 `rem` 单位进行适配,推荐使用以下两个工具:
|
||||
|
||||
- [postcss-pxtorem](https://github.com/cuth/postcss-pxtorem) 是一款 PostCSS 插件,用于将 px 单位转化为 rem 单位
|
||||
- [lib-flexible](https://github.com/amfe/lib-flexible) 用于设置 rem 基准值
|
||||
|
||||
#### PostCSS 示例配置
|
||||
|
||||
下面提供了一份基本的 PostCSS 示例配置,可以在此配置的基础上根据项目需求进行修改。
|
||||
|
||||
```js
|
||||
// postcss.config.js
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'postcss-pxtorem': {
|
||||
rootValue: 37.5,
|
||||
propList: ['*'],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
#### 其他设计稿尺寸
|
||||
|
||||
如果设计稿的尺寸不是 375,而是 750 或其他大小,可以将 `rootValue` 配置调整为:
|
||||
|
||||
```js
|
||||
// postcss.config.js
|
||||
module.exports = {
|
||||
plugins: {
|
||||
// postcss-pxtorem 插件的版本需要 >= 5.0.0
|
||||
'postcss-pxtorem': {
|
||||
rootValue({ file }) {
|
||||
return file.indexOf('vant') !== -1 ? 37.5 : 75;
|
||||
},
|
||||
propList: ['*'],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 桌面端适配
|
||||
|
||||
Vant 是一个面向移动端的组件库,因此默认只适配了移动端设备,这意味着组件只监听了移动端的 `touch` 事件,没有监听桌面端的 `mouse` 事件。
|
||||
|
||||
如果你需要在桌面端使用 Vant,可以引入我们提供的 [@vant/touch-emulator](https://github.com/youzan/vant/tree/dev/packages/vant-touch-emulator),这个库会在桌面端自动将 `mouse` 事件转换成对应的 `touch` 事件,使得组件能够在桌面端使用。
|
||||
|
||||
```bash
|
||||
# 安装模块
|
||||
npm i @vant/touch-emulator -S
|
||||
```
|
||||
|
||||
```js
|
||||
// 引入模块后自动生效
|
||||
import '@vant/touch-emulator';
|
||||
```
|
||||
|
||||
### 底部安全区适配
|
||||
|
||||
iPhone X 等机型底部存在底部指示条,指示条的操作区域与页面底部存在重合,容易导致用户误操作,因此我们需要针对这些机型进行安全区适配。Vant 中部分组件提供了 `safe-area-inset-top` 或 `safe-area-inset-bottom` 属性,设置该属性后,即可在对应的机型上开启适配,如下示例:
|
||||
|
||||
```html
|
||||
<!-- 在 head 标签中添加 meta 标签,并设置 viewport-fit=cover 值 -->
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
|
||||
/>
|
||||
|
||||
<!-- 开启顶部安全区适配 -->
|
||||
<van-nav-bar safe-area-inset-top />
|
||||
|
||||
<!-- 开启底部安全区适配 -->
|
||||
<van-number-keyboard safe-area-inset-bottom />
|
||||
```
|
||||
|
||||
<img src="https://img.yzcdn.cn/vant/safearea.png">
|
||||
@@ -0,0 +1,732 @@
|
||||
# Changelog
|
||||
|
||||
### Tips
|
||||
|
||||
The current document is the changelog of Vant 3. If you want to view the changelog of Vant 2, please visit [Vant 2 Changelog](https://youzan.github.io/vant/#/en-US/changelog).
|
||||
|
||||
### Intro
|
||||
|
||||
Vant follows [Semantic Versioning 2.0.0](https://semver.org/lang/zh-CN/).
|
||||
|
||||
**Release Schedule**
|
||||
|
||||
- Patch version:released weekly, including features and bug fixes.
|
||||
- Minor version:released every one to two months, including backwards compatible features.
|
||||
- Major version:including breaking changes and new features.
|
||||
|
||||
## Details
|
||||
|
||||
### [v3.2.2](https://github.com/youzan/vant/compare/v3.2.1...v3.2.2)
|
||||
|
||||
`2021-09-02`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Field: add id prop [#9347](https://github.com/youzan/vant/issues/9347)
|
||||
- Field: add `van-field__error` class when error [#9327](https://github.com/youzan/vant/issues/9327)
|
||||
- Field: using `label` tag for label [#9346](https://github.com/youzan/vant/issues/9346)
|
||||
- Popover: add show-arrow prop [#9372](https://github.com/youzan/vant/issues/9372)
|
||||
- Progress: add transition effect [ba4ff5](https://github.com/youzan/vant/commit/ba4ff58af6ccf67e255bf43ef905677dc64596a3)
|
||||
- Search: add id prop [#9349](https://github.com/youzan/vant/issues/9349)
|
||||
- Tab: add show-zero-badge prop [#9343](https://github.com/youzan/vant/issues/9343)
|
||||
- Locale: simplify locale configs [#9329](https://github.com/youzan/vant/issues/9329)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- AddressEdit: remove unused finish button [#9364](https://github.com/youzan/vant/issues/9364)
|
||||
- Progress: fix render error when use v-show and improve performance [841e09](https://github.com/youzan/vant/commit/841e09d0529961058ecb63ed26f018cf3a66a3bf)
|
||||
- Progress: percentage missing default value [8ac597](https://github.com/youzan/vant/commit/8ac597dc3d2316d34f866dcfd7e1646c695da180)
|
||||
- fix animation css vars not work [#9337](https://github.com/youzan/vant/issues/9337)
|
||||
|
||||
### [v3.2.1](https://github.com/youzan/vant/compare/v3.2.0...v3.2.1)
|
||||
|
||||
`2021-08-22`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Circle: add start-position prop [#9305](https://github.com/youzan/vant/issues/9305)
|
||||
- Slider: add reverse prop [#9308](https://github.com/youzan/vant/issues/9308)
|
||||
- NumberKeyboard: add van-number-keyboard-key-background-color css var [#9303](https://github.com/youzan/vant/issues/9303)
|
||||
- PasswordInput: add password-input-text-color css var [#9304](https://github.com/youzan/vant/issues/9304)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Calendar: title is undefined in month-show event [#9275](https://github.com/youzan/vant/issues/9275)
|
||||
- Dialog: fix beforeClose repeat trigger [#9283](https://github.com/youzan/vant/issues/9283) [#9291](https://github.com/youzan/vant/issues/9291)
|
||||
- Field: should export FieldInstance type [#9254](https://github.com/youzan/vant/issues/9254)
|
||||
- Rate: convert count type [#9307](https://github.com/youzan/vant/issues/9307)
|
||||
- TreeSelect: fix negative css vars [#9306](https://github.com/youzan/vant/issues/9306)
|
||||
|
||||
### [v3.2.0](https://github.com/youzan/vant/compare/v3.1.5...v3.2.0)
|
||||
|
||||
`2021-08-12`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Form: add useCustomFieldValue api [#9200](https://github.com/youzan/vant/issues/9200)
|
||||
- Button: loading-size prop support number type [#9177](https://github.com/youzan/vant/issues/9177)
|
||||
- Style: add van-safe-area-bottom util class [#9205](https://github.com/youzan/vant/issues/9205)
|
||||
|
||||
**Types**
|
||||
|
||||
- AddressEdit: add AddressEditInstance type [#9197](https://github.com/youzan/vant/issues/9197)
|
||||
- Area: add AreaInstance type [#9195](https://github.com/youzan/vant/issues/9195)
|
||||
- Calendar: add CalendarInstance type [#9165](https://github.com/youzan/vant/issues/9165)
|
||||
- Checkbox: add CheckboxInstance type [#9140](https://github.com/youzan/vant/issues/9140)
|
||||
- CheckboxGroup: add CheckboxGroupInstance type [#9142](https://github.com/youzan/vant/issues/9142)
|
||||
- CollapseItem: add CollapseItemInstance type [#9194](https://github.com/youzan/vant/issues/9194)
|
||||
- CountDown: add CountDownInstance type [#9153](https://github.com/youzan/vant/issues/9153)
|
||||
- DatetimePicker: add DatetimePickerInstance type [#9208](https://github.com/youzan/vant/issues/9208)
|
||||
- DropdownItem: add DropdownItemInstance type [#9214](https://github.com/youzan/vant/issues/9214)
|
||||
- Field: add FieldInstance type [#9166](https://github.com/youzan/vant/issues/9166)
|
||||
- Form: add FormInstance type [#9139](https://github.com/youzan/vant/issues/9139)
|
||||
- ImagePreview: add ImagePreviewInstance type [#9216](https://github.com/youzan/vant/issues/9216)
|
||||
- IndexBar: add IndexBarInstance type [#9246](https://github.com/youzan/vant/issues/9246)
|
||||
- List: add ListInstance type [#9159](https://github.com/youzan/vant/issues/9159)
|
||||
- NoticeBar: add NoticeBarInstance type [#9245](https://github.com/youzan/vant/issues/9245)
|
||||
- Picker: add PickerInstance type [#9183](https://github.com/youzan/vant/issues/9183)
|
||||
- Progress: add ProgressInstance type [#9247](https://github.com/youzan/vant/issues/9247)
|
||||
- Search: add SearchInstance type [#9181](https://github.com/youzan/vant/issues/9181)
|
||||
- Swipe: add SwipeInstance type [#9158](https://github.com/youzan/vant/issues/9158)
|
||||
- SwipeCell: add SwipeCellInstance type [#9179](https://github.com/youzan/vant/issues/9179)
|
||||
- Tabs: add TabsInstance type [#9174](https://github.com/youzan/vant/issues/9174)
|
||||
- Uploader: add UploaderInstance type [#9164](https://github.com/youzan/vant/issues/9164)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Badge: minus x offset not work [#9199](https://github.com/youzan/vant/issues/9199)
|
||||
- Image: fix border radius value [#9163](https://github.com/youzan/vant/issues/9163)
|
||||
- Field: textarea scroll to top after resizing [#9206](https://github.com/youzan/vant/issues/9206)
|
||||
- Notify: default option is overridden [#9138](https://github.com/youzan/vant/issues/9138)
|
||||
- Rate: should enable flex wrap [#9192](https://github.com/youzan/vant/issues/9192)
|
||||
- Tabs: remove invalid head padding for card type [#9168](https://github.com/youzan/vant/issues/9168)
|
||||
- Toast: failed to update message [#9196](https://github.com/youzan/vant/issues/9196)
|
||||
|
||||
### [v3.1.5](https://github.com/youzan/vant/compare/v3.1.4...v3.1.5)
|
||||
|
||||
`2021-07-26`
|
||||
|
||||
**Feature**
|
||||
|
||||
- AddressEdit: add address-edit-button-font-size var [#9113](https://github.com/youzan/vant/issues/9113)
|
||||
- Icon: add shield-o icon [#9082](https://github.com/youzan/vant/issues/9082)
|
||||
- Locale: add Russian language [#9088](https://github.com/youzan/vant/issues/9088)
|
||||
- Toast: improve unclickable cursor [#9116](https://github.com/youzan/vant/issues/9116)
|
||||
- Uploader: add click-upload event [#9119](https://github.com/youzan/vant/issues/9119)
|
||||
- Uploader: add readonly prop [#9118](https://github.com/youzan/vant/issues/9118)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Icon: fix invitation typo [#9096](https://github.com/youzan/vant/issues/9096)
|
||||
- NumberKeyboard: should not emit close event when click away [#9108](https://github.com/youzan/vant/issues/9108)
|
||||
- Search: fix incorrect left icon color [#9100](https://github.com/youzan/vant/issues/9100)
|
||||
- Tabbar: fix tabbar-item-icon-margin-bottom var name [#9101](https://github.com/youzan/vant/issues/9101)
|
||||
|
||||
### [v3.1.4](https://github.com/youzan/vant/compare/v3.1.3...v3.1.4)
|
||||
|
||||
`2021-07-19`
|
||||
|
||||
**Feature**
|
||||
|
||||
- ActionSheet: add before-close prop [#9068](https://github.com/youzan/vant/issues/9068)
|
||||
- Cascader: add option slot [#9036](https://github.com/youzan/vant/issues/9036)
|
||||
- Cascader: improve option cursor [#9032](https://github.com/youzan/vant/issues/9032)
|
||||
- Popup: add before-close prop [#9067](https://github.com/youzan/vant/issues/9067)
|
||||
- ShareSheet: add before-close prop [#9068](https://github.com/youzan/vant/issues/9068)
|
||||
- Tabs: add click-tab event [#9037](https://github.com/youzan/vant/issues/9037)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Field: required mark position [#9035](https://github.com/youzan/vant/issues/9035)
|
||||
- List: should emit load event when parent tab is activated [#9022](https://github.com/youzan/vant/issues/9022)
|
||||
- Popup: missing open、close event in some cases [#9065](https://github.com/youzan/vant/issues/9065)
|
||||
|
||||
### [v3.1.3](https://github.com/youzan/vant/compare/v3.1.2...v3.1.3)
|
||||
|
||||
`2021-07-11`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Calendar: add click-subtitle event [#8981](https://github.com/youzan/vant/issues/8981)
|
||||
- Calendar: add subtitle slot [#8980](https://github.com/youzan/vant/issues/8980)
|
||||
- ConfigProvider: add icon-prefix prop [#8986](https://github.com/youzan/vant/issues/8986)
|
||||
- Slider: add drag event param [#8990](https://github.com/youzan/vant/issues/8990)
|
||||
- Slider: add left-button、right-button slot [#8989](https://github.com/youzan/vant/issues/8989)
|
||||
- touch-emulator: support data-no-touch-simulate [#8984](https://github.com/youzan/vant/issues/8984)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Step: fix z-index issue [#9003](https://github.com/youzan/vant/issues/9003)
|
||||
|
||||
### [v3.1.2](https://github.com/youzan/vant/compare/v3.1.1...v3.1.2)
|
||||
|
||||
`2021-07-03`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Area: add toolbar、confirm、cancel slots [#8969](https://github.com/youzan/vant/issues/8969)
|
||||
- Calendar: simplify placeholder dom [#8955](https://github.com/youzan/vant/issues/8955)
|
||||
- Cascader: add disabled option [#8952](https://github.com/youzan/vant/issues/8952)
|
||||
- ConfigProvider: add tag prop [#8967](https://github.com/youzan/vant/issues/8967)
|
||||
- Picker: add toolbar slot [#8968](https://github.com/youzan/vant/issues/8968)
|
||||
- Picker: allow option text to be number type [#8951](https://github.com/youzan/vant/issues/8951)
|
||||
- Picker: add picker-option-padding CSS var [#8947](https://github.com/youzan/vant/issues/8947)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Toast: fix word break [#8965](https://github.com/youzan/vant/issues/8965)
|
||||
|
||||
### [v3.1.1](https://github.com/youzan/vant/compare/v3.1.0...v3.1.1)
|
||||
|
||||
`2021-06-27`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Cell: add value slot [#8933](https://github.com/youzan/vant/issues/8933)
|
||||
- CollapseItem: add label slot [#8934](https://github.com/youzan/vant/issues/8934)
|
||||
- NoticeBar: add reset method [#8917](https://github.com/youzan/vant/issues/8917)
|
||||
- Tabs: add nav-bottom slot [#8915](https://github.com/youzan/vant/issues/8915)
|
||||
|
||||
### [v3.1.0](https://github.com/youzan/vant/compare/v3.1.0-beta.0...v3.1.0)
|
||||
|
||||
`2021-06-22`
|
||||
|
||||
**New Component**
|
||||
|
||||
- add [ConfigProvider](#/en-US/config-provider) Component [#8854](https://github.com/youzan/vant/issues/8854)
|
||||
|
||||
**Feature**
|
||||
|
||||
- all components support CSS Variables [aef257](https://github.com/youzan/vant/commit/aef2579a95da7c8b528ba7062b227fea698a0487) [fe1cba](https://github.com/youzan/vant/commit/fe1cba97b796eba7e9b5dca0ce4ab0d1de95715c)
|
||||
- add more CSS Variables [#8861](https://github.com/youzan/vant/issues/8861)
|
||||
- Checkbox: icon slot add disabled param [#8839](https://github.com/youzan/vant/issues/8839)
|
||||
- Cascader: add className option [#8882](https://github.com/youzan/vant/issues/8882)
|
||||
- Cascader: add color option [#8883](https://github.com/youzan/vant/issues/8883)
|
||||
- CellGroup: add inset prop [#8885](https://github.com/youzan/vant/issues/8885)
|
||||
- GridItem: add reverse prop [#8878](https://github.com/youzan/vant/issues/8878)
|
||||
- IndexBar: add teleport prop [#8820](https://github.com/youzan/vant/issues/8820)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Dialog: allow message function to return html [#8872](https://github.com/youzan/vant/issues/8872)
|
||||
- Slider: format v-model with step correctly [#8893](https://github.com/youzan/vant/issues/8893)
|
||||
|
||||
### [v3.0.18](https://github.com/youzan/vant/compare/v3.0.17...v3.0.18)
|
||||
|
||||
`2021-06-03`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Button: add icon slot [#8783](https://github.com/youzan/vant/issues/8783)
|
||||
- CouponList: add list-footer、disabled-list-footer slot [#8801](https://github.com/youzan/vant/issues/8801)
|
||||
- List: remove unused Less var @list-icon-margin-right [#8759](https://github.com/youzan/vant/issues/8759)
|
||||
- Locale: add French translations [#8795](https://github.com/youzan/vant/issues/8795)
|
||||
- Popup: add icon-prefix prop [#8793](https://github.com/youzan/vant/issues/8793)
|
||||
- Popup: add overlay-content slot [#8794](https://github.com/youzan/vant/issues/8794)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Collapse: fix safari rendering issues [#8788](https://github.com/youzan/vant/issues/8788)
|
||||
- NoticeBar: failed to play when inside a re-opened popup [#8789](https://github.com/youzan/vant/issues/8789)
|
||||
- @vant/touch-emulator: add SSR support [#8767](https://github.com/youzan/vant/issues/8767)
|
||||
|
||||
### [v3.0.17](https://github.com/youzan/vant/compare/v3.0.16...v3.0.17)
|
||||
|
||||
`2021-05-23`
|
||||
|
||||
**Feature**
|
||||
|
||||
- ActionBarIcon: add icon-prefix prop [#8748](https://github.com/youzan/vant/issues/8748)
|
||||
- Calendar: add show-range-prompt prop [#8739](https://github.com/youzan/vant/issues/8739)
|
||||
- Calendar: add top-info、bottom-info slot [#8716](https://github.com/youzan/vant/issues/8716)
|
||||
- GridItem: add icon-color prop [#8753](https://github.com/youzan/vant/issues/8753)
|
||||
- NoticeBar: increase default speed to 60 [#8694](https://github.com/youzan/vant/issues/8694)
|
||||
- Popover: add icon-prefix prop [#8703](https://github.com/youzan/vant/issues/8703)
|
||||
- Toast: add transition [#8743](https://github.com/youzan/vant/issues/8743)
|
||||
- Uploader: max-size prop can be a function [#8744](https://github.com/youzan/vant/issues/8744)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Button: add onClick event shim for tsx [#8665](https://github.com/youzan/vant/issues/8665)
|
||||
- Calendar: initial date incorrect [#8696](https://github.com/youzan/vant/issues/8696)
|
||||
- DatetimePicker: vant3 fixed incorrect value when dynamic set min/max [#8658](https://github.com/youzan/vant/issues/8658)
|
||||
- List: skip check when inside an inactive tab [#8741](https://github.com/youzan/vant/issues/8741)
|
||||
- Tabs: fix add scroll event target [#8734](https://github.com/youzan/vant/issues/8734)
|
||||
- Toast: should reset duration when type or message changed [#8742](https://github.com/youzan/vant/issues/8742)
|
||||
|
||||
### [v3.0.16](https://github.com/youzan/vant/compare/v3.0.15...v3.0.16)
|
||||
|
||||
`2021-05-03`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Swipe: indicator slot add active param [#8645](https://github.com/youzan/vant/issues/8645)
|
||||
- Cascader: add @cascader-header-padding less var [#8626](https://github.com/youzan/vant/issues/8626)
|
||||
- Steps: add icon-prefix prop [#8631](https://github.com/youzan/vant/issues/8631)
|
||||
- export more types [#8652](https://github.com/youzan/vant/issues/8652)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Stepper: fix blur event trigger timing [#8620](https://github.com/youzan/vant/issues/8620)
|
||||
- SubmitBar: @submit-bar-price-font-size not work [#8639](https://github.com/youzan/vant/issues/8639)
|
||||
- Swipe: re-initialize when popup reopened [#8643](https://github.com/youzan/vant/issues/8643)
|
||||
- Tabs: setLine when popup reopened [#8642](https://github.com/youzan/vant/issues/8642)
|
||||
|
||||
### [v3.0.15](https://github.com/youzan/vant/compare/v2.12.14-test...v3.0.15)
|
||||
|
||||
`2021-04-25`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Cascader: add click-tab event [#8606](https://github.com/youzan/vant/issues/8606)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Tab: failed to render during SSR [#8603](https://github.com/youzan/vant/issues/8603)
|
||||
- Rate: select half star correctly when clicked [#8580](https://github.com/youzan/vant/issues/8580)
|
||||
- Tag: incorrect border color when using plain [#8601](https://github.com/youzan/vant/issues/8601)
|
||||
|
||||
### [v3.0.14](https://github.com/youzan/vant/compare/v3.0.13...v3.0.14)
|
||||
|
||||
`2021-04-18`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Badge: offset prop support custom unit [35edb7](https://github.com/youzan/vant/commit/35edb72b5cd519d4e75443acaa0a63db16695d2d)
|
||||
- Rate: support decimal modelValue when readonly [#8528](https://github.com/youzan/vant/issues/8528)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- ContactList: fix nodes type [0b764b](https://github.com/youzan/vant/commit/0b764b63470b09f5654d267c8d07a20bc2d31536)
|
||||
|
||||
### [v3.0.13](https://github.com/youzan/vant/compare/v3.0.12...v3.0.13)
|
||||
|
||||
`2021-04-11`
|
||||
|
||||
**Feature**
|
||||
|
||||
- ActionBar: add @action-bar-icon-background-color less var [#8474](https://github.com/youzan/vant/issues/8474)
|
||||
- Popover: bump @popperjs/core@2.9.2 [0d1323](https://github.com/youzan/vant/commit/0d132337d5d263957a7993d60e47a18efec7313e)
|
||||
- perf: reduce bundle size [ba3e6d](https://github.com/youzan/vant/commit/ba3e6d56a0bc7ae3acc25b1380f054da3b9b020f)
|
||||
|
||||
**Types**
|
||||
|
||||
- Popup: fix PopupCloseIconPosition type [15d901](https://github.com/youzan/vant/commit/15d901ad6aace3826881cb3c6e0499f75b71df80)
|
||||
- Search: missing some props in jsx [#8485](https://github.com/youzan/vant/issues/8485)
|
||||
- Stepper: improve theme prop typing [#8489](https://github.com/youzan/vant/issues/8489)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Field: autofocus prop not work [#8488](https://github.com/youzan/vant/issues/8488)
|
||||
|
||||
### [v3.0.12](https://github.com/youzan/vant/compare/v3.0.11...v3.0.12)
|
||||
|
||||
`2021-04-05`
|
||||
|
||||
**Feature**
|
||||
|
||||
- CollapseItem: add readonly prop [#8445](https://github.com/youzan/vant/issues/8445)
|
||||
- Field: add clear-icon prop [#8438](https://github.com/youzan/vant/issues/8438)
|
||||
- Search: add clear-icon prop [#8439](https://github.com/youzan/vant/issues/8439)
|
||||
- Search: add error-message prop [#8442](https://github.com/youzan/vant/issues/8442)
|
||||
- Search: add formatter、format-trigger prop [#8441](https://github.com/youzan/vant/issues/8441)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- fix incorrect tag prompts under Webstorm [#8450](https://github.com/youzan/vant/issues/8450)
|
||||
|
||||
### [v3.0.11](https://github.com/youzan/vant/compare/v3.0.10...v3.0.11)
|
||||
|
||||
`2021-03-30`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Cascader: add swipeable prop [#8383](https://github.com/youzan/vant/issues/8383)
|
||||
- Dialog: add footer slot [#8382](https://github.com/youzan/vant/issues/8382)
|
||||
- Dialog: allow to render JSX message [#8420](https://github.com/youzan/vant/issues/8420)
|
||||
- Image: add icon-size prop [#8395](https://github.com/youzan/vant/issues/8395)
|
||||
- Row: add wrap prop [#8393](https://github.com/youzan/vant/issues/8393)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Field: should not reset validation after blurred [#8409](https://github.com/youzan/vant/issues/8409)
|
||||
- Sticky: Element not exist during SSR [#8407](https://github.com/youzan/vant/issues/8407)
|
||||
- Tabs: incorrect horizontal slip judgment [#8388](https://github.com/youzan/vant/issues/8388)
|
||||
|
||||
### [v3.0.10](https://github.com/youzan/vant/compare/v3.0.9...v3.0.10)
|
||||
|
||||
`2021-03-19`
|
||||
|
||||
**Feature**
|
||||
|
||||
- ActionSheet: add cancel slot [#8333](https://github.com/youzan/vant/issues/8333)
|
||||
- Badge: add show-zero prop [#8381](https://github.com/youzan/vant/issues/8381)
|
||||
- Cascader: add close-icon prop [#8334](https://github.com/youzan/vant/issues/8334)
|
||||
- Popover: add close-on-click-overlay prop [#8351](https://github.com/youzan/vant/issues/8351)
|
||||
- Popover: add duration prop [#8355](https://github.com/youzan/vant/issues/8355)
|
||||
- Popover: add overlay-class prop [#8353](https://github.com/youzan/vant/issues/8353)
|
||||
- Popover: add overlay-style prop [#8354](https://github.com/youzan/vant/issues/8354)
|
||||
- ShareSheet: add cancel slot [#8335](https://github.com/youzan/vant/issues/8335)
|
||||
- Sticky: add change event [#8374](https://github.com/youzan/vant/issues/8374)
|
||||
- Tag: close event param [#8337](https://github.com/youzan/vant/issues/8337)
|
||||
- Toast: add iconSize option [#8338](https://github.com/youzan/vant/issues/8338)
|
||||
|
||||
**Feature**
|
||||
|
||||
- ContactList: add @contact-list-item-radio-icon-color var [#8322](https://github.com/youzan/vant/issues/8322)
|
||||
- Coupon: add @coupon-corner-checkbox-icon-color var [#8323](https://github.com/youzan/vant/issues/8323)
|
||||
- List: add @list-loading-icon-size less var [#8365](https://github.com/youzan/vant/issues/8365)
|
||||
- Loading: add @button-loading-icon-size less var [465bf0](https://github.com/youzan/vant/commit/465bf07095c58e8292b23ef0c64be1550aa9d430)
|
||||
- PullRefresh: add @pull-refresh-loading-icon-size less var [#8366](https://github.com/youzan/vant/issues/8366)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Popover: close-on-click-outside not work [#8352](https://github.com/youzan/vant/issues/8352)
|
||||
- Swipe: incorrect item width after scaled [#8330](https://github.com/youzan/vant/issues/8330)
|
||||
|
||||
### [v3.0.9](https://github.com/youzan/vant/compare/v3.0.8...v3.0.9)
|
||||
|
||||
`2021-03-08`
|
||||
|
||||
**Feature**
|
||||
|
||||
- AddressList: add tag slots [#8292](https://github.com/youzan/vant/issues/8292)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- fix custom theme not work [#8301](https://github.com/youzan/vant/issues/8301)
|
||||
- fix failed to install component in TypeScript [#8308](https://github.com/youzan/vant/issues/8308)
|
||||
|
||||
### [v3.0.8](https://github.com/youzan/vant/compare/v3.0.7...v3.0.8)
|
||||
|
||||
`2021-03-07`
|
||||
|
||||
**Types**
|
||||
|
||||
- Build types from source code [#8264](https://github.com/youzan/vant/issues/8264)
|
||||
|
||||
**Feature**
|
||||
|
||||
- ImagePreview: add overlay-style prop [#8276](https://github.com/youzan/vant/issues/8276)
|
||||
- ImagePreview: add transition prop [#8275](https://github.com/youzan/vant/issues/8275)
|
||||
- Locale: add th-TH lang [#8297](https://github.com/youzan/vant/issues/8297)
|
||||
- PullRefresh: add pull-distance prop [#8280](https://github.com/youzan/vant/issues/8280)
|
||||
- Button: add some less vars [#8281](https://github.com/youzan/vant/issues/8281)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- ImagePreview: add test cases [#8282](https://github.com/youzan/vant/issues/8282)
|
||||
- ActionSheet: should not reopen when closed [#8272](https://github.com/youzan/vant/issues/8272)
|
||||
- Stepper: incorrect text color in iOS14 when disabled [#8277](https://github.com/youzan/vant/issues/8277)
|
||||
- Swipe: should render dynamic swipe item correctly [#8288](https://github.com/youzan/vant/issues/8288)
|
||||
|
||||
### [v3.0.7](https://github.com/youzan/vant/compare/v3.0.6...v3.0.7)
|
||||
|
||||
`2021-02-28`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Notify: add lockScroll option [#8168](https://github.com/youzan/vant/issues/8168)
|
||||
- Popup: click-overlay event add `Event` param [#8107](https://github.com/youzan/vant/issues/8107)
|
||||
- ShareSheet: add overlay-style prop [#8225](https://github.com/youzan/vant/issues/8225)
|
||||
- ShareSheet: add overlay-class prop [#8225](https://github.com/youzan/vant/issues/8225)
|
||||
- Step: add finish-icon slot [#8241](https://github.com/youzan/vant/issues/8241)
|
||||
- Steps: add finish-icon prop [#8103](https://github.com/youzan/vant/issues/8103)
|
||||
- Uploader: add @uploader-mask-text-color var [#8064](https://github.com/youzan/vant/issues/8064)
|
||||
|
||||
**perf**
|
||||
|
||||
- adjust browserslist to fit Vue 3 [#8227](https://github.com/youzan/vant/issues/8227)
|
||||
- disable enableObjectSlots to reduce bundle size [#8226](https://github.com/youzan/vant/issues/8226)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- ActionSheet: fix safe-area-inset-bottom prop not work [#8085](https://github.com/youzan/vant/issues/8085)
|
||||
- DateTimePicker: fix incorrect initial value [#8193](https://github.com/youzan/vant/issues/8193)
|
||||
- Form: may scroll to incorrect field after submitted [#8159](https://github.com/youzan/vant/issues/8159)
|
||||
- ImagePreview: fix incorrect image display during the second call [#8060](https://github.com/youzan/vant/issues/8060)
|
||||
- IndexBar: failed to render active anchor when inited [#8164](https://github.com/youzan/vant/issues/8164)
|
||||
- Popup: should watch lockScroll [#8169](https://github.com/youzan/vant/issues/8169)
|
||||
- Swipe: active may outrange when initialize [#8061](https://github.com/youzan/vant/issues/8061)
|
||||
- SwipeCell: incorrect position param when clicking outside [#8108](https://github.com/youzan/vant/issues/8108)
|
||||
- Tabbar: incorrect active tab when name is zero [#8125](https://github.com/youzan/vant/issues/8125)
|
||||
- Tabs: incorrect active tab when active prop is zero [#8074](https://github.com/youzan/vant/issues/8074)
|
||||
- Toast: ssr error [#8214](https://github.com/youzan/vant/issues/8214)
|
||||
|
||||
### [v3.0.6](https://github.com/youzan/vant/compare/v3.0.5...v3.0.6)
|
||||
|
||||
`2021-01-31`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Area: support more than 6-digit area code [#8001](https://github.com/youzan/vant/issues/8001)
|
||||
- Form: adjust show-error default value to false [#8016](https://github.com/youzan/vant/issues/8016)
|
||||
- Form: allow validator to return message [#8052](https://github.com/youzan/vant/issues/8052)
|
||||
- NumberKeyboard: add blur-on-close prop [#8033](https://github.com/youzan/vant/issues/8033)
|
||||
- Popover: add click-overlay event [#8050](https://github.com/youzan/vant/issues/8050)
|
||||
- Popover: support config action color [#8049](https://github.com/youzan/vant/issues/8049)
|
||||
- Sticky: add position、offset-bottom prop [#7979](https://github.com/youzan/vant/issues/7979)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Button: should not submit form when loading [#8018](https://github.com/youzan/vant/issues/8018)
|
||||
- Calendar: should expose scrollToDate method [#7983](https://github.com/youzan/vant/issues/7983)
|
||||
- Empty: linearGradient id conflict [#8013](https://github.com/youzan/vant/issues/8013)
|
||||
- Toast: closeOnClickOverlay not work [#8044](https://github.com/youzan/vant/issues/8044)
|
||||
|
||||
### [v3.0.5](https://github.com/youzan/vant/compare/v3.0.4...v3.0.5)
|
||||
|
||||
`2021-01-24`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Badge: add offset prop [e0b463](https://github.com/youzan/vant/commit/e0b463630108b5031a02a8afcd0c141a7fdbac9e)
|
||||
- Calendar: reset method support specified date [#7966](https://github.com/youzan/vant/issues/7966)
|
||||
- Icons: add wechat icon, rename wechat-pay icon [b3cd8c](https://github.com/youzan/vant/commit/b3cd8c14aea9e542a9de4ba9999e50c3ecbf3b3c)
|
||||
- ImagePreview: reset scale after swiping [#7972](https://github.com/youzan/vant/issues/7972)
|
||||
- ImagePreview: adjust default swipeDuration to 300ms [#7970](https://github.com/youzan/vant/issues/7970)
|
||||
- ShareSheet: add wechat-moments icon [ca66fb](https://github.com/youzan/vant/commit/ca66fbca36c5c839e3a294d465b0fc2bd7bf5039)
|
||||
- Slider: add readonly prop [4cd991](https://github.com/youzan/vant/commit/4cd991dfec01bd5342cb59b750d0dfa5901b8dc8)
|
||||
|
||||
**style**
|
||||
|
||||
- ShareSheet: update qrcode icon [32a08b](https://github.com/youzan/vant/commit/32a08bb6807d9d38027e03eef376d82b6eab282e)
|
||||
- TreeSelect: add active feedback [bada31](https://github.com/youzan/vant/commit/bada315fb3b0fbdf30c663170c867bbbc274687c)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Calendar: should reset to default date when calling reset method [#7967](https://github.com/youzan/vant/issues/7967)
|
||||
- Dialog: failed to render when toggling allowHtml [#7968](https://github.com/youzan/vant/issues/7968)
|
||||
- ImagePreview: scale event index is undefined [#7971](https://github.com/youzan/vant/issues/7971)
|
||||
|
||||
### [v3.0.4](https://github.com/youzan/vant/compare/v3.0.3...v3.0.4)
|
||||
|
||||
`2021-01-17`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Cascader: add field-names prop [#7933](https://github.com/youzan/vant/issues/7933)
|
||||
- Cell: allow to disable clickable when using is-link [#7923](https://github.com/youzan/vant/issues/7923)
|
||||
- DropdownItem: title-class can be array or object type [#7926](https://github.com/youzan/vant/issues/7926)
|
||||
- Popup: overlay-class can be array or object [#7924](https://github.com/youzan/vant/issues/7924)
|
||||
- Toast: add overlayClass option [#7925](https://github.com/youzan/vant/issues/7925)
|
||||
- Toast: add overlayStyle option [#7898](https://github.com/youzan/vant/issues/7898)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- AddressEdit: should expose setAreaCode method [6a184f](https://github.com/youzan/vant/commit/6a184f8e930fea31035680dd44f40bc007aba4cd)
|
||||
- Circle: the gradient color is incorrect [#7909](https://github.com/youzan/vant/issues/7909)
|
||||
- NumberKeyboard: fix delete、extra-key slot not work [52a0e5](https://github.com/youzan/vant/commit/52a0e5a8c70dcc07b87140e33318acefcbdd3ef9)
|
||||
- Search: fix update:modelValue emits warning [#7872](https://github.com/youzan/vant/issues/7872)
|
||||
- Swipe: should stop autoplay when page is hidden [1c428f](https://github.com/youzan/vant/commit/1c428f240cd44d3389510263dd7f03973cfbfa2b)
|
||||
|
||||
### [v3.0.3](https://github.com/youzan/vant/compare/v3.0.2...v3.0.3)
|
||||
|
||||
`2021-01-10`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Field: add autocomplate prop [#7877](https://github.com/youzan/vant/issues/7877)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Area: should expose getValues method [03c7b4](https://github.com/youzan/vant/commit/03c7b46b04d8c543f952cbf8399ec21ca39f979f)
|
||||
- ImagePreview: close-on-popstate not work [#7880](https://github.com/youzan/vant/issues/7880)
|
||||
- List: should watch error prop and check position [b79c32](https://github.com/youzan/vant/commit/b79c32183f6159a663dad42f6189a939061f9f32)
|
||||
|
||||
### [v3.0.2](https://github.com/youzan/vant/compare/v3.0.1...v3.0.2)
|
||||
|
||||
`2021-01-02`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Calendar: add scrollToDate method [#7847](https://github.com/youzan/vant/issues/7847)
|
||||
- Form: add disabled prop [#7830](https://github.com/youzan/vant/issues/7830)
|
||||
- Form: add readonly prop [#7830](https://github.com/youzan/vant/issues/7830)
|
||||
- Loading: add text-color prop [#7806](https://github.com/youzan/vant/issues/7806)
|
||||
- Picker: add columns-field-names prop [#7791](https://github.com/youzan/vant/issues/7791)
|
||||
- NumberKeyboard: add random-key-order prop [#7841](https://github.com/youzan/vant/issues/7841)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Calendar: title slot not work [#7826](https://github.com/youzan/vant/issues/7826)
|
||||
- Calendar: failed to watch defaultDate [#7815](https://github.com/youzan/vant/issues/7815)
|
||||
- Popup: should remove lock scroll before destroyed [#7835](https://github.com/youzan/vant/issues/7835)
|
||||
- Stepper: should format model-value [81494d](https://github.com/youzan/vant/commit/81494dfa13e6ab9a3f12995f481290d27d14ab7a)
|
||||
|
||||
### [v3.0.1](https://github.com/youzan/vant/compare/v3.0.0...v3.0.1)
|
||||
|
||||
`2020-12-27`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Form: support valdiate multiple names [#7810](https://github.com/youzan/vant/issues/7810)
|
||||
- Form: resetValidation support multiple names [#7811](https://github.com/youzan/vant/issues/7811)
|
||||
- Stepper: add show-input prop [#7812](https://github.com/youzan/vant/issues/7812)
|
||||
- IndexBar: add scrollTo method [#7794](https://github.com/youzan/vant/issues/7794)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- CountDown: fix ssr memory leak [#7808](https://github.com/youzan/vant/issues/7808)
|
||||
- Image: mismatching warning during ssr [#7822](https://github.com/youzan/vant/issues/7822)
|
||||
- Popup: lockScroll not work [#7738](https://github.com/youzan/vant/issues/7738)
|
||||
- Stepper: change event emitted twice [#7820](https://github.com/youzan/vant/issues/7820)
|
||||
- Swipe: incorrect size during ssr [#7821](https://github.com/youzan/vant/issues/7821)
|
||||
- Swipe: incorrect active swipe when children changed [#7802](https://github.com/youzan/vant/issues/7802)
|
||||
- Swipe: incorrect active tab when activated [#7772](https://github.com/youzan/vant/issues/7772)
|
||||
|
||||
### [v3.0.0](https://github.com/youzan/vant/compare/v2.12.0...v3.0.0)
|
||||
|
||||
`2020-12-23`
|
||||
|
||||
**Content**
|
||||
|
||||
Reference: [Vant 3.0 正式发布:全面拥抱 Vue 3](https://github.com/youzan/vant/issues/7797)。
|
||||
|
||||
### [v3.0.0-rc.4](https://github.com/youzan/vant/compare/v2.12.0-beta.0...v3.0.0-rc.4)
|
||||
|
||||
`2020-12-21`
|
||||
|
||||
**New Component**
|
||||
|
||||
- add Cascader component [#7771](https://github.com/youzan/vant/pull/7771)
|
||||
|
||||
<img src="https://b.yzcdn.cn/vant/cascader_1221.png">
|
||||
|
||||
**Feature**
|
||||
|
||||
- Stepper: add show-input prop [#7785](https://github.com/youzan/vant/issues/7785)
|
||||
- uploader: add single uploader preview image style [#7731](https://github.com/youzan/vant/issues/7731)
|
||||
|
||||
**Types**
|
||||
|
||||
- Lazyload: fix typing [#7757](https://github.com/youzan/vant/issues/7757)
|
||||
- Contains all features and bug fixes of `v2.12.0-beta.0` version
|
||||
|
||||
### [v3.0.0-rc.3](https://github.com/youzan/vant/compare/v2.11.2...v3.0.0-rc.3)
|
||||
|
||||
`2020-12-10`
|
||||
|
||||
**Breaking Change**
|
||||
|
||||
- Stepper: rename async-change to before-change [e026d2](https://github.com/youzan/vant/commit/e026d2d83f66bb25c66f805cf8085de70d8e009f)
|
||||
|
||||
**perf**
|
||||
|
||||
- Stepper: improve bundle size [#7675](https://github.com/youzan/vant/issues/7675)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Stepper: disabled not work [c27760](https://github.com/youzan/vant/commit/c277603160a7a17685dc532304b9a0c2444db959)
|
||||
- Tabs: failed to set active tab [#7717](https://github.com/youzan/vant/issues/7717)
|
||||
- Contains all features and bug fixes of `v2.11.3` version
|
||||
|
||||
### [v3.0.0-rc.2](https://github.com/youzan/vant/compare/v3.0.0-rc.1...v3.0.0-rc.2)
|
||||
|
||||
`2020-12-04`
|
||||
|
||||
**perf**
|
||||
|
||||
- reduce bundle size [#7675](https://github.com/youzan/vant/issues/7675)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Lazyload: missing esm output [#7685](https://github.com/youzan/vant/issues/7685)
|
||||
- NumberKeyboard: fix hide-on-click-outside prop not working [#7668](https://github.com/youzan/vant/issues/7668) [#7667](https://github.com/youzan/vant/issues/7667)
|
||||
- Uploader: fix change status is not valid [#7681](https://github.com/youzan/vant/issues/7681)
|
||||
- Types: fix teleport typing [#7687](https://github.com/youzan/vant/issues/7687)
|
||||
- Contains all features and bug fixes of `v2.11.2` version
|
||||
|
||||
### [v3.0.0-rc.1](https://github.com/youzan/vant/compare/v2.11.1...v3.0.0-rc.1)
|
||||
|
||||
`2020-12-01`
|
||||
|
||||
**Breaking Change**
|
||||
|
||||
- Popover: adjust trigger default value to click [1699d9](https://github.com/youzan/vant/commit/1699d9927240373867f065355136fd27ac04b0e5)
|
||||
|
||||
**Feature**
|
||||
|
||||
- Lazyload: support Vue 3 [d3ca40](https://github.com/youzan/vant/commit/d3ca404f98ffd572035d7048c949e8942b89fc55)
|
||||
- Contains all features and bug fixes of `v2.11.1` version
|
||||
|
||||
**style**
|
||||
|
||||
- Circle: add @circle-color less var [1a6cf6](https://github.com/youzan/vant/commit/1a6cf64f548bb19c6bd478db67f2e0a1d7c9a145)
|
||||
- Circle: add @circle-layer-color less var [65a5ed](https://github.com/youzan/vant/commit/65a5ed85537b7a406655bd39f7e4f5332d780a82)
|
||||
- Circle: add @circle-size less var [b57f7e](https://github.com/youzan/vant/commit/b57f7e9d9810ce95047334f0897899ebddaac6f3)
|
||||
- IndexBar: adjust default highlight color to red [65b680](https://github.com/youzan/vant/commit/65b6807a7e6b8a415b5f228c5d55426cd81a1dfa)
|
||||
- IndexBar: adjust sticky anchor color to red [87b0a0](https://github.com/youzan/vant/commit/87b0a034958296a720409ded893e708081c35bc5)
|
||||
- IndexBar: increase right padding to 8px [aad055](https://github.com/youzan/vant/commit/aad055906484d8b6c38a9f84a768f09522b13a41)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Image: lazy-load prop not work [0ba818](https://github.com/youzan/vant/commit/0ba8187bf540abc0c593c6571554f1b72e8d3e19)
|
||||
- Lazyload: fix typing [d0c4c2](https://github.com/youzan/vant/commit/d0c4c26d758f18ac3f33fc7d4867a98b731b129d)
|
||||
- Popup: transition-appear prop not work [dd6930](https://github.com/youzan/vant/commit/dd6930533593a363e25f56717e5c17184ef6e867)
|
||||
|
||||
### [v3.0.0-beta.10](https://github.com/youzan/vant/compare/v3.0.0-beta.9...v3.0.0-beta.10)
|
||||
|
||||
`2020-11-22`
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Radio: failed to bind group [0f7c9a](https://github.com/youzan/vant/commit/0f7c9a317cc9a7219ec8431bae0658a5e84d43af)
|
||||
|
||||
### [v3.0.0-beta.9](https://github.com/youzan/vant/compare/v2.11.0...v3.0.0-beta.9)
|
||||
|
||||
`2020-11-22`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Search: add blur method [d26282](https://github.com/youzan/vant/commit/d26282e54245a47075fed01baf6304e0d84559e0)
|
||||
- Search: add focus method [2833bc](https://github.com/youzan/vant/commit/2833bc03f5243370e5a3aeece5b823fc2ebde64c)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Checkbox: bind-group prop not work [#7447](https://github.com/youzan/vant/issues/7447)
|
||||
- Badge: fix missing typing [c487b3](https://github.com/youzan/vant/commit/c487b394efa946f6fae5059f1e1a69be11a25a6e)
|
||||
- Contains all features and bug fixes of `v2.11.0` version
|
||||
|
||||
### [v3.0.0-beta.8](https://github.com/youzan/vant/compare/v2.10.14...v3.0.0-beta.8)
|
||||
|
||||
`2020-11-15`
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- ActionSheet: incorrect behavior when clicking disabled option [996598](https://github.com/youzan/vant/commit/996598686955b90bb5cf7589b5ca1589e17e2016)
|
||||
- ActionSheet: missing callback option [27b761](https://github.com/youzan/vant/commit/27b761f534186a6bfa2e8e54cc78ccb51ec48e25)
|
||||
- Calendar: failed to render when default-date is null #7519 [#7519](https://github.com/youzan/vant/issues/7519)
|
||||
- cli: should not collect coverage from test dir [c21517](https://github.com/youzan/vant/commit/c2151708bbffee95ceb169176bfa5deb5f7e9317)
|
||||
- DatetimePicker: inherit correct props [ed332d](https://github.com/youzan/vant/commit/ed332daf319e2005995f279026a57d4f30a339f6)
|
||||
- NavBar: safe-area-inset-top css incorrect [#7535](https://github.com/youzan/vant/issues/7535)
|
||||
- NoticeBar: avoid repeated start [0712d9](https://github.com/youzan/vant/commit/0712d920634e7b70b77f49c71337172bf3ece470)
|
||||
- Swipe: failed to render in lazy-render mode [e06ba4](https://github.com/youzan/vant/commit/e06ba480a9ec02af8659616ff6ceb5155defddad)
|
||||
- Swipe: avoid repeated initialization [c94173](https://github.com/youzan/vant/commit/c9417341e0adb681db6108cf1383bab77ab90da9)
|
||||
- Tabs: avoid repeated initialization [599e81](https://github.com/youzan/vant/commit/599e817cd4f4239b4a93c75f34118731d47891b5)
|
||||
- Contains all features and bug fixes of `v2.10.14` version
|
||||
|
||||
### [v3.0.0-beta.7](https://github.com/youzan/vant/compare/v2.10.13...v3.0.0-beta.7)
|
||||
|
||||
`2020-11-08`
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Calendar: incorrect initial date [#7412](https://github.com/youzan/vant/issues/7412)
|
||||
- DropdownMenu: can't disable closeOnClickOutside [#7473](https://github.com/youzan/vant/issues/7473)
|
||||
- Uploader: before-read return true not work [#7493](https://github.com/youzan/vant/issues/7493)
|
||||
- Uploader: can't get index in delete event [#7481](https://github.com/youzan/vant/issues/7481)
|
||||
- Contains all features and bug fixes of `v2.10.13` version
|
||||
|
||||
### [v3.0.0-beta.6](https://github.com/youzan/vant/compare/v2.10.12...v3.0.0-beta.6)
|
||||
|
||||
`2020-11-01`
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Calendar: watch maxData/minDate and reset [#7412](https://github.com/youzan/vant/issues/7412)
|
||||
- Swipe: incorrect lazy render when loop is false [#7465](https://github.com/youzan/vant/issues/7465)
|
||||
- Swipe: item should only rendered once [#7466](https://github.com/youzan/vant/issues/7466)
|
||||
- Tabs: skip initial animation [49e877](https://github.com/youzan/vant/commit/49e87756c70b33e1a56620ebee3c0aa53fb9fc86)
|
||||
- ActionBar: fix typing [#7440](https://github.com/youzan/vant/issues/7440) [#7442](https://github.com/youzan/vant/issues/7442)
|
||||
- Contains all features and bug fixes of `v2.10.12` version
|
||||
@@ -0,0 +1,987 @@
|
||||
# 更新日志
|
||||
|
||||
### 提示
|
||||
|
||||
当前文档为 Vant 3 的更新日志,如需查询 Vant 2 的更新内容,请访问 [Vant 2 更新日志](https://youzan.github.io/vant/#/zh-CN/changelog)。
|
||||
|
||||
### 介绍
|
||||
|
||||
Vant 遵循 [Semver](https://semver.org/lang/zh-CN/) 语义化版本规范。
|
||||
|
||||
**发布节奏**
|
||||
|
||||
- 修订号:每周发布,包含新特性和问题修复。
|
||||
- 次版本号:每隔一至二个月发布,包含新特性和较大的功能更新,向下兼容。
|
||||
- 主版本号:无固定的发布时间,包含不兼容更新和重大功能更新。
|
||||
|
||||
## 更新内容
|
||||
|
||||
### [v3.2.2](https://github.com/youzan/vant/compare/v3.2.1...v3.2.2)
|
||||
|
||||
`2021-09-02`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Field: 新增 id 属性 [#9347](https://github.com/youzan/vant/issues/9347)
|
||||
- Field: 新增 `van-field__error` 类名 [#9327](https://github.com/youzan/vant/issues/9327)
|
||||
- Field: label 现在会使用原生 `label` 标签 [#9346](https://github.com/youzan/vant/issues/9346)
|
||||
- Popover: 新增 show-arrow 属性 [#9372](https://github.com/youzan/vant/issues/9372)
|
||||
- Progress: 新增过渡动画效果 [ba4ff5](https://github.com/youzan/vant/commit/ba4ff58af6ccf67e255bf43ef905677dc64596a3)
|
||||
- Search: 新增 id 属性 [#9349](https://github.com/youzan/vant/issues/9349)
|
||||
- Tab: 新增 show-zero-badge 属性 [#9343](https://github.com/youzan/vant/issues/9343)
|
||||
- Locale: 精简一部分国际化文本配置 [#9329](https://github.com/youzan/vant/issues/9329)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- AddressEdit: 移除了无效的样式变量 [#9364](https://github.com/youzan/vant/issues/9364)
|
||||
- Progress: 修复在 v-show 内使用时无法正确渲染的问题 [841e09](https://github.com/youzan/vant/commit/841e09d0529961058ecb63ed26f018cf3a66a3bf)
|
||||
- Progress: 修复 percentage 属性缺少默认值的问题 [8ac597](https://github.com/youzan/vant/commit/8ac597dc3d2316d34f866dcfd7e1646c695da180)
|
||||
- 修复动画相关的 CSS 变量不生效的问题 [#9337](https://github.com/youzan/vant/issues/9337)
|
||||
|
||||
### [v3.2.1](https://github.com/youzan/vant/compare/v3.2.0...v3.2.1)
|
||||
|
||||
`2021-08-22`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Circle: 新增 start-position 属性 [#9305](https://github.com/youzan/vant/issues/9305)
|
||||
- Slider: 新增 reverse 属性 [#9308](https://github.com/youzan/vant/issues/9308)
|
||||
- NumberKeyboard: 新增 van-number-keyboard-key-background-color CSS 变量 [#9303](https://github.com/youzan/vant/issues/9303)
|
||||
- PasswordInput: add password-input-text-color CSS 变量 [#9304](https://github.com/youzan/vant/issues/9304)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Calendar: 修复 month-show 事件缺少 title 参数的问题 [#9275](https://github.com/youzan/vant/issues/9275)
|
||||
- Dialog: 修复 beforeClose 重复触发的问题 [#9283](https://github.com/youzan/vant/issues/9283) [#9291](https://github.com/youzan/vant/issues/9291)
|
||||
- Field: 修复 FieldInstance 类型未导出的问题 [#9254](https://github.com/youzan/vant/issues/9254)
|
||||
- Rate: 修复 count 属性传入字符串类型时展示错误的问题 [#9307](https://github.com/youzan/vant/issues/9307)
|
||||
- TreeSelect: 修复 CSS 负数变量不生效导致样式错误的问题 [#9306](https://github.com/youzan/vant/issues/9306)
|
||||
|
||||
### [v3.2.0](https://github.com/youzan/vant/compare/v3.1.5...v3.2.0)
|
||||
|
||||
`2021-08-12`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Form: 新增 useCustomFieldValue 方法,用于自定义表单项 [#9200](https://github.com/youzan/vant/issues/9200)
|
||||
- Button: loading-size 属性支持 number 类型 [#9177](https://github.com/youzan/vant/issues/9177)
|
||||
- Style: 新增 van-safe-area-bottom 样式类 [#9205](https://github.com/youzan/vant/issues/9205)
|
||||
|
||||
**Types**
|
||||
|
||||
- AddressEdit: 新增 AddressEditInstance 类型 [#9197](https://github.com/youzan/vant/issues/9197)
|
||||
- Area: 新增 AreaInstance 类型 [#9195](https://github.com/youzan/vant/issues/9195)
|
||||
- Calendar: 新增 CalendarInstance 类型 [#9165](https://github.com/youzan/vant/issues/9165)
|
||||
- Checkbox: 新增 CheckboxInstance 类型 [#9140](https://github.com/youzan/vant/issues/9140)
|
||||
- CheckboxGroup: 新增 CheckboxGroupInstance 类型 [#9142](https://github.com/youzan/vant/issues/9142)
|
||||
- CollapseItem: 新增 CollapseItemInstance 类型 [#9194](https://github.com/youzan/vant/issues/9194)
|
||||
- CountDown: 新增 CountDownInstance 类型 [#9153](https://github.com/youzan/vant/issues/9153)
|
||||
- DatetimePicker: 新增 DatetimePickerInstance 类型 [#9208](https://github.com/youzan/vant/issues/9208)
|
||||
- DropdownItem: 新增 DropdownItemInstance 类型 [#9214](https://github.com/youzan/vant/issues/9214)
|
||||
- Field: 新增 FieldInstance 类型 [#9166](https://github.com/youzan/vant/issues/9166)
|
||||
- Form: 新增 FormInstance 类型 [#9139](https://github.com/youzan/vant/issues/9139)
|
||||
- ImagePreview: 新增 ImagePreviewInstance 类型 [#9216](https://github.com/youzan/vant/issues/9216)
|
||||
- IndexBar: 新增 IndexBarInstance 类型 [#9246](https://github.com/youzan/vant/issues/9246)
|
||||
- List: 新增 ListInstance 类型 [#9159](https://github.com/youzan/vant/issues/9159)
|
||||
- NoticeBar: 新增 NoticeBarInstance 类型 [#9245](https://github.com/youzan/vant/issues/9245)
|
||||
- Picker: 新增 PickerInstance 类型 [#9183](https://github.com/youzan/vant/issues/9183)
|
||||
- Progress: 新增 ProgressInstance 类型 [#9247](https://github.com/youzan/vant/issues/9247)
|
||||
- Search: 新增 SearchInstance 类型 [#9181](https://github.com/youzan/vant/issues/9181)
|
||||
- Swipe: 新增 SwipeInstance 类型 [#9158](https://github.com/youzan/vant/issues/9158)
|
||||
- SwipeCell: 新增 SwipeCellInstance 类型 [#9179](https://github.com/youzan/vant/issues/9179)
|
||||
- Tabs: 新增 TabsInstance 类型 [#9174](https://github.com/youzan/vant/issues/9174)
|
||||
- Uploader: 新增 UploaderInstance 类型 [#9164](https://github.com/youzan/vant/issues/9164)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Badge: 修复 offset 为负数时不生效的问题 [#9199](https://github.com/youzan/vant/issues/9199)
|
||||
- Image: 修复圆角数值不正确的问题 [#9163](https://github.com/youzan/vant/issues/9163)
|
||||
- Field: 修复 Textarea 内容较多时,输入会导致页面滚动到顶部的问题 [#9206](https://github.com/youzan/vant/issues/9206)
|
||||
- Notify: 修复默认选项被错误覆盖的问题 [#9138](https://github.com/youzan/vant/issues/9138)
|
||||
- Rate: 修复星星较多时无法自动换行的问题 [#9192](https://github.com/youzan/vant/issues/9192)
|
||||
- Tabs: 修复 card 类型内边距错误的问题 [#9168](https://github.com/youzan/vant/issues/9168)
|
||||
- Toast: 修复某些情况下 message 无法更新的问题 [#9196](https://github.com/youzan/vant/issues/9196)
|
||||
|
||||
### [v3.1.5](https://github.com/youzan/vant/compare/v3.1.4...v3.1.5)
|
||||
|
||||
`2021-07-26`
|
||||
|
||||
**Feature**
|
||||
|
||||
- AddressEdit: 新增 address-edit-button-font-size 样式变量 [#9113](https://github.com/youzan/vant/issues/9113)
|
||||
- Icon: 新增 shield-o 图标 [#9082](https://github.com/youzan/vant/issues/9082)
|
||||
- Locale: 新增 Russian 俄罗斯语言包 [#9088](https://github.com/youzan/vant/issues/9088)
|
||||
- Toast: 优化不可点击状态下的光标展示 [#9116](https://github.com/youzan/vant/issues/9116)
|
||||
- Uploader: 新增 click-upload 事件 [#9119](https://github.com/youzan/vant/issues/9119)
|
||||
- Uploader: 新增 readonly 属性 [#9118](https://github.com/youzan/vant/issues/9118)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Icon: 修复 invitation 图标名称拼写错误 [#9096](https://github.com/youzan/vant/issues/9096)
|
||||
- NumberKeyboard: 修复点击外部时会触发 close 事件的问题 [#9108](https://github.com/youzan/vant/issues/9108)
|
||||
- Search: 修复左侧图标颜色不正确的问题 [#9100](https://github.com/youzan/vant/issues/9100)
|
||||
- Tabbar: 修复 tabbar-item-icon-margin-bottom 样式变量名称 [#9101](https://github.com/youzan/vant/issues/9101)
|
||||
|
||||
### [v3.1.4](https://github.com/youzan/vant/compare/v3.1.3...v3.1.4)
|
||||
|
||||
`2021-07-19`
|
||||
|
||||
**Feature**
|
||||
|
||||
- ActionSheet: 新增 before-close 属性 [#9068](https://github.com/youzan/vant/issues/9068)
|
||||
- Cascader: 新增 option 插槽 [#9036](https://github.com/youzan/vant/issues/9036)
|
||||
- Cascader: 优化光标展示 [#9032](https://github.com/youzan/vant/issues/9032)
|
||||
- Popup: 新增 before-close 属性 [#9067](https://github.com/youzan/vant/issues/9067)
|
||||
- ShareSheet: 新增 before-close 属性 [#9068](https://github.com/youzan/vant/issues/9068)
|
||||
- Tabs: 新增 click-tab 事件 [#9037](https://github.com/youzan/vant/issues/9037)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Field: 修复 label-align 为 right 时 required 标记位置错误的问题 [#9035](https://github.com/youzan/vant/issues/9035)
|
||||
- List: 修复在 Tabs 内嵌套使用时,切换 Tabs 不触发 load 事件的问题 [#9022](https://github.com/youzan/vant/issues/9022)
|
||||
- Popup: 修复某些情况下未正确触发 open、close 事件的问题 [#9065](https://github.com/youzan/vant/issues/9065)
|
||||
|
||||
### [v3.1.3](https://github.com/youzan/vant/compare/v3.1.2...v3.1.3)
|
||||
|
||||
`2021-07-11`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Calendar: 新增 click-subtitle 事件 [#8981](https://github.com/youzan/vant/issues/8981)
|
||||
- Calendar: 新增 subtitle 插槽 [#8980](https://github.com/youzan/vant/issues/8980)
|
||||
- ConfigProvider: 新增 icon-prefix 属性 [#8986](https://github.com/youzan/vant/issues/8986)
|
||||
- Slider: 新增 drag 事件参数 [#8990](https://github.com/youzan/vant/issues/8990)
|
||||
- Slider: 新增 left-button、right-button 插槽 [#8989](https://github.com/youzan/vant/issues/8989)
|
||||
- touch-emulator: 支持通过白名单排除节点 [#8984](https://github.com/youzan/vant/issues/8984)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Step: 修复 z-index 过高问题 [#9003](https://github.com/youzan/vant/issues/9003)
|
||||
|
||||
### [v3.1.2](https://github.com/youzan/vant/compare/v3.1.1...v3.1.2)
|
||||
|
||||
`2021-07-03`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Area: 新增 toolbar、confirm、cancel 插槽 [#8969](https://github.com/youzan/vant/issues/8969)
|
||||
- Calendar: 优化日期较多时的加载性能 [#8955](https://github.com/youzan/vant/issues/8955)
|
||||
- Cascader: 新增 disabled 选项 [#8952](https://github.com/youzan/vant/issues/8952)
|
||||
- ConfigProvider: 新增 tag 属性 [#8967](https://github.com/youzan/vant/issues/8967)
|
||||
- Picker: 新增 toolbar 插槽,将 default 插槽标记为废弃 [#8968](https://github.com/youzan/vant/issues/8968)
|
||||
- Picker: 允许 Option 的值为 number 类型 [#8951](https://github.com/youzan/vant/issues/8951)
|
||||
- Picker: 新增 picker-option-padding CSS 变量 [#8947](https://github.com/youzan/vant/issues/8947)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Toast: 修复文字换行问题 [#8965](https://github.com/youzan/vant/issues/8965)
|
||||
|
||||
### [v3.1.1](https://github.com/youzan/vant/compare/v3.1.0...v3.1.1)
|
||||
|
||||
`2021-06-27`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Cell: 新增 value 插槽,将 default 插槽标记为废弃 [#8933](https://github.com/youzan/vant/issues/8933)
|
||||
- CollapseItem: 新增 label 插槽 [#8934](https://github.com/youzan/vant/issues/8934)
|
||||
- NoticeBar: 新增 reset 方法 [#8917](https://github.com/youzan/vant/issues/8917)
|
||||
- Tabs: 新增 nav-bottom 插槽 [#8915](https://github.com/youzan/vant/issues/8915)
|
||||
|
||||
### [v3.1.0](https://github.com/youzan/vant/compare/v3.1.0-beta.0...v3.1.0)
|
||||
|
||||
`2021-06-22`
|
||||
|
||||
**New Component**
|
||||
|
||||
- 新增 [ConfigProvider](#/zh-CN/config-provider) 组件,用于主题定制 [#8854](https://github.com/youzan/vant/issues/8854)
|
||||
|
||||
**Feature**
|
||||
|
||||
- 所有组件支持 CSS 变量 [aef257](https://github.com/youzan/vant/commit/aef2579a95da7c8b528ba7062b227fea698a0487) [fe1cba](https://github.com/youzan/vant/commit/fe1cba97b796eba7e9b5dca0ce4ab0d1de95715c)
|
||||
- 新增 primary-color 等样式变量 [#8861](https://github.com/youzan/vant/issues/8861)
|
||||
- Checkbox: icon 插槽新增 disabled 参数 [#8839](https://github.com/youzan/vant/issues/8839)
|
||||
- Cascader: 新增 className 选项 [#8882](https://github.com/youzan/vant/issues/8882)
|
||||
- Cascader: 新增 color 选项 [#8883](https://github.com/youzan/vant/issues/8883)
|
||||
- CellGroup: 新增 inset 属性 [#8885](https://github.com/youzan/vant/issues/8885)
|
||||
- GridItem: 新增 reverse 属性 [#8878](https://github.com/youzan/vant/issues/8878)
|
||||
- IndexBar: 新增 teleport 属性 [#8820](https://github.com/youzan/vant/issues/8820)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Dialog: 修复 message 作为函数时返回 HTML 字符串无效的问题 [#8872](https://github.com/youzan/vant/issues/8872)
|
||||
- Slider: 修复设置 step 属性时,输入值格式化错误的问题 [#8893](https://github.com/youzan/vant/issues/8893)
|
||||
|
||||
### [v3.0.18](https://github.com/youzan/vant/compare/v3.0.17...v3.0.18)
|
||||
|
||||
`2021-06-03`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Button: 新增 icon 插槽 [#8783](https://github.com/youzan/vant/issues/8783)
|
||||
- CouponList: 新增 list-footer、disabled-list-footer 插槽 [#8801](https://github.com/youzan/vant/issues/8801)
|
||||
- Locale: 新增 French 法语语言包 [#8795](https://github.com/youzan/vant/issues/8795)
|
||||
- Popup: 新增 icon-prefix 属性 [#8793](https://github.com/youzan/vant/issues/8793)
|
||||
- Popup: 新增 overlay-content 插槽 [#8794](https://github.com/youzan/vant/issues/8794)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Collapse: 修复在 safari 上可能出现渲染异常的问题 [#8788](https://github.com/youzan/vant/issues/8788)
|
||||
- NoticeBar: 修复在 Popup 内嵌套使用时播放异常的问题 [#8789](https://github.com/youzan/vant/issues/8789)
|
||||
- List: 移除未使用的 @list-icon-margin-right 变量 [#8759](https://github.com/youzan/vant/issues/8759)
|
||||
- @vant/touch-emulator: 修复 SSR 时报错的问题 [#8767](https://github.com/youzan/vant/issues/8767)
|
||||
|
||||
### [v3.0.17](https://github.com/youzan/vant/compare/v3.0.16...v3.0.17)
|
||||
|
||||
`2021-05-23`
|
||||
|
||||
**Feature**
|
||||
|
||||
- ActionBarIcon: 新增 icon-prefix 属性 [#8748](https://github.com/youzan/vant/issues/8748)
|
||||
- Calendar: 新增 over-range 事件 [#8739](https://github.com/youzan/vant/issues/8739)
|
||||
- Calendar: 新增 show-range-prompt 属性 [#8739](https://github.com/youzan/vant/issues/8739)
|
||||
- Calendar: 新增 top-info、bottom-info 插槽 [#8716](https://github.com/youzan/vant/issues/8716)
|
||||
- GridItem: 新增 icon-color 属性 [#8753](https://github.com/youzan/vant/issues/8753)
|
||||
- NoticeBar: 默认 speed 由 50 调整为 60 [#8694](https://github.com/youzan/vant/issues/8694)
|
||||
- Popover: 新增 icon-prefix 属性 [#8703](https://github.com/youzan/vant/issues/8703)
|
||||
- Toast: 新增不同类型 Toast 的 transition 过渡效果 [#8743](https://github.com/youzan/vant/issues/8743)
|
||||
- Uploader: max-size 属性支持函数格式 [#8744](https://github.com/youzan/vant/issues/8744)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Button: 修复 tsx 下使用时缺少 onClick 类型定义的问题 [#8665](https://github.com/youzan/vant/issues/8665)
|
||||
- Calendar: 修复默认日期不正确的问题 [#8696](https://github.com/youzan/vant/issues/8696)
|
||||
- DatetimePicker: 修复动态设置 minDate、maxDate 时异常的问题 [#8658](https://github.com/youzan/vant/issues/8658)
|
||||
- List: 修复在开启 animated 的 Tabs 下使用时加载异常的问题 [#8741](https://github.com/youzan/vant/issues/8741)
|
||||
- Tabs: 修复滚动事件监听不正确的问题 [#8734](https://github.com/youzan/vant/issues/8734)
|
||||
- Toast: 修复多次调用时持续时间不正确的问题 [#8742](https://github.com/youzan/vant/issues/8742)
|
||||
|
||||
### [v3.0.16](https://github.com/youzan/vant/compare/v3.0.15...v3.0.16)
|
||||
|
||||
`2021-05-03`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Swipe: 新增 indicator 插槽的 active 参数 [#8645](https://github.com/youzan/vant/issues/8645)
|
||||
- Cascader: 新增 @cascader-header-padding less 变量 [#8626](https://github.com/youzan/vant/issues/8626)
|
||||
- Steps: 新增 icon-prefix 属性 [#8631](https://github.com/youzan/vant/issues/8631)
|
||||
- 导出更多类型定义 [#8652](https://github.com/youzan/vant/issues/8652)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Stepper: 修复 blur 事件触发时机 [#8620](https://github.com/youzan/vant/issues/8620)
|
||||
- SubmitBar: 修复 @submit-bar-price-font-size 变量不生效的问题 [#8639](https://github.com/youzan/vant/issues/8639)
|
||||
- Swipe: 修复在 Popup 内时展示可能不正确的问题 [#8643](https://github.com/youzan/vant/issues/8643)
|
||||
- Tabs: 修复在 Popup 内时展示可能不正确的问题 [#8642](https://github.com/youzan/vant/issues/8642)
|
||||
|
||||
### [v3.0.15](https://github.com/youzan/vant/compare/v2.12.14-test...v3.0.15)
|
||||
|
||||
`2021-04-25`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Cascader: 新增 click-tab 事件 [#8606](https://github.com/youzan/vant/issues/8606)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Tab: 修复 SSR 时报错的问题 [#8603](https://github.com/youzan/vant/issues/8603)
|
||||
- Rate: 修复点击半星时未正确选中的问题 [#8580](https://github.com/youzan/vant/issues/8580)
|
||||
- Tag: 修复使用 color 和 plain 属性时边框颜色错误的问题 [#8601](https://github.com/youzan/vant/issues/8601)
|
||||
|
||||
### [v3.0.14](https://github.com/youzan/vant/compare/v3.0.13...v3.0.14)
|
||||
|
||||
`2021-04-18`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Badge: offset 属性支持传入任意单位 [35edb7](https://github.com/youzan/vant/commit/35edb72b5cd519d4e75443acaa0a63db16695d2d)
|
||||
- Rate: 支持在 readonly 时渲染任意小数结果 [#8528](https://github.com/youzan/vant/issues/8528)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- ContactList: 修复 nodes 类型错误 [0b764b](https://github.com/youzan/vant/commit/0b764b63470b09f5654d267c8d07a20bc2d31536)
|
||||
|
||||
### [v3.0.13](https://github.com/youzan/vant/compare/v3.0.12...v3.0.13)
|
||||
|
||||
`2021-04-11`
|
||||
|
||||
**Feature**
|
||||
|
||||
- ActionBar: 新增 @action-bar-icon-background-color 样式变量 [#8474](https://github.com/youzan/vant/issues/8474)
|
||||
- Popover: 升级依赖的 @popperjs/core 到 2.9.2 版本 [0d1323](https://github.com/youzan/vant/commit/0d132337d5d263957a7993d60e47a18efec7313e)
|
||||
- perf: 优化包体积 [ba3e6d](https://github.com/youzan/vant/commit/ba3e6d56a0bc7ae3acc25b1380f054da3b9b020f)
|
||||
|
||||
**Types**
|
||||
|
||||
- Popup: 修复 PopupCloseIconPosition 类型错误 [15d901](https://github.com/youzan/vant/commit/15d901ad6aace3826881cb3c6e0499f75b71df80)
|
||||
- Search: 修复在 tsx 下部分 props 不存在的问题 [#8485](https://github.com/youzan/vant/issues/8485)
|
||||
- Stepper: 优化 theme 属性类型定义 [#8489](https://github.com/youzan/vant/issues/8489)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Field: 修复 autofocus 属性不生效的问题 [#8488](https://github.com/youzan/vant/issues/8488)
|
||||
|
||||
### [v3.0.12](https://github.com/youzan/vant/compare/v3.0.11...v3.0.12)
|
||||
|
||||
`2021-04-05`
|
||||
|
||||
**Feature**
|
||||
|
||||
- CollapseItem: 新增 readonly 属性 [#8445](https://github.com/youzan/vant/issues/8445)
|
||||
- Field: 新增 clear-icon 属性 [#8438](https://github.com/youzan/vant/issues/8438)
|
||||
- Search: 新增 clear-icon 属性 [#8439](https://github.com/youzan/vant/issues/8439)
|
||||
- Search: 新增 error-message 属性 [#8442](https://github.com/youzan/vant/issues/8442)
|
||||
- Search: 新增 formatter、format-trigger 属性 [#8441](https://github.com/youzan/vant/issues/8441)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- 修复 Webstorm 下组件标签提示不正确的问题 [#8450](https://github.com/youzan/vant/issues/8450)
|
||||
|
||||
### [v3.0.11](https://github.com/youzan/vant/compare/v3.0.10...v3.0.11)
|
||||
|
||||
`2021-03-30`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Cascader: 新增 swipeable 属性 [#8383](https://github.com/youzan/vant/issues/8383)
|
||||
- Dialog: 新增 footer 插槽 [#8382](https://github.com/youzan/vant/issues/8382)
|
||||
- Dialog: 支持在 message 中传入 render 函数 [#8420](https://github.com/youzan/vant/issues/8420)
|
||||
- Image: 新增 icon-size 属性 [#8395](https://github.com/youzan/vant/issues/8395)
|
||||
- Row: 新增 wrap 属性 [#8393](https://github.com/youzan/vant/issues/8393)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Field: 修复在个别情况下错误地清除错误提示的问题 [#8409](https://github.com/youzan/vant/issues/8409)
|
||||
- Sticky: 修复在 SSR 时提示 Element 不存在的问题 [#8407](https://github.com/youzan/vant/issues/8407)
|
||||
- Tabs: 修复在 safari 上左滑退出页面时手势判断错误的问题 [#8388](https://github.com/youzan/vant/issues/8388)
|
||||
|
||||
### [v3.0.10](https://github.com/youzan/vant/compare/v3.0.9...v3.0.10)
|
||||
|
||||
`2021-03-19`
|
||||
|
||||
**Feature**
|
||||
|
||||
- ActionSheet: 新增 cancel 插槽 [#8333](https://github.com/youzan/vant/issues/8333)
|
||||
- Badge: 新增 show-zero 属性 [#8381](https://github.com/youzan/vant/issues/8381)
|
||||
- Cascader: 新增 close-icon 属性 [#8334](https://github.com/youzan/vant/issues/8334)
|
||||
- Popover: 新增 close-on-click-overlay 属性 [#8351](https://github.com/youzan/vant/issues/8351)
|
||||
- Popover: 新增 duration 属性 [#8355](https://github.com/youzan/vant/issues/8355)
|
||||
- Popover: 新增 overlay-class 属性 [#8353](https://github.com/youzan/vant/issues/8353)
|
||||
- Popover: 新增 overlay-style 属性 [#8354](https://github.com/youzan/vant/issues/8354)
|
||||
- ShareSheet: 新增 cancel 插槽 [#8335](https://github.com/youzan/vant/issues/8335)
|
||||
- Sticky: 新增 change event [#8374](https://github.com/youzan/vant/issues/8374)
|
||||
- Tag: close 事件新增 event 参数 [#8337](https://github.com/youzan/vant/issues/8337)
|
||||
- Toast: 新增 iconSize 选项 [#8338](https://github.com/youzan/vant/issues/8338)
|
||||
|
||||
**Feature**
|
||||
|
||||
- ContactList: 新增 @contact-list-item-radio-icon-color Less 变量 [#8322](https://github.com/youzan/vant/issues/8322)
|
||||
- Coupon: 新增 @coupon-corner-checkbox-icon-color Less 变量 [#8323](https://github.com/youzan/vant/issues/8323)
|
||||
- List: 新增 @list-loading-icon-size Less 变量 [#8365](https://github.com/youzan/vant/issues/8365)
|
||||
- Loading: 新增 @button-loading-icon-size Less 变量 [465bf0](https://github.com/youzan/vant/commit/465bf07095c58e8292b23ef0c64be1550aa9d430)
|
||||
- PullRefresh: 新增 @pull-refresh-loading-icon-size Less 变量 [#8366](https://github.com/youzan/vant/issues/8366)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Popover: 修复 close-on-click-outside 属性不生效的问题 [#8352](https://github.com/youzan/vant/issues/8352)
|
||||
- Swipe: 修复添加 scale 动画时宽度计算错误的问题 [#8330](https://github.com/youzan/vant/issues/8330)
|
||||
|
||||
### [v3.0.9](https://github.com/youzan/vant/compare/v3.0.8...v3.0.9)
|
||||
|
||||
`2021-03-08`
|
||||
|
||||
**Feature**
|
||||
|
||||
- AddressList: 新增 tag 插槽 [#8292](https://github.com/youzan/vant/issues/8292)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- 修复主题定制不生效的问题 [#8301](https://github.com/youzan/vant/issues/8301)
|
||||
- 修复在 TS 下使用 app.use 注册组件报错的问题 [#8308](https://github.com/youzan/vant/issues/8308)
|
||||
|
||||
### [v3.0.8](https://github.com/youzan/vant/compare/v3.0.7...v3.0.8)
|
||||
|
||||
`2021-03-07`
|
||||
|
||||
**Types**
|
||||
|
||||
- 完善所有组件的类型定义 [#8264](https://github.com/youzan/vant/issues/8264)
|
||||
|
||||
**Feature**
|
||||
|
||||
- ImagePreview: 新增 transition 属性 [#8275](https://github.com/youzan/vant/issues/8275)
|
||||
- ImagePreview: 新增 overlay-style 属性 [#8276](https://github.com/youzan/vant/issues/8276)
|
||||
- Locale: 新增 th-TH 泰语 [#8297](https://github.com/youzan/vant/issues/8297)
|
||||
- PullRefresh: 新增 pull-distance 属性 [#8280](https://github.com/youzan/vant/issues/8280)
|
||||
- Button: 新增若干个 Less 变量 [#8281](https://github.com/youzan/vant/issues/8281)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- ActionSheet: 修复返回页面时可能错误地重新打开的问题 [#8272](https://github.com/youzan/vant/issues/8272)
|
||||
- Stepper: 修复在 iOS14 下禁用时输入框文字不可见的问题 [#8277](https://github.com/youzan/vant/issues/8277)
|
||||
- Swipe: 修复动态插入轮播图时渲染错误的问题 [#8288](https://github.com/youzan/vant/issues/8288)
|
||||
|
||||
### [v3.0.7](https://github.com/youzan/vant/compare/v3.0.6...v3.0.7)
|
||||
|
||||
`2021-02-28`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Notify: 新增 lockScroll 选项 [#8168](https://github.com/youzan/vant/issues/8168)
|
||||
- Popup: click-overlay 事件新增 `Event` 参数 [#8107](https://github.com/youzan/vant/issues/8107)
|
||||
- ShareSheet: 新增 overlay-style 属性 [#8225](https://github.com/youzan/vant/issues/8225)
|
||||
- ShareSheet: 新增 overlay-class 属性 [#8225](https://github.com/youzan/vant/issues/8225)
|
||||
- Step: 新增 finish-icon 插槽 [#8241](https://github.com/youzan/vant/issues/8241)
|
||||
- Steps: 新增 finish-icon 属性 [#8103](https://github.com/youzan/vant/issues/8103)
|
||||
- Uploader: 新增 @uploader-mask-text-color 样式变量 [#8064](https://github.com/youzan/vant/issues/8064)
|
||||
|
||||
**perf**
|
||||
|
||||
- 包体积优化:调整适配的浏览器版本,与 Vue 3 保持一致 [#8227](https://github.com/youzan/vant/issues/8227)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- ActionSheet: 修复 safe-area-inset-bottom 属性不生效的问题 [#8085](https://github.com/youzan/vant/issues/8085)
|
||||
- DateTimePicker: 修复 v-model 为 null 时初始值不正确的问题 [#8193](https://github.com/youzan/vant/issues/8193)
|
||||
- Form: 修复提交表单时可能滚动到错误的表单项的问题 [#8159](https://github.com/youzan/vant/issues/8159)
|
||||
- ImagePreview: 修复第二次调用时可能出现渲染不正确的问题 [#8060](https://github.com/youzan/vant/issues/8060)
|
||||
- IndexBar: 修复初始化时激活的锚点未正确渲染的问题 [#8164](https://github.com/youzan/vant/issues/8164)
|
||||
- Popup: 修复动态设置 lock-scroll 属性不生效的问题 [#8169](https://github.com/youzan/vant/issues/8169)
|
||||
- Swipe: 修复初始化时 active 值可能错误的问题 [#8061](https://github.com/youzan/vant/issues/8061)
|
||||
- SwipeCell: 修复点击外部时 click 事件参数不正确的问题 [#8108](https://github.com/youzan/vant/issues/8108)
|
||||
- Tabbar: 修复 name 为 0 时激活的选项可能不正确的问题 [#8125](https://github.com/youzan/vant/issues/8125)
|
||||
- Tabs: 修复 v-model 为 0 时激活的标签页可能不正确的问题 [#8074](https://github.com/youzan/vant/issues/8074)
|
||||
- Toast: 修复 SSR 时可能报错的问题 [#8214](https://github.com/youzan/vant/issues/8214)
|
||||
|
||||
### [v3.0.6](https://github.com/youzan/vant/compare/v3.0.5...v3.0.6)
|
||||
|
||||
`2021-01-31`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Area: 支持超过 6 位的地区码 [#8001](https://github.com/youzan/vant/issues/8001)
|
||||
- Form: show-error 属性的默认值调整为 false [#8016](https://github.com/youzan/vant/issues/8016)
|
||||
- Form: 支持在 validator 中返回错误提示 [#8052](https://github.com/youzan/vant/issues/8052)
|
||||
- NumberKeyboard: 新增 blur-on-close 属性 [#8033](https://github.com/youzan/vant/issues/8033)
|
||||
- Popover: 新增 click-overlay 事件 [#8050](https://github.com/youzan/vant/issues/8050)
|
||||
- Popover: 支持在 action 选项对象中配置 color 字段 [#8049](https://github.com/youzan/vant/issues/8049)
|
||||
- Sticky: 新增 position、offset-bottom 属性 [#7979](https://github.com/youzan/vant/issues/7979)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Button: 修复加载状态下会触发表单提交的问题 [#8018](https://github.com/youzan/vant/issues/8018)
|
||||
- Calendar: 修复无法使用 scrollToDate 方法的问题 [#7983](https://github.com/youzan/vant/issues/7983)
|
||||
- Empty: 修复 linearGradient id 可能导致冲突的问题 [#8013](https://github.com/youzan/vant/issues/8013)
|
||||
- Toast: 修复 closeOnClickOverlay 设置为 true 不生效的问题 [#8044](https://github.com/youzan/vant/issues/8044)
|
||||
|
||||
### [v3.0.5](https://github.com/youzan/vant/compare/v3.0.4...v3.0.5)
|
||||
|
||||
`2021-01-24`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Badge: 新增 offset 属性 [e0b463](https://github.com/youzan/vant/commit/e0b463630108b5031a02a8afcd0c141a7fdbac9e)
|
||||
- Calendar: reset 方法支持重置到指定日期 [#7966](https://github.com/youzan/vant/issues/7966)
|
||||
- Icons: 新增 wechat 图标, 重命名原 wechat 图标为 wechat-pay [b3cd8c](https://github.com/youzan/vant/commit/b3cd8c14aea9e542a9de4ba9999e50c3ecbf3b3c)
|
||||
- ImagePreview: 调用 swipeTo 方法后自动重置缩放状态 [#7972](https://github.com/youzan/vant/issues/7972)
|
||||
- ImagePreview: 调整 swipeDuration 的默认值为 300ms [#7970](https://github.com/youzan/vant/issues/7970)
|
||||
- ShareSheet: 新增 wechat-moments 朋友圈图标 [ca66fb](https://github.com/youzan/vant/commit/ca66fbca36c5c839e3a294d465b0fc2bd7bf5039)
|
||||
- Slider: 新增 readonly 属性 [4cd991](https://github.com/youzan/vant/commit/4cd991dfec01bd5342cb59b750d0dfa5901b8dc8)
|
||||
|
||||
**style**
|
||||
|
||||
- ShareSheet: 更新 qrcode 图标 [32a08b](https://github.com/youzan/vant/commit/32a08bb6807d9d38027e03eef376d82b6eab282e)
|
||||
- TreeSelect: 新增右侧选项点击反馈 [bada31](https://github.com/youzan/vant/commit/bada315fb3b0fbdf30c663170c867bbbc274687c)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Calendar: 修复调用 reset 方法时未重置到默认日期的问题 [#7967](https://github.com/youzan/vant/issues/7967)
|
||||
- Dialog: 修复切换 allowHtml 时 message 渲染不正确的问题 [#7968](https://github.com/youzan/vant/issues/7968)
|
||||
- ImagePreview: 修复 scale 事件的 index 参数为 undefined 的问题 [#7971](https://github.com/youzan/vant/issues/7971)
|
||||
|
||||
### [v3.0.4](https://github.com/youzan/vant/compare/v3.0.3...v3.0.4)
|
||||
|
||||
`2021-01-17`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Cascader: 新增 field-names 属性,用于自定义字段名 [#7933](https://github.com/youzan/vant/issues/7933)
|
||||
- Cell: 支持在设置 is-link 时将 clickable 设置为 false 来禁用点击状态 [#7923](https://github.com/youzan/vant/issues/7923)
|
||||
- DropdownItem: 支持传入数组或对象格式的 title-class [#7926](https://github.com/youzan/vant/issues/7926)
|
||||
- Popup: 支持传入数组或对象格式的 overlay-class [#7924](https://github.com/youzan/vant/issues/7924)
|
||||
- Toast: 新增 overlayClass 选项 [#7925](https://github.com/youzan/vant/issues/7925)
|
||||
- Toast: 新增 overlayStyle 选项 [#7898](https://github.com/youzan/vant/issues/7898)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- AddressEdit: 修复无法调用 setAreaCode 方法的问题 [6a184f](https://github.com/youzan/vant/commit/6a184f8e930fea31035680dd44f40bc007aba4cd)
|
||||
- Circle: 修复渐变色不生效的问题 [#7909](https://github.com/youzan/vant/issues/7909)
|
||||
- NumberKeyboard: 修复 delete、extra-key 插槽不生效的问题 [52a0e5](https://github.com/youzan/vant/commit/52a0e5a8c70dcc07b87140e33318acefcbdd3ef9)
|
||||
- Search: 修复控制台存在 update:modelValue warning 的问题 [#7872](https://github.com/youzan/vant/issues/7872)
|
||||
- Swipe: 修复页面隐藏时未暂停自动轮播的问题 [1c428f](https://github.com/youzan/vant/commit/1c428f240cd44d3389510263dd7f03973cfbfa2b)
|
||||
|
||||
### [v3.0.3](https://github.com/youzan/vant/compare/v3.0.2...v3.0.3)
|
||||
|
||||
`2021-01-10`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Field: 新增 autocomplate 属性 [#7877](https://github.com/youzan/vant/issues/7877)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Area: 修复无法调用 getValues 方法的问题 [03c7b4](https://github.com/youzan/vant/commit/03c7b46b04d8c543f952cbf8399ec21ca39f979f)
|
||||
- ImagePreview: 修复 close-on-popstate 属性不生效的问题 [#7880](https://github.com/youzan/vant/issues/7880)
|
||||
- List: 修复更新 error 属性后未触发位置检查的问题 [b79c32](https://github.com/youzan/vant/commit/b79c32183f6159a663dad42f6189a939061f9f32)
|
||||
|
||||
### [v3.0.2](https://github.com/youzan/vant/compare/v3.0.1...v3.0.2)
|
||||
|
||||
`2021-01-02`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Calendar: 新增 scrollToDate 方法 [#7847](https://github.com/youzan/vant/issues/7847)
|
||||
- Form: 新增 disabled 属性 [#7830](https://github.com/youzan/vant/issues/7830)
|
||||
- Form: 新增 readonly 属性 [#7830](https://github.com/youzan/vant/issues/7830)
|
||||
- Loading: 新增 text-color 属性 [#7806](https://github.com/youzan/vant/issues/7806)
|
||||
- Picker: 新增 columns-field-names 属性 [#7791](https://github.com/youzan/vant/issues/7791)
|
||||
- NumberKeyboard: 新增 random-key-order 属性 [#7841](https://github.com/youzan/vant/issues/7841)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Calendar: 修复 title 插槽不生效的问题 [#7826](https://github.com/youzan/vant/issues/7826)
|
||||
- Calendar: 修复动态设置 defaultDate 不生效的问题 [#7815](https://github.com/youzan/vant/issues/7815)
|
||||
- Popup: 修复组件销毁时未解除滚动锁定的问题 [#7835](https://github.com/youzan/vant/issues/7835)
|
||||
- Stepper: 修复动态设置 modelValue 时未格式化的问题 [81494d](https://github.com/youzan/vant/commit/81494dfa13e6ab9a3f12995f481290d27d14ab7a)
|
||||
|
||||
### [v3.0.1](https://github.com/youzan/vant/compare/v3.0.0...v3.0.1)
|
||||
|
||||
`2020-12-27`
|
||||
|
||||
**Feature**
|
||||
|
||||
- Form: valdiate 方法支持校验多个表单项 [#7810](https://github.com/youzan/vant/issues/7810)
|
||||
- Form: resetValidation 方法支持重置多个表单项 [#7811](https://github.com/youzan/vant/issues/7811)
|
||||
- Stepper: 新增 show-input 属性,用于控制是否显示输入框 [#7812](https://github.com/youzan/vant/issues/7812)
|
||||
- IndexBar: 新增 scrollTo 方法 [#7794](https://github.com/youzan/vant/issues/7794)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Cascader: 修复动画闪烁的问题 [#7802](https://github.com/youzan/vant/issues/7802)
|
||||
- CountDown: 修复 SSR 过程中内存泄露的问题 [#7808](https://github.com/youzan/vant/issues/7808)
|
||||
- Image: 修复 SSR 时提示 DOM 不匹配的问题 [#7822](https://github.com/youzan/vant/issues/7822)
|
||||
- Popup: 修复滚动穿透的问题 [#7738](https://github.com/youzan/vant/issues/7738)
|
||||
- Stepper: 修复 change 事件重复触发的问题 [#7820](https://github.com/youzan/vant/issues/7820)
|
||||
- Swipe: 修复 SSR 样式不正确的问题 [#7821](https://github.com/youzan/vant/issues/7821)
|
||||
- Swipe: 修复在 keepalive 标签内使用时显示不正确的问题 [#7772](https://github.com/youzan/vant/issues/7772)
|
||||
|
||||
### [v3.0.0](https://github.com/youzan/vant/compare/v2.12.0...v3.0.0)
|
||||
|
||||
`2020-12-23`
|
||||
|
||||
**更新内容**
|
||||
|
||||
请参考 [Vant 3.0 正式发布:全面拥抱 Vue 3](https://github.com/youzan/vant/issues/7797)。
|
||||
|
||||
### [v3.0.0-rc.4](https://github.com/youzan/vant/compare/v2.12.0-beta.0...v3.0.0-rc.4)
|
||||
|
||||
`2020-12-21`
|
||||
|
||||
**New Component**
|
||||
|
||||
- 新增 Cascader 级联选择组件 [#7771](https://github.com/youzan/vant/pull/7771)
|
||||
|
||||
<img src="https://b.yzcdn.cn/vant/cascader_1221.png">
|
||||
|
||||
**Feature**
|
||||
|
||||
- Stepper: 新增 show-input 属性 [#7785](https://github.com/youzan/vant/issues/7785)
|
||||
- uploader: 支持在 fileList 的选项中单独配置 `imageFit` `deletable` `previewSize` `beforeDelete` 字段 [#7731](https://github.com/youzan/vant/issues/7731)
|
||||
|
||||
**Types**
|
||||
|
||||
- Lazyload: 修复类型定义错误 [#7757](https://github.com/youzan/vant/issues/7757)
|
||||
|
||||
### [v3.0.0-rc.3](https://github.com/youzan/vant/compare/v2.11.2...v3.0.0-rc.3)
|
||||
|
||||
`2020-12-10`
|
||||
|
||||
**Breaking Change**
|
||||
|
||||
- Stepper: `async-change` 属性重命名为 `before-change`,并调整使用方法 [e026d2](https://github.com/youzan/vant/commit/e026d2d83f66bb25c66f805cf8085de70d8e009f)
|
||||
|
||||
**perf**
|
||||
|
||||
- Stepper: 优化代码包体积 [#7675](https://github.com/youzan/vant/issues/7675)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Stepper: 修复禁用按钮仍然能点击的问题 [c27760](https://github.com/youzan/vant/commit/c277603160a7a17685dc532304b9a0c2444db959)
|
||||
- Tabs: 修复动态设置 active 值无效的问题 [#7717](https://github.com/youzan/vant/issues/7717)
|
||||
- 包含 `v2.11.3` 版本的所有改动和修复
|
||||
|
||||
### [v3.0.0-rc.2](https://github.com/youzan/vant/compare/v3.0.0-rc.1...v3.0.0-rc.2)
|
||||
|
||||
`2020-12-04`
|
||||
|
||||
**perf**
|
||||
|
||||
- 优化包体积大小 [#7675](https://github.com/youzan/vant/issues/7675)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Lazyload: 修复未导出 ESModule 的问题 [#7685](https://github.com/youzan/vant/issues/7685)
|
||||
- NumberKeyboard: 修复 hide-on-click-outside 属性不生效的问题 [#7668](https://github.com/youzan/vant/issues/7668) [#7667](https://github.com/youzan/vant/issues/7667)
|
||||
- Uploader: 修复动态修改 status 不生效的问题 [#7681](https://github.com/youzan/vant/issues/7681)
|
||||
- Types: 修复 teleport 类型定义错误的问题 [#7687](https://github.com/youzan/vant/issues/7687)
|
||||
- 包含 `v2.11.2` 版本的所有改动和修复
|
||||
|
||||
### [v3.0.0-rc.1](https://github.com/youzan/vant/compare/v2.11.1...v3.0.0-rc.1)
|
||||
|
||||
`2020-12-01`
|
||||
|
||||
**Breaking Change**
|
||||
|
||||
- Popover: trigger 属性的默认值调整为 click [1699d9](https://github.com/youzan/vant/commit/1699d9927240373867f065355136fd27ac04b0e5)
|
||||
|
||||
**Feature**
|
||||
|
||||
- Lazyload: 适配 Vue 3 [d3ca40](https://github.com/youzan/vant/commit/d3ca404f98ffd572035d7048c949e8942b89fc55)
|
||||
- 包含 `v2.11.1` 版本的所有改动和修复
|
||||
|
||||
**style**
|
||||
|
||||
- Circle: 新增 @circle-color Less 变量 [1a6cf6](https://github.com/youzan/vant/commit/1a6cf64f548bb19c6bd478db67f2e0a1d7c9a145)
|
||||
- Circle: 新增 @circle-layer-color Less 变量 [65a5ed](https://github.com/youzan/vant/commit/65a5ed85537b7a406655bd39f7e4f5332d780a82)
|
||||
- Circle: 新增 @circle-size Less 变量 [b57f7e](https://github.com/youzan/vant/commit/b57f7e9d9810ce95047334f0897899ebddaac6f3)
|
||||
- IndexBar: 默认高亮颜色调整为红色 [65b680](https://github.com/youzan/vant/commit/65b6807a7e6b8a415b5f228c5d55426cd81a1dfa) [87b0a0](https://github.com/youzan/vant/commit/87b0a034958296a720409ded893e708081c35bc5)
|
||||
- IndexBar: 右边距调整为 8px [aad055](https://github.com/youzan/vant/commit/aad055906484d8b6c38a9f84a768f09522b13a41)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Image: 修复 lazy-load 属性不生效的问题 [0ba818](https://github.com/youzan/vant/commit/0ba8187bf540abc0c593c6571554f1b72e8d3e19)
|
||||
- Lazyload: 修复类型定义错误的问题 [d0c4c2](https://github.com/youzan/vant/commit/d0c4c26d758f18ac3f33fc7d4867a98b731b129d)
|
||||
- Popup: 修复 transition-appear 属性不生效的问题 [dd6930](https://github.com/youzan/vant/commit/dd6930533593a363e25f56717e5c17184ef6e867)
|
||||
|
||||
### [v3.0.0-beta.10](https://github.com/youzan/vant/compare/v3.0.0-beta.9...v3.0.0-beta.10)
|
||||
|
||||
`2020-11-22`
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Radio: 修复 Radio 无法操作的问题 [0f7c9a](https://github.com/youzan/vant/commit/0f7c9a317cc9a7219ec8431bae0658a5e84d43af)
|
||||
|
||||
### [v3.0.0-beta.9](https://github.com/youzan/vant/compare/v2.11.0...v3.0.0-beta.9)
|
||||
|
||||
`2020-11-22`
|
||||
|
||||
**New Component**
|
||||
|
||||
- 新增 [Popover 气泡弹出框](#/zh-CN/popover)组件 [#7579](https://github.com/youzan/vant/issues/7579)
|
||||
|
||||

|
||||
|
||||
**Feature**
|
||||
|
||||
- Search: 新增 blur 方法 [d26282](https://github.com/youzan/vant/commit/d26282e54245a47075fed01baf6304e0d84559e0)
|
||||
- Search: 新增 focus 方法 [2833bc](https://github.com/youzan/vant/commit/2833bc03f5243370e5a3aeece5b823fc2ebde64c)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Checkbox: 修复 bind-group 属性不生效的问题 [#7447](https://github.com/youzan/vant/issues/7447)
|
||||
- Badge: 修复无类型定义的问题 [c487b3](https://github.com/youzan/vant/commit/c487b394efa946f6fae5059f1e1a69be11a25a6e)
|
||||
- 包含 `v2.11.0` 版本的所有改动和修复
|
||||
|
||||
### [v3.0.0-beta.8](https://github.com/youzan/vant/compare/v2.10.14...v3.0.0-beta.8)
|
||||
|
||||
`2020-11-15`
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- ActionSheet: 修复选项禁用或加载时仍能点击的问题 [996598](https://github.com/youzan/vant/commit/996598686955b90bb5cf7589b5ca1589e17e2016)
|
||||
- ActionSheet: 修复 callback 选项不生效的问题 [27b761](https://github.com/youzan/vant/commit/27b761f534186a6bfa2e8e54cc78ccb51ec48e25)
|
||||
- Calendar: 修复 default-date 为 null 时渲染失败的问题 [#7519](https://github.com/youzan/vant/issues/7519)
|
||||
- DatetimePicker: 修复 DOM 上渲染多余属性的问题 [ed332d](https://github.com/youzan/vant/commit/ed332daf319e2005995f279026a57d4f30a339f6)
|
||||
- NoticeBar: 修复初始化逻辑执行多次的问题 [0712d9](https://github.com/youzan/vant/commit/0712d920634e7b70b77f49c71337172bf3ece470)
|
||||
- Swipe: 修复在 lazy-render 模式下渲染失败的问题 [e06ba4](https://github.com/youzan/vant/commit/e06ba480a9ec02af8659616ff6ceb5155defddad)
|
||||
- Swipe: 修复初始化逻辑执行多次的问题 [c94173](https://github.com/youzan/vant/commit/c9417341e0adb681db6108cf1383bab77ab90da9)
|
||||
- Tabs: 修复初始化逻辑执行多次的问题 [599e81](https://github.com/youzan/vant/commit/599e817cd4f4239b4a93c75f34118731d47891b5)
|
||||
- 包含 `v2.10.14` 版本的所有改动和修复
|
||||
|
||||
### [v3.0.0-beta.7](https://github.com/youzan/vant/compare/v2.10.13...v3.0.0-beta.7)
|
||||
|
||||
`2020-11-08`
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Calendar: 修复动态设置 minDate 和 maxDate 时展示错误的问题 [#7412](https://github.com/youzan/vant/issues/7412)
|
||||
- DropdownMenu: 修复无法禁用 closeOnClickOutside 属性的问题 [#7473](https://github.com/youzan/vant/issues/7473)
|
||||
- Uploader: 修复在 before-read 返回 true 无效的问题 [#7493](https://github.com/youzan/vant/issues/7493)
|
||||
- Uploader: 修复在 delete 事件中无法获取 index 的问题 [#7481](https://github.com/youzan/vant/issues/7481)
|
||||
- 包含 `v2.10.13` 版本的所有改动和修复
|
||||
|
||||
### [v3.0.0-beta.6](https://github.com/youzan/vant/compare/v2.10.12...v3.0.0-beta.6)
|
||||
|
||||
`2020-11-01`
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Swipe: 修复开启 lazy-render 且 loop 为 false 时渲染节点不正确的问题 [#7465](https://github.com/youzan/vant/issues/7465)
|
||||
- Swipe: 修复开启 lazy-render 时子节点被重复挂载的问题 [#7466](https://github.com/youzan/vant/issues/7466)
|
||||
- Tabs: 修复初始动画错误的问题 [49e877](https://github.com/youzan/vant/commit/49e87756c70b33e1a56620ebee3c0aa53fb9fc86)
|
||||
- ActionBar: 修复类型定义不存在的问题 [#7440](https://github.com/youzan/vant/issues/7440) [#7442](https://github.com/youzan/vant/issues/7442)
|
||||
- 包含 `v2.10.12` 版本的所有改动和修复
|
||||
|
||||
### [v3.0.0-beta.5](https://github.com/youzan/vant/compare/v2.10.11...v3.0.0-beta.5)
|
||||
|
||||
`2020-10-24`
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Swipe: 修复动态插入轮播时无法滚动的问题 [#7366](https://github.com/youzan/vant/issues/7366)
|
||||
- Toast: 修复 forbidClick 属性不生效的问题 [#7396](https://github.com/youzan/vant/issues/7396)
|
||||
- Toast: 修复 duration 变化未生效的问题 [#7394](https://github.com/youzan/vant/issues/7394)
|
||||
- 包含 `v2.10.11` 版本的所有改动和修复
|
||||
|
||||
### [v3.0.0-beta.4](https://github.com/youzan/vant/compare/v2.10.10...v3.0.0-beta.4)
|
||||
|
||||
`2020-10-18`
|
||||
|
||||
**refactor**
|
||||
|
||||
- Layout: 默认使用 flex 布局,移除 type 属性 [f7a120](https://github.com/youzan/vant/commit/f7a1208a18f61eaa9dbec80db1c585f19229cd91)
|
||||
|
||||
**style**
|
||||
|
||||
- Stepper: 布局方式调整为 inline-block [e9c282](https://github.com/youzan/vant/commit/e9c28212358cd0317442051383b92d23441920c6)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- ContactList: 修复 select 事件重复触发的问题 [1dd408](https://github.com/youzan/vant/commit/1dd4083102272250637d6397bd98355d87d99bf5)
|
||||
- Search: 修复布局错误的问题 [9cd48e](https://github.com/youzan/vant/commit/9cd48e0e333fc6f0a2f71b568b7e5b5ca2138bae)
|
||||
- Image: 修复图片加载错误时仍会渲染图片节点的问题 [59fb1d](https://github.com/youzan/vant/commit/59fb1d4dfcdc99773642a63c62e6b08baa3fac30)
|
||||
- Pagination: 修复 change 事件触发时机错误的问题 [346035](https://github.com/youzan/vant/commit/3460351ce396bb418408ddbfad462ddac8ef9477)
|
||||
- Toast: 修复展示时会锁定滚动的问题 [a622ca](https://github.com/youzan/vant/commit/a622caa649baedac7cfe9614ded88e7ec1cd18e1)
|
||||
- 包含 `v2.10.10` 版本的所有改动和修复
|
||||
|
||||
### [v3.0.0-beta.3](https://github.com/youzan/vant/compare/v2.10.9...v3.0.0-beta.3)
|
||||
|
||||
`2020-10-03`
|
||||
|
||||
**breaking changes**
|
||||
|
||||
- Checkbox: 在 Cell 内部使用时,现在需要手动添加 `@click.stop` 来阻止事件冒泡 [#7023](https://github.com/youzan/vant/issues/7023)
|
||||
|
||||
**Feature**
|
||||
|
||||
- 新增 Badge 徽标组件 [#6573](https://github.com/youzan/vant/issues/6573)
|
||||
- Tab: 增加滑动切换动画 [#1174](https://github.com/youzan/vant/issues/1174)
|
||||
- 包含 `v2.10.9` 版本的所有改动和修复
|
||||
|
||||
### [v3.0.0-beta.2](https://github.com/youzan/vant/compare/v3.0.0-beta.1...v3.0.0-beta.2)
|
||||
|
||||
`2020-09-28`
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- 修复引入 Vant 时提示 'global is not defined' 的问题 [7007fc](https://github.com/youzan/vant/commit/7007fcf9eaea239f5e680068d59d8e9f8202ec3b)
|
||||
|
||||
### [v3.0.0-beta.1](https://github.com/youzan/vant/compare/v2.10.8...v3.0.0-beta.1)
|
||||
|
||||
`2020-09-28`
|
||||
|
||||
**breaking changes**
|
||||
|
||||
- DatetimePicker: change 事件的第一个参数调整为当前选中值 [058665](https://github.com/youzan/vant/commit/05866514dbdac098d8210f8b08e2fbc8d3479ada)
|
||||
|
||||
**refactor**
|
||||
|
||||
使用 Composition API 重构以下组件:
|
||||
|
||||
- AddressEdit [749e4a](https://github.com/youzan/vant/commit/749e4ae73b9c07265e81237493b5e7d37afc6255)
|
||||
- Calendar [fc50e2](https://github.com/youzan/vant/commit/fc50e26416feb1cbc3d07de23cd39bf6ba57eefc)
|
||||
- Checkbox [278ea6](https://github.com/youzan/vant/commit/278ea6a439b65c1bf1ce420ab7619858a739486c)
|
||||
- ContactEdit [4f0921](https://github.com/youzan/vant/commit/4f0921cbdffe1f654ce75222027f8b85120ab67b)
|
||||
- DatetimePicker [638842](https://github.com/youzan/vant/commit/6388423c9609e099565e51423271e333fab38a55)
|
||||
- Field [00dbf2](https://github.com/youzan/vant/commit/00dbf2cc50c44d0ac45bc43daeaa91730b1a6e23)
|
||||
- Form [92aac9](https://github.com/youzan/vant/commit/92aac941fc25e028a7631be301ed895edff53487)
|
||||
- Radio [aafbcf](https://github.com/youzan/vant/commit/aafbcfcf04e7c0a4b4f5da83291e9b158f2503c3)
|
||||
- Tabs [882e3e](https://github.com/youzan/vant/commit/882e3ef5e787e587909bde1064f5dabe3d66ad72)
|
||||
|
||||
**Feature**
|
||||
|
||||
- Locale: 新增德语语言包 [#7245](https://github.com/youzan/vant/issues/7245)
|
||||
- Pagination: 新增多个插槽 [#7222](https://github.com/youzan/vant/issues/7222)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Picker: 修复 setIndex 方法无效的问题 [d2a542](https://github.com/youzan/vant/commit/d2a54279766acca3981403c4fb9eb34d3d586643)
|
||||
- Dialog: 修复最小高度错误的问题 [bf1f0f](https://github.com/youzan/vant/commit/bf1f0f57eb16e2308b388c4e2ccab46c65f76196)
|
||||
- 包含 `v2.10.8` 版本的所有改动和修复
|
||||
|
||||
### [v3.0.0-beta.0](https://github.com/youzan/vant/compare/v2.10.7...v3.0.0-beta.0)
|
||||
|
||||
`2020-09-18`
|
||||
|
||||
**breaking changes**
|
||||
|
||||
- Dialog: allow-html 属性的默认值调整为 false [02c7a7](https://github.com/youzan/vant/commit/02c7a75ee3d7725157b744bb710bd879f01a0065)
|
||||
- Picker: allow-html 属性的默认值调整为 false [02c7a7](https://github.com/youzan/vant/commit/02c7a75ee3d7725157b744bb710bd879f01a0065)
|
||||
|
||||
**refactor**
|
||||
|
||||
使用 Composition API 重构以下组件:
|
||||
|
||||
- ImagePreview [6ab2b3](https://github.com/youzan/vant/commit/6ab2b3bf1f53dabf272ae3a6d663221236eab47c)
|
||||
- Picker [85d0d4](https://github.com/youzan/vant/commit/85d0d423eb33567d74d029991509589237214cf8)
|
||||
- Popup [946565](https://github.com/youzan/vant/commit/9465653f429d216bf0f34cb9cf26cc1f51b3e358)
|
||||
- Swipe [39c68c](https://github.com/youzan/vant/commit/39c68c993a34f8cfb0de056f0da7edcd01bd6d4d)
|
||||
- Uploader [595b06](https://github.com/youzan/vant/commit/595b062c34e34e48b5f8d730dc6b13221fcad841)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- AddressEdit: 修复 emits 未声明导致 warning 的问题 [1e6a12](https://github.com/youzan/vant/commit/1e6a120b2e48f7262062729260d362c96355eca6)
|
||||
- AddressEdit: 修复点击省市区弹窗的蒙层时无法关闭的问题 [02e89a](https://github.com/youzan/vant/commit/02e89a73c57af1e59429ab320c2a13395abc0520)
|
||||
- Field: 修复在 iOS 上中文输入过程中触发 input 事件的问题 [#7035](https://github.com/youzan/vant/issues/7035)
|
||||
- 包含 `v2.10.7` 版本的所有改动和修复
|
||||
|
||||
### [v3.0.0-alpha.5](https://github.com/youzan/vant/compare/v2.10.6...v3.0.0-alpha.5)
|
||||
|
||||
`2020-09-13`
|
||||
|
||||
**breaking changes**
|
||||
|
||||
- Button: native-type 属性的默认值调整为 button [df8059](https://github.com/youzan/vant/commit/df8059eb015f2804433a7306c208a5909a4d46ac)
|
||||
|
||||
**refactor**
|
||||
|
||||
使用 Composition API 重构以下组件:
|
||||
|
||||
- DatetimePicker [60e087](https://github.com/youzan/vant/commit/60e08767b313e90b13c6a4a3246a113367ed09a5)
|
||||
- DropdownItem [cd5f5b](https://github.com/youzan/vant/commit/cd5f5bb65544676279e486790761c38a2a9f0fc1)
|
||||
- Grid [38740b](https://github.com/youzan/vant/commit/38740b6c1c783d49a2201b24ba51121576e4c643)
|
||||
- IndexBar [f94c8c](https://github.com/youzan/vant/commit/f94c8ccbb93f4783814832a9363d663fb4986f10)
|
||||
- NumberKeyboard [14c1d4](https://github.com/youzan/vant/commit/14c1d4ea771cd9f01cb282493e57303ced897fa9)
|
||||
- PullRefresh [9f632f](https://github.com/youzan/vant/commit/9f632f151e3028adfd376f8ad166bf9d8af356fc)
|
||||
- Stepper [a7c285](https://github.com/youzan/vant/commit/a7c28548fcefe48a2ffa95bb0423dee0a48f8e16)
|
||||
- SwipeCell [b17c67](https://github.com/youzan/vant/commit/b17c67ab53652a361185934cb4119eca23622d9a)
|
||||
|
||||
**Feature**
|
||||
|
||||
- Button: 新增 icon-position 属性 [#7174](https://github.com/youzan/vant/issues/7174)
|
||||
- slider: 新增 range 属性,支持范围选择 [#7175](https://github.com/youzan/vant/issues/7175)
|
||||
- TabbarItem: 新增 @tabbar-item-active-background-color 变量 [#7162](https://github.com/youzan/vant/issues/7162)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Sticky: 修复组件销毁时报错的问题 [#7169](https://github.com/youzan/vant/issues/7169)
|
||||
|
||||
### [v3.0.0-alpha.4](https://github.com/youzan/vant/compare/v2.10.5...v3.0.0-alpha.4)
|
||||
|
||||
`2020-09-06`
|
||||
|
||||
**breaking changes**
|
||||
|
||||
- Dialog: `before-close` 属性用法调整,不再传入 done 函数,而是通过返回 Promise 来控制
|
||||
- SwipeCell: `before-close` 属性不再传入组件实例
|
||||
- ImagePreview: 移除 `async-close` 属性,新增 `before-close` 属性
|
||||
|
||||
**refactor**
|
||||
|
||||
使用 Composition API 重构以下组件:
|
||||
|
||||
- Coupon [ec5a75](https://github.com/youzan/vant/commit/ec5a759f684531e7c5ab751d1d746d0e65d26279)
|
||||
- Dialog [2b8284](https://github.com/youzan/vant/commit/2b8284a227b6d483685cfa3a70e01774491a2ff9)
|
||||
- NumberKeyboard [f735b2](https://github.com/youzan/vant/commit/f735b24a4b71176ce5c214af69b7afc99deab85f)
|
||||
- Pagination [1cd918](https://github.com/youzan/vant/commit/1cd918395805f57a60f2cce1f5174b480cfd70f2)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Tag: 修复 color 属性不生效的问题 [4b6da2](https://github.com/youzan/vant/commit/4b6da2aab6acae95977579094bc5707345f3d3e9)
|
||||
- 修复在 TSX 中使用组件时提示类型错误的问题 [#7076](https://github.com/youzan/vant/issues/7076)
|
||||
- 修复全量引入组件时提示类型错误的问题 [#7056](https://github.com/youzan/vant/issues/7056)
|
||||
|
||||
### [v3.0.0-alpha.3](https://github.com/youzan/vant/compare/v3.0.0-alpha.2...v3.0.0-alpha.3)
|
||||
|
||||
`2020-09-01`
|
||||
|
||||
**Feature**
|
||||
|
||||
- ActionSheet: 新增 description 插槽 [#7068](https://github.com/youzan/vant/issues/7068)
|
||||
- Toast: 使用 composition api 重构 [44aaa4](https://github.com/youzan/vant/commit/44aaa471879ac79b7baee0e07c92d7a71ff7f530)
|
||||
|
||||
**Types**
|
||||
|
||||
- 修复使用 app.use 注册组件时提示类型错误的问题 [#7056](https://github.com/youzan/vant/issues/7056)
|
||||
- 修复 $toast、$dialog 类型不存在的问题 [0acbc6](https://github.com/youzan/vant/commit/0acbc6ec21588686b41f6387d2fdf642ae2c024e)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Dialog: 修复 Dialog.close 不生效的问题 [476e16](https://github.com/youzan/vant/commit/476e16ff2d22a5da3ab8b57a6c7789610b008e22)
|
||||
- Toast: 修复设置 toast.message 不生效的问题 [dac7fe](https://github.com/youzan/vant/commit/dac7feb919cfc4c3c1b8dc544431eb5547414604)
|
||||
|
||||
### [v3.0.0-alpha.2](https://github.com/youzan/vant/compare/v3.0.0-alpha.1...v3.0.0-alpha.2)
|
||||
|
||||
`2020-08-28`
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- 修复使用 `yarn add vant@next` 安装失败的问题
|
||||
|
||||
### [v3.0.0-alpha.1](https://github.com/youzan/vant/compare/v2.10.3...v3.0.0-alpha.1)
|
||||
|
||||
`2020-08-28`
|
||||
|
||||
**refactor**
|
||||
|
||||
使用 Composition API 重构以下组件:
|
||||
|
||||
- ActionBar
|
||||
- AddressList
|
||||
- Area
|
||||
- Badge
|
||||
- Button
|
||||
- Circle
|
||||
- Col
|
||||
- Collapse
|
||||
- CountDown
|
||||
- Image
|
||||
- Row
|
||||
- List
|
||||
- Loading
|
||||
- NavBar
|
||||
- NoticeBar
|
||||
- Progress
|
||||
- Rate
|
||||
- Sidebar
|
||||
- Slider
|
||||
- Steps
|
||||
- Sticky
|
||||
- Tabbar
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
- Rate: 修复控制台报 emit warning 提示的问题 [c32fba](https://github.com/youzan/vant/commit/c32fba0f1e7afa657c69c233d644c1994963a638)
|
||||
- Button: 修复 click 事件参数丢失的问题 [cea272](https://github.com/youzan/vant/commit/cea2724321daf693a1dd36dd6923c4d28585895a)
|
||||
- CellGroup: 修复 attrs 继承错误的问题 [8f978a](https://github.com/youzan/vant/commit/8f978addd49b7d2a5e6fcce0c952fcb05145ad1d)
|
||||
- Dialog: 修复部分弹窗相关属性不生效的问题 [af94c9](https://github.com/youzan/vant/commit/af94c92614b78e999e5377208e2c3c3672480210)
|
||||
- Image: 修复 loading 图标和 error 图标不展示的问题 [c720ee](https://github.com/youzan/vant/commit/c720eea83170b36e1b2f4eb8bdaff400e88bf714)
|
||||
|
||||
### v3.0.0-alpha.0
|
||||
|
||||
`2020-08-22`
|
||||
|
||||
**主要改动**
|
||||
|
||||
- 完成 Vue 3 适配
|
||||
- 调整部分组件的 v-model 和 prop.sync 用法,以适配 v-model 语法变更
|
||||
- 调整部分组件的 prop 和 event 用法
|
||||
- 重命名所有组件的 info 属性为 badge
|
||||
- 重命名所有组件的 get-container 属性为 teleport
|
||||
- 废弃 SwitchCell 组件
|
||||
- 废弃个别 API
|
||||
|
||||
**已知问题**
|
||||
|
||||
- Lazyload、Panel 和 Sku 组件暂未完成 Vue 3 适配
|
||||
|
||||
> 详细改动请参考 [从 v2 升级](https://youzan.github.io/vant/v3/#/zh-CN/migrate-from-v2)。
|
||||
@@ -0,0 +1,104 @@
|
||||
# 贡献指南
|
||||
|
||||
### 介绍
|
||||
|
||||
感谢你使用 Vant。
|
||||
|
||||
以下是关于向 Vant 提交反馈或代码的指南。在向 Vant 提交 issue 或者 PR 之前,请先花几分钟时间阅读以下文字。
|
||||
|
||||
### Issue 规范
|
||||
|
||||
- 遇到问题时,请先确认这个问题是否已经在 issue 中有记录或者已被修复
|
||||
- 提 issue 时,请用简短的语言描述遇到的问题,并添加出现问题时的环境和复现步骤
|
||||
|
||||
## 参与开发
|
||||
|
||||
### 本地开发
|
||||
|
||||
按照下面的步骤操作,即可在本地开发 Vant 组件。
|
||||
|
||||
```bash
|
||||
# 克隆仓库
|
||||
# 默认为 dev 分支,包含 Vant 3 的代码
|
||||
# 如果需要在 Vant 2 上进行更改,请基于 2.x 分支进行开发
|
||||
git clone git@github.com:youzan/vant.git
|
||||
|
||||
# 安装依赖
|
||||
cd vant && yarn
|
||||
|
||||
# 进入开发模式,浏览器访问 http://localhost:8080
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 目录结构
|
||||
|
||||
项目的主要目录结构如下所示:
|
||||
|
||||
```
|
||||
vant
|
||||
├─ docs # 文档
|
||||
├─ packages # 基础包
|
||||
├─ src # 组件源代码
|
||||
├─ test # 单测工具类
|
||||
└─ vant.config.js # 文档网站配置
|
||||
```
|
||||
|
||||
组件代码位于 src 目录下,每个组件一个独立的文件夹。
|
||||
|
||||
### 组件目录结构
|
||||
|
||||
添加新组件时,请按照下面的目录结构组织文件,并在 `vant.config.js` 中配置组件名称。
|
||||
|
||||
```
|
||||
src
|
||||
└─ button
|
||||
├─ demo # 示例代码
|
||||
├─ test # 单元测试
|
||||
├─ Component.ts # 组件
|
||||
├─ index.ts # 组件入口
|
||||
├─ index.less # 样式
|
||||
├─ var.less # 样式变量
|
||||
├─ README.md # 英文文档
|
||||
└─ README.zh-CN.md # 中文文档
|
||||
```
|
||||
|
||||
## 提交 PR
|
||||
|
||||
### Pull Request 规范
|
||||
|
||||
如果你是第一次在 GitHub 上提 Pull Request ,可以阅读下面这两篇文章来学习:
|
||||
|
||||
- [如何优雅地在 GitHub 上贡献代码](https://segmentfault.com/a/1190000000736629)
|
||||
- [第一次参与开源](https://github.com/firstcontributions/first-contributions/blob/master/translations/README.chs.md)
|
||||
|
||||
#### 规范
|
||||
|
||||
- 如果遇到问题,建议保持你的 PR 足够小。保证一个 PR 只解决一个问题或只添加一个功能
|
||||
- 当新增组件或者修改原有组件时,记得增加或者修改测试代码,保证代码的稳定
|
||||
- 在 PR 中请添加合适的描述,并关联相关的 Issue
|
||||
|
||||
### Pull Request 流程
|
||||
|
||||
1. fork 主仓库,如果已经 fork 过,请同步主仓库的最新代码
|
||||
2. 基于 fork 后仓库的 dev 分支新建一个分支,比如 `feature/button_color`
|
||||
3. 在新分支上进行开发,开发完成后,提 Pull Request 到主仓库的 dev 分支
|
||||
4. Pull Request 会在 Review 通过后被合并到主仓库
|
||||
5. 等待 Vant 发布版本,一般是每周一次
|
||||
|
||||
### 同步最新代码
|
||||
|
||||
提 Pull Request 前,请依照下面的流程同步主仓库的最新代码:
|
||||
|
||||
```bash
|
||||
# 添加主仓库到 remote,作为 fork 后仓库的上游仓库
|
||||
git remote add upstream https://github.com/youzan/vant.git
|
||||
|
||||
# 拉取主仓库最新代码
|
||||
git fetch upstream
|
||||
|
||||
# 切换至 dev 分支
|
||||
git checkout dev
|
||||
|
||||
# 合并主仓库代码
|
||||
git merge upstream/dev
|
||||
```
|
||||
@@ -0,0 +1,60 @@
|
||||
# Design Resource
|
||||
|
||||
### Intro
|
||||
|
||||
You can download Vant's design resources here.
|
||||
|
||||
## Resources
|
||||
|
||||
### Components (Sketch)
|
||||
|
||||
Contains color specifications, font specifications, and component design specifications.
|
||||
|
||||
#### Colors
|
||||
|
||||
<img src="https://img.yzcdn.cn/vant/color_202009101415.png" style="width: 80%; box-shadow: 0 1px 2px rgba(0,0,0,.2)">
|
||||
|
||||
#### Fonts
|
||||
|
||||
<img src="https://img.yzcdn.cn/vant/words_202009101415.png" style="width: 80%; box-shadow: 0 1px 2px rgba(0,0,0,.2)">
|
||||
|
||||
#### Components
|
||||
|
||||
<img src="https://img.yzcdn.cn/vant/tab_202009101415.png" style="width: 80%; box-shadow: 0 1px 2px rgba(0,0,0,.2)">
|
||||
|
||||
<a class="design-download" href="https://github.com/youzan/vant/blob/dev/docs/assets/design.sketch?raw=true">Download</a>
|
||||
|
||||
### Icons (Sketch)
|
||||
|
||||
Contains icon library resources.
|
||||
|
||||
<img src="https://img.yzcdn.cn/vant/design-icons-0321.png" style="width: 80%; box-shadow: 0 1px 2px rgba(0,0,0,.2)">
|
||||
|
||||
<a class="design-download" href="https://github.com/youzan/vant/blob/dev/packages/vant-icons/assets/icons.sketch?raw=true">Download</a>
|
||||
|
||||
### Axure
|
||||
|
||||
<img src="https://img.yzcdn.cn/vant/vant-axure-0905.png" style="width: 80%; box-shadow: 0 1px 2px rgba(0,0,0,.2)">
|
||||
|
||||
<a class="design-download" href="https://b.yzcdn.cn/vant/vant-axure-20200905.zip">Download</a>
|
||||
|
||||
<style>
|
||||
a.design-download {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
color: #fff !important;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
background-color: #38f;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
a.design-download:hover {
|
||||
color: #fff;
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
a.design-download:active {
|
||||
opacity: .7;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,66 @@
|
||||
# 设计资源
|
||||
|
||||
### 介绍
|
||||
|
||||
Vant 是基于有赞 [Zan Design System](https://design.youzan.com/) 视觉规范实现的组件库,在这里可以下载 Vant 的设计资源。
|
||||
|
||||
## 设计稿
|
||||
|
||||
### 组件设计稿(Sketch)
|
||||
|
||||
包含 Sketch 格式的色彩规范、字体规范、组件设计规范。
|
||||
|
||||
#### 色彩规范
|
||||
|
||||
<img src="https://img.yzcdn.cn/vant/color_202009101415.png" style="width: 80%; box-shadow: 0 1px 2px rgba(0,0,0,.2)">
|
||||
|
||||
#### 字体规范
|
||||
|
||||
<img src="https://img.yzcdn.cn/vant/words_202009101415.png" style="width: 80%; box-shadow: 0 1px 2px rgba(0,0,0,.2)">
|
||||
|
||||
#### 组件规范
|
||||
|
||||
<img src="https://img.yzcdn.cn/vant/tab_202009101415.png" style="width: 80%; box-shadow: 0 1px 2px rgba(0,0,0,.2)">
|
||||
|
||||
<a class="design-download" href="https://github.com/youzan/vant/blob/dev/docs/assets/design.sketch?raw=true">下载</a>
|
||||
|
||||
### 图标设计稿(Sketch)
|
||||
|
||||
包含 Sketch 格式的图标库资源。
|
||||
|
||||
<img src="https://img.yzcdn.cn/vant/design-icons-0321.png" style="width: 80%; box-shadow: 0 1px 2px rgba(0,0,0,.2)">
|
||||
|
||||
<a class="design-download" href="https://github.com/youzan/vant/blob/dev/packages/vant-icons/assets/icons.sketch?raw=true">下载</a>
|
||||
|
||||
#### 在线资源
|
||||
|
||||
Vant 的所有图标都托管在 **iconfont.cn** 上,点此查看:[Vant 图标库](https://www.iconfont.cn/collections/detail?spm=a313x.7781069.1998910419.d9df05512&cid=31945)。
|
||||
|
||||
### Axure 元件库
|
||||
|
||||
Axure 元件库,由社区的 [@axure-tczy](https://github.com/axure-tczy) 同学贡献。
|
||||
|
||||
<img src="https://img.yzcdn.cn/vant/vant-axure-0905.png" style="width: 80%; box-shadow: 0 1px 2px rgba(0,0,0,.2)">
|
||||
|
||||
<a class="design-download" href="https://b.yzcdn.cn/vant/vant-axure-20200905.zip">下载</a>
|
||||
|
||||
<style>
|
||||
a.design-download {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
color: #fff !important;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
background-color: #38f;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
a.design-download:hover {
|
||||
color: #fff;
|
||||
opacity: .9;
|
||||
}
|
||||
|
||||
a.design-download:active {
|
||||
opacity: .7;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,63 @@
|
||||
<div class="card">
|
||||
<div class="van-doc-intro">
|
||||
<img class="van-doc-intro__logo" style="width: 120px; height: 120px;" src="https://img.yzcdn.cn/vant/logo.png">
|
||||
<h2 style="margin: 0; font-size: 36px; line-height: 60px;">Vant</h2>
|
||||
<p>Mobile UI Components built on Vue</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
### Features
|
||||
|
||||
- 65+ Reusable components
|
||||
- 1kb Component average size (min+gzip)
|
||||
- 90%+ Unit test coverage
|
||||
- Extensive documentation and demos
|
||||
- Support Vue 2 & Vue 3
|
||||
- Support Tree Shaking
|
||||
- Support Custom Theme
|
||||
- Support i18n
|
||||
- Support TS
|
||||
- Support SSR
|
||||
|
||||
### Quickstart
|
||||
|
||||
See in [Quickstart](#/en-US/quickstart).
|
||||
|
||||
### Contribution
|
||||
|
||||
Please make sure to read the [Contributing Guide](https://github.com/youzan/vant/blob/dev/.github/CONTRIBUTING.md) before making a pull request.
|
||||
|
||||
### Browser Support
|
||||
|
||||
Vant 2 supports modern browsers and Android >= 4.0、iOS >= 8.0.
|
||||
|
||||
Vant 3 supports modern browsers and Chrome >= 51、iOS >= 10.0 (same as Vue 3).
|
||||
|
||||
### Official Ecosystem
|
||||
|
||||
| Project | Description |
|
||||
| --- | --- |
|
||||
| [vant-weapp](https://github.com/youzan/vant-weapp) | WeChat MiniProgram UI |
|
||||
| [vant-demo](https://github.com/youzan/vant-demo) | Collection of Vant demos |
|
||||
| [vant-cli](https://github.com/youzan/vant/tree/dev/packages/vant-cli) | Scaffold for UI library |
|
||||
| [vant-icons](https://github.com/youzan/vant/tree/dev/packages/vant-icons) | Vant icons |
|
||||
| [vant-touch-emulator](https://github.com/youzan/vant/tree/dev/packages/vant-touch-emulator) | Using vant in desktop browsers |
|
||||
|
||||
### Community Ecosystem
|
||||
|
||||
| Project | Description |
|
||||
| --- | --- |
|
||||
| [3lang3/react-vant](https://github.com/3lang3/react-vant) | React mobile UI Components base on Vant |
|
||||
| [mxdi9i7/vant-react](https://github.com/mxdi9i7/vant-react) | Mobile UI Components built on React and TS, inspired by Vant |
|
||||
| [vant-aliapp](https://github.com/ant-move/Vant-Aliapp) | Alipay MiniProgram UI |
|
||||
| [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro |
|
||||
|
||||
### Links
|
||||
|
||||
- [Feedback](https://github.com/youzan/vant/issues)
|
||||
- [Changelog](#/en-US/changelog)
|
||||
- [Gitter](https://gitter.im/vant-contrib/discuss?utm_source=share-link&utm_medium=link&utm_campaign=share-link)
|
||||
|
||||
### LICENSE
|
||||
|
||||
[MIT](https://zh.wikipedia.org/wiki/MIT%E8%A8%B1%E5%8F%AF%E8%AD%89)
|
||||
@@ -0,0 +1,80 @@
|
||||
<div class="card">
|
||||
<div class="van-doc-intro">
|
||||
<img class="van-doc-intro__logo" style="width: 120px; height: 120px;" src="https://img.yzcdn.cn/vant/logo.png">
|
||||
<h2 style="margin: 0; font-size: 36px; line-height: 60px;">Vant</h2>
|
||||
<p>轻量、可靠的移动端 Vue 组件库</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
### 介绍
|
||||
|
||||
Vant 是**有赞前端团队**开源的移动端组件库,于 2017 年开源,已持续维护 4 年时间。Vant 对内承载了有赞所有核心业务,对外服务十多万开发者,是业界主流的移动端组件库之一。 <br><br>
|
||||
|
||||
目前 Vant 官方提供了 [Vue 2 版本](https://vant-contrib.gitee.io/vant)、[Vue 3 版本](https://vant-contrib.gitee.io/vant/v3)和[微信小程序版本](http://vant-contrib.gitee.io/vant-weapp),并由社区团队维护 [React 版本](https://github.com/mxdi9i7/vant-react)和[支付宝小程序版本](https://github.com/ant-move/Vant-Aliapp)。
|
||||
|
||||
### 版本提示
|
||||
|
||||
你当前浏览的是 **Vant 3.x 版本** 的文档,适用于 Vue 3 开发。如果你在使用 Vue 2,请浏览 [Vant 2 文档](https://vant-contrib.gitee.io/vant)。
|
||||
|
||||
### 特性
|
||||
|
||||
- 提供 60 多个高质量组件,覆盖移动端各类场景
|
||||
- 性能极佳,组件平均体积不到 1kb(min+gzip)
|
||||
- 单元测试覆盖率 90%+,提供稳定性保障
|
||||
- 完善的中英文文档和示例
|
||||
- 支持 Vue 2 & Vue 3
|
||||
- 支持按需引入
|
||||
- 支持主题定制
|
||||
- 支持国际化
|
||||
- 支持 TypeScript
|
||||
- 支持 SSR
|
||||
|
||||
### 快速上手
|
||||
|
||||
请阅读[快速上手](#/zh-CN/quickstart)章节,通过该章节你可以了解到 Vant 的安装方法和基本使用姿势。
|
||||
|
||||
### 贡献代码
|
||||
|
||||
贡献代码请阅读我们的[贡献指南](#/zh-CN/contribution)。
|
||||
|
||||
使用过程中发现任何问题都可以提 [Issue](https://github.com/youzan/vant/issues) 给我们,当然,我们也非常欢迎你给我们发 [PR](https://github.com/youzan/vant/pulls)。
|
||||
|
||||
### 浏览器支持
|
||||
|
||||
Vant 2 支持现代浏览器以及 Android >= 4.0、iOS >= 8.0。
|
||||
|
||||
Vant 3 支持现代浏览器以及 Chrome >= 51、iOS >= 10.0(与 Vue 3 一致)。
|
||||
|
||||
### 官方生态
|
||||
|
||||
由 Vant 官方团队维护的项目如下:
|
||||
|
||||
| 项目 | 描述 |
|
||||
| --- | --- |
|
||||
| [vant-weapp](https://github.com/youzan/vant-weapp) | Vant 微信小程序版 |
|
||||
| [vant-demo](https://github.com/youzan/vant-demo) | Vant 官方示例合集 |
|
||||
| [vant-cli](https://github.com/youzan/vant/tree/dev/packages/vant-cli) | 开箱即用的组件库搭建工具 |
|
||||
| [vant-icons](https://github.com/youzan/vant/tree/dev/packages/vant-icons) | Vant 图标库 |
|
||||
| [vant-touch-emulator](https://github.com/youzan/vant/tree/dev/packages/vant-touch-emulator) | 在桌面端使用 Vant 的辅助库 |
|
||||
|
||||
### 社区生态
|
||||
|
||||
由社区维护的项目如下,欢迎补充:
|
||||
|
||||
| 项目 | 描述 |
|
||||
| --- | --- |
|
||||
| [3lang3/react-vant](https://github.com/3lang3/react-vant) | 参照 Vant 打造的 React 移动端组件库 |
|
||||
| [mxdi9i7/vant-react](https://github.com/mxdi9i7/vant-react) | 基于 React 和 TS 构建的移动端组件库 |
|
||||
| [vant-aliapp](https://github.com/ant-move/Vant-Aliapp) | Vant 支付宝小程序版 |
|
||||
| [taroify](https://gitee.com/mallfoundry/taroify) | Vant Taro 版 |
|
||||
|
||||
### 链接
|
||||
|
||||
- [意见反馈](https://github.com/youzan/vant/issues)
|
||||
- [更新日志](#/zh-CN/changelog)
|
||||
- [码云镜像](https://gitee.com/vant-contrib/vant)
|
||||
- [Gitter 讨论组](https://gitter.im/vant-contrib/discuss?utm_source=share-link&utm_medium=link&utm_campaign=share-link)
|
||||
|
||||
### 开源协议
|
||||
|
||||
本项目基于 [MIT](https://zh.wikipedia.org/wiki/MIT%E8%A8%B1%E5%8F%AF%E8%AD%89) 协议,请自由地享受和参与开源
|
||||
@@ -0,0 +1,241 @@
|
||||
# 从 v2 升级
|
||||
|
||||
### 介绍
|
||||
|
||||
本文档提供了从 Vant 2 到 Vant 3 的升级指南。
|
||||
|
||||
### 升级步骤
|
||||
|
||||
#### 1. 升级 Vue 3
|
||||
|
||||
Vant 3 是基于 Vue 3 开发的,在使用 Vant 3 前,请将项目中的 Vue 升级到 3.0 以上版本。
|
||||
|
||||
#### 2. 处理不兼容更新
|
||||
|
||||
Vant 2 到 Vant 3 存在一些不兼容更新,请仔细阅读下方的不兼容更新内容,并依次处理。
|
||||
|
||||
## 不兼容更新
|
||||
|
||||
### 组件命名调整
|
||||
|
||||
GoodsAction 商品导航组件重命名为 **ActionBar 行动栏**。
|
||||
|
||||
```html
|
||||
<!-- Vant 2 -->
|
||||
<van-goods-action>
|
||||
<van-goods-action-icon text="图标" />
|
||||
<van-goods-action-button text="按钮" />
|
||||
</van-goods-action>
|
||||
|
||||
<!-- Vant 3 -->
|
||||
<van-action-bar>
|
||||
<van-action-bar-icon text="图标" />
|
||||
<van-action-bar-button text="按钮" />
|
||||
</van-action-bar>
|
||||
```
|
||||
|
||||
### 废弃组件
|
||||
|
||||
移除 SwitchCell 组件,可以直接使用 Cell 和 Switch 组件代替。
|
||||
|
||||
```html
|
||||
<!-- Vant 2 -->
|
||||
<van-switch-cell title="标题" v-model="checked" />
|
||||
|
||||
<!-- Vant 3 -->
|
||||
<van-cell center title="标题">
|
||||
<template #right-icon>
|
||||
<van-switch v-model="checked" size="24" />
|
||||
</template>
|
||||
</van-cell>
|
||||
```
|
||||
|
||||
### 弹窗型组件 v-model 变更
|
||||
|
||||
为了适配 Vue 3 的 v-model API 用法变更,所有提供 v-model 属性的组件在用法上有一定调整。以下弹窗类组件的 `v-model` 被重命名为 `v-model:show`:
|
||||
|
||||
- ActionSheet
|
||||
- Calendar
|
||||
- Dialog
|
||||
- ImagePreview
|
||||
- Notify
|
||||
- Popover
|
||||
- Popup
|
||||
- ShareSheet
|
||||
|
||||
```html
|
||||
<!-- Vant 2 -->
|
||||
<van-popup v-model="show" />
|
||||
|
||||
<!-- Vant 3 -->
|
||||
<van-popup v-model:show="show" />
|
||||
```
|
||||
|
||||
### 表单型组件 v-model 内部值变更
|
||||
|
||||
以下表单型组件 v-model 对应的 prop 重命名为 `modelValue`,event 重命名为 `update:modelValue`:
|
||||
|
||||
- Checkbox
|
||||
- CheckboxGroup
|
||||
- DatetimePicker
|
||||
- DropdownItem
|
||||
- Field
|
||||
- Radio
|
||||
- RadioGroup
|
||||
- Search
|
||||
- Stepper
|
||||
- Switch
|
||||
- Sidebar
|
||||
- Uploader
|
||||
|
||||
```html
|
||||
<!-- Vant 2 -->
|
||||
<van-field :value="value" @input="onInput" />
|
||||
|
||||
<!-- Vant 3 -->
|
||||
<van-field :model-value="value" @update:model-value="onInput" />
|
||||
```
|
||||
|
||||
### 其他 v-model 调整
|
||||
|
||||
- Circle: `v-model` 重命名为 `v-model:currentRate`
|
||||
- CouponList: `v-model` 重命名为 `v-model:code`
|
||||
- List: `v-model` 重命名为 `v-model:loading`,`error.sync` 重命名为 `v-model:error`
|
||||
- Tabs: `v-model` 重命名为 `v-model:active`
|
||||
- TreeSelect: `active-id.sync` 重命名为 `v-model:active-id`
|
||||
- TreeSelect: `main-active-index.sync` 重命名为 `v-model:main-active-index`
|
||||
|
||||
### 徽标属性命名调整
|
||||
|
||||
在之前的版本中,我们通过 info 属性来展示图标右上角的徽标信息,为了更符合社区的命名习惯,我们将这个属性重命名为 badge,影响以下组件:
|
||||
|
||||
- Tab
|
||||
- Icon
|
||||
- GridItem
|
||||
- TreeSelect
|
||||
- TabbarItem
|
||||
- SidebarItem
|
||||
- GoodsActionIcon
|
||||
|
||||
同时内部使用的 Info 组件也会重命名为 Badge。
|
||||
|
||||
```html
|
||||
<!-- Vant 2 -->
|
||||
<van-icon info="5" />
|
||||
|
||||
<!-- Vant 3 -->
|
||||
<van-icon badge="5" />
|
||||
```
|
||||
|
||||
### 重命名 get-container 属性
|
||||
|
||||
Vue 3.0 中增加了 `Teleport` 组件,提供将组件渲染到任意 DOM 位置的能力,Vant 2 也通过 `get-container` 属性提供了类似的能力。为了与官方的 API 保持一致,Vant 中的 `get-container` 属性将重命名为 `teleport`。
|
||||
|
||||
```html
|
||||
<!-- Vant 2 -->
|
||||
<template>
|
||||
<van-popup get-container="body" />
|
||||
<van-popup :get-container="getContainer" />
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
getContainer() {
|
||||
return document.querySelector('#container');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Vant 3 -->
|
||||
<template>
|
||||
<van-popup teleport="body" />
|
||||
<van-popup :teleport="container" />
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
beforeCreate() {
|
||||
this.container = document.querySelector('#container');
|
||||
},
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
### API 调整
|
||||
|
||||
#### Area
|
||||
|
||||
- `change` 事件参数不再传入组件实例
|
||||
|
||||
#### Button
|
||||
|
||||
- 蓝色按钮对应的类型由 `info` 调整为 `primary`
|
||||
- 绿色按钮对应的类型由 `primary` 调整为 `success`
|
||||
- `native-type` 的默认值由 `submit` 调整为 `button`
|
||||
|
||||
#### Checkbox
|
||||
|
||||
- 在 Cell 内部使用时,现在需要手动添加 `@click.stop` 来阻止事件冒泡
|
||||
|
||||
#### Dialog
|
||||
|
||||
- 默认关闭 `allow-html` 属性
|
||||
- `before-close` 属性用法调整,不再传入 done 函数,而是通过返回 Promise 来控制
|
||||
|
||||
#### DatetimePicker
|
||||
|
||||
- `change` 事件参数不再传入组件实例
|
||||
|
||||
#### ImagePreview
|
||||
|
||||
- 移除 `async-close` 属性,可以使用新增的 `before-close` 属性代替
|
||||
|
||||
#### Picker
|
||||
|
||||
- `change` 事件参数不再传入组件实例
|
||||
- 默认关闭 `allow-html` 属性
|
||||
- 默认开启 `show-toolbar` 属性
|
||||
- 级联选择下,`confirm`、`change` 事件返回的回调参数将包含为完整的选项对象。
|
||||
|
||||
#### Popover
|
||||
|
||||
- `trigger` 属性的默认值调整为 `click`
|
||||
|
||||
#### Stepper
|
||||
|
||||
- `async-change` 属性重命名为 `before-change`,并调整使用方法
|
||||
|
||||
#### SwipeCell
|
||||
|
||||
- `open` 事件的 `detail` 参数重命名为 `name`
|
||||
- `on-close` 属性重命名为 `before-close`,并调整参数结构
|
||||
- `before-close` 属性不再传入组件实例
|
||||
|
||||
#### Toast
|
||||
|
||||
- `mask` 属性重命名为 `overlay`
|
||||
|
||||
#### TreeSelect
|
||||
|
||||
- `navclick` 事件重命名为 `click-nav`
|
||||
- `itemclick` 事件重命名为 `click-item`
|
||||
|
||||
### 注册全局方法
|
||||
|
||||
Vant 2 中默认提供了 `$toast`、`$dialog` 等全局方法,但 Vue 3.0 不再支持直接在 Vue 的原型链上挂载方法,因此从 Vant 3.0 开始,使用全局方法前必须先通过 `app.use` 将组件注册到对应的 app 上。
|
||||
|
||||
```js
|
||||
import { Toast, Dialog, Notify } from 'vant';
|
||||
|
||||
// 将 Toast 等组件注册到 app 上
|
||||
app.use(Toast);
|
||||
app.use(Dialog);
|
||||
app.use(Notify);
|
||||
|
||||
// app 内的子组件可以直接调用 $toast 等方法
|
||||
export default {
|
||||
mounted() {
|
||||
this.$toast('提示文案');
|
||||
},
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,160 @@
|
||||
# Quickstart
|
||||
|
||||
## Install
|
||||
|
||||
### npm
|
||||
|
||||
```bash
|
||||
# Install Vant 2 for Vue 2 project
|
||||
npm i vant -S
|
||||
|
||||
# Install Vant 3 for Vue 3 project
|
||||
npm i vant@next -S
|
||||
```
|
||||
|
||||
### CDN
|
||||
|
||||
The easiest way to use Vant is to include a CDN link in the html file, after which you can access all components via the global variable `vant`.
|
||||
|
||||
```html
|
||||
<!-- import style -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/vant@next/lib/index.css"
|
||||
/>
|
||||
|
||||
<!-- import script -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@next"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vant@next/lib/vant.min.js"></script>
|
||||
|
||||
<script>
|
||||
// Render the Button component
|
||||
const app = Vue.createApp({
|
||||
template: `<van-button>Button</van-button>`,
|
||||
});
|
||||
app.use(vant);
|
||||
|
||||
// Register Lazyload directive
|
||||
app.use(vant.Lazyload);
|
||||
|
||||
// Call function component
|
||||
vant.Toast('Message');
|
||||
|
||||
app.mount('#app');
|
||||
</script>
|
||||
```
|
||||
|
||||
You can use Vant through these free CDN services:
|
||||
|
||||
- [jsdelivr](https://www.jsdelivr.com/package/npm/vant)
|
||||
- [cdnjs](https://cdnjs.com/libraries/vant)
|
||||
- [unpkg](https://unpkg.com/)
|
||||
|
||||
### CLI
|
||||
|
||||
We recommend to use [Vue Cli](https://cli.vuejs.org/) to create a new project.
|
||||
|
||||
```bash
|
||||
# Install Vue Cli
|
||||
npm install -g @vue/cli
|
||||
|
||||
# Create a project
|
||||
vue create hello-world
|
||||
|
||||
# Open GUI
|
||||
vue ui
|
||||
```
|
||||
|
||||

|
||||
|
||||
In the GUI, click on 'Dependencies' -> `Install Dependencies` and add `vant` to the dependencies.
|
||||
|
||||
## Usage
|
||||
|
||||
### 1. Import on demand
|
||||
|
||||
Use [babel-plugin-import](https://github.com/ant-design/babel-plugin-import) to import components on demand.
|
||||
|
||||
```bash
|
||||
# Install plugin
|
||||
npm i babel-plugin-import -D
|
||||
```
|
||||
|
||||
Set babel config in .babelrc or babel.config.js:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": [
|
||||
[
|
||||
"import",
|
||||
{
|
||||
"libraryName": "vant",
|
||||
"libraryDirectory": "es",
|
||||
"style": true
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Then you can import components from vant:
|
||||
|
||||
```js
|
||||
// Input
|
||||
import { Button } from 'vant';
|
||||
|
||||
// Output
|
||||
import Button from 'vant/es/button';
|
||||
import 'vant/es/button/style';
|
||||
```
|
||||
|
||||
> If you are using TypeScript,please use [ts-import-plugin](https://github.com/Brooooooklyn/ts-import-plugin) instead.
|
||||
|
||||
### 2. Vite Plugin
|
||||
|
||||
If you are using Vite, please use [vite-plugin-style-import](https://github.com/anncwb/vite-plugin-style-import).
|
||||
|
||||
```bash
|
||||
npm i vite-plugin-style-import -D
|
||||
```
|
||||
|
||||
```js
|
||||
// vite.config.js
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import styleImport from 'vite-plugin-style-import';
|
||||
|
||||
export default {
|
||||
plugins: [
|
||||
vue(),
|
||||
styleImport({
|
||||
libs: [
|
||||
{
|
||||
libraryName: 'vant',
|
||||
esModule: true,
|
||||
resolveStyle: (name) => `vant/es/${name}/style`,
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### 3. Manually import
|
||||
|
||||
```js
|
||||
import Button from 'vant/es/button';
|
||||
import 'vant/es/button/style';
|
||||
```
|
||||
|
||||
### 4. Import all components
|
||||
|
||||
```js
|
||||
import { createApp } from 'vue';
|
||||
import Vant from 'vant';
|
||||
import 'vant/lib/index.css';
|
||||
|
||||
const app = createApp();
|
||||
app.use(Vant);
|
||||
```
|
||||
|
||||
> If you configured babel-plugin-import, you won't be allowed to import all components.
|
||||
@@ -0,0 +1,240 @@
|
||||
# 快速上手
|
||||
|
||||
### 介绍
|
||||
|
||||
通过本章节你可以了解到 Vant 的安装方法和基本使用姿势。
|
||||
|
||||
## 安装
|
||||
|
||||
### 通过 npm 安装
|
||||
|
||||
在现有项目中使用 Vant 时,可以通过 `npm` 或 `yarn` 进行安装:
|
||||
|
||||
```bash
|
||||
# Vue 2 项目,安装 Vant 2:
|
||||
npm i vant -S
|
||||
|
||||
# Vue 3 项目,安装 Vant 3:
|
||||
npm i vant@next -S
|
||||
```
|
||||
|
||||
### 通过 CDN 安装
|
||||
|
||||
使用 Vant 最简单的方法是直接在 html 文件中引入 CDN 链接,之后你可以通过全局变量 `vant` 访问到所有组件。
|
||||
|
||||
```html
|
||||
<!-- 引入样式文件 -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/vant@next/lib/index.css"
|
||||
/>
|
||||
|
||||
<!-- 引入 Vue 和 Vant 的 JS 文件 -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@next"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vant@next/lib/vant.min.js"></script>
|
||||
|
||||
<script>
|
||||
// 在 #app 标签下渲染一个按钮组件
|
||||
const app = Vue.createApp({
|
||||
template: `<van-button>按钮</van-button>`,
|
||||
});
|
||||
app.use(vant);
|
||||
|
||||
// 通过 CDN 引入时不会自动注册 Lazyload 组件
|
||||
// 可以通过下面的方式手动注册
|
||||
app.use(vant.Lazyload);
|
||||
|
||||
// 调用函数组件,弹出一个 Toast
|
||||
vant.Toast('提示');
|
||||
|
||||
app.mount('#app');
|
||||
</script>
|
||||
```
|
||||
|
||||
你可以通过以下免费 CDN 服务来使用 Vant:
|
||||
|
||||
- [jsdelivr](https://www.jsdelivr.com/package/npm/vant)
|
||||
- [cdnjs](https://cdnjs.com/libraries/vant)
|
||||
- [unpkg](https://unpkg.com/)
|
||||
|
||||
### 通过脚手架安装
|
||||
|
||||
在新项目中使用 Vant 时,推荐使用 Vue 官方提供的脚手架 [Vue Cli](https://cli.vuejs.org/zh/) 创建项目并安装 Vant。
|
||||
|
||||
```bash
|
||||
# 安装 Vue Cli
|
||||
npm install -g @vue/cli
|
||||
|
||||
# 创建一个项目
|
||||
vue create hello-world
|
||||
|
||||
# 创建完成后,可以通过命令打开图形化界面,如下图所示
|
||||
vue ui
|
||||
```
|
||||
|
||||

|
||||
|
||||
在图形化界面中,点击 `依赖` -> `安装依赖`,然后将 `vant` 添加到依赖中即可。
|
||||
|
||||
## 示例
|
||||
|
||||
### 示例工程
|
||||
|
||||
我们提供了丰富的[示例工程](https://github.com/youzan/vant-demo),通过示例工程你可以了解如下内容:
|
||||
|
||||
- 基于 Vue Cli 和 Vant 搭建应用
|
||||
- 基于 Nuxt 和 Vant 搭建应用
|
||||
- 配置按需引入组件
|
||||
- 配置基于 Rem 的适配方案
|
||||
- 配置基于 Viewport 的适配方案
|
||||
- 配置基于 TypeScript 的工程
|
||||
- 配置自定义主题色方案
|
||||
|
||||
## 引入组件
|
||||
|
||||
### 方式一. 通过 babel 插件按需引入组件
|
||||
|
||||
[babel-plugin-import](https://github.com/ant-design/babel-plugin-import) 是一款 babel 插件,它会在编译过程中将 import 语句自动转换为按需引入的方式。
|
||||
|
||||
```bash
|
||||
# 安装插件
|
||||
npm i babel-plugin-import -D
|
||||
```
|
||||
|
||||
在.babelrc 或 babel.config.js 中添加配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": [
|
||||
[
|
||||
"import",
|
||||
{
|
||||
"libraryName": "vant",
|
||||
"libraryDirectory": "es",
|
||||
"style": true
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
接着你可以在代码中直接引入 Vant 组件,插件会自动将代码转化为按需引入的形式。
|
||||
|
||||
```js
|
||||
// 原始代码
|
||||
import { Button } from 'vant';
|
||||
|
||||
// 编译后代码
|
||||
import Button from 'vant/es/button';
|
||||
import 'vant/es/button/style';
|
||||
```
|
||||
|
||||
> 如果你在使用 TypeScript,可以使用 [ts-import-plugin](https://github.com/Brooooooklyn/ts-import-plugin) 实现按需引入。
|
||||
|
||||
### 方式二. 在 Vite 项目中按需引入组件
|
||||
|
||||
对于 vite 项目,可以使用 [vite-plugin-style-import](https://github.com/anncwb/vite-plugin-style-import) 实现按需引入, 原理和 `babel-plugin-import` 类似。
|
||||
|
||||
```bash
|
||||
# 安装插件
|
||||
npm i vite-plugin-style-import -D
|
||||
```
|
||||
|
||||
```js
|
||||
// vite.config.js
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import styleImport from 'vite-plugin-style-import';
|
||||
|
||||
export default {
|
||||
plugins: [
|
||||
vue(),
|
||||
styleImport({
|
||||
libs: [
|
||||
{
|
||||
libraryName: 'vant',
|
||||
esModule: true,
|
||||
resolveStyle: (name) => `vant/es/${name}/style`,
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### 方式三. 手动按需引入组件
|
||||
|
||||
在不使用插件的情况下,可以手动引入需要使用的组件和样式。
|
||||
|
||||
```js
|
||||
// 引入组件
|
||||
import Button from 'vant/es/button';
|
||||
// 引入组件对应的样式,若组件没有样式文件,则无须引入
|
||||
import 'vant/es/button/style';
|
||||
```
|
||||
|
||||
### 方式四. 导入所有组件
|
||||
|
||||
Vant 支持一次性导入所有组件,引入所有组件会增加代码包体积,因此不推荐这种做法。
|
||||
|
||||
```js
|
||||
import { createApp } from 'vue';
|
||||
import Vant from 'vant';
|
||||
import 'vant/lib/index.css';
|
||||
|
||||
const app = createApp();
|
||||
app.use(Vant);
|
||||
```
|
||||
|
||||
> Tips: 配置按需引入后,将不允许直接导入所有组件。
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 如何自定义 Vant 组件的样式?
|
||||
|
||||
#### 1. 主题定制
|
||||
|
||||
Vant 基于 CSS 变量提供了主题定制的能力,可以对组件样式进行统一修改,详见 [ConfigProvider 全局配置](#/zh-CN/config-provider) 组件。
|
||||
|
||||
#### 2. 覆盖默认样式
|
||||
|
||||
如果主题定制不能满足你的需求,也可以通过**自定义样式类**来覆盖默认样式,参考下面的示例:
|
||||
|
||||
```html
|
||||
<template>
|
||||
<van-button class="my-button">按钮</van-button>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
/** 覆盖 Button 最外层元素的样式 */
|
||||
.my-button {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
/** 覆盖 Button 内部子元素的样式 */
|
||||
.my-button .van-button__text {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### 在 HTML 中无法正确渲染组件?
|
||||
|
||||
在 HTML 中使用 Vant 组件时,你可能会碰到部分示例代码无法正确渲染的情况,比如下面的用法:
|
||||
|
||||
```html
|
||||
<van-cell-group>
|
||||
<van-cell title="单元格" value="内容" />
|
||||
<van-cell title="单元格" value="内容" />
|
||||
</van-cell-group>
|
||||
```
|
||||
|
||||
这是因为 HTML 并不支持自闭合的自定义元素,也就是说 `<van-cell />` 这样的语法是不被识别的,使用完整的闭合标签可以避免这个问题:
|
||||
|
||||
```html
|
||||
<van-cell-group>
|
||||
<van-cell title="单元格" value="内容"></van-cell>
|
||||
<van-cell title="单元格" value="内容"></van-cell>
|
||||
</van-cell-group>
|
||||
```
|
||||
|
||||
在单文件组件、字符串模板和 JSX 中可以使用自闭合的自定义元素,因此不会出现这个问题。
|
||||
@@ -0,0 +1,204 @@
|
||||
# 风格指南
|
||||
|
||||
### 介绍
|
||||
|
||||
在参与 Vant 开发时,请遵守约定的单文件组件风格指南,指南内容节选自 [Vue 官方风格指南](https://v3.cn.vuejs.org/style-guide/)。
|
||||
|
||||
### 组件数据
|
||||
|
||||
组件的 data 必须是一个函数。
|
||||
|
||||
```js
|
||||
// bad
|
||||
export default {
|
||||
data: {
|
||||
foo: 'bar',
|
||||
},
|
||||
};
|
||||
|
||||
// good
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
foo: 'bar',
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 单文件组件文件名称
|
||||
|
||||
单文件组件的文件名应该要么始终是单词大写开头 (PascalCase),要么始终是横线连接 (kebab-case)。
|
||||
|
||||
```
|
||||
// bad
|
||||
mycomponent.vue
|
||||
myComponent.vue
|
||||
|
||||
// good
|
||||
my-component.vue
|
||||
MyComponent.vue
|
||||
```
|
||||
|
||||
### 紧密耦合的组件名
|
||||
|
||||
和父组件紧密耦合的子组件应该以父组件名作为前缀命名。
|
||||
|
||||
```
|
||||
// bad
|
||||
components/
|
||||
|- TodoList.vue
|
||||
|- TodoItem.vue
|
||||
└─ TodoButton.vue
|
||||
|
||||
// good
|
||||
components/
|
||||
|- TodoList.vue
|
||||
|- TodoListItem.vue
|
||||
└─ TodoListItemButton.vue
|
||||
```
|
||||
|
||||
### 自闭合组件
|
||||
|
||||
在单文件组件中没有内容的组件应该是自闭合的。
|
||||
|
||||
```html
|
||||
<!-- bad -->
|
||||
<my-component></my-component>
|
||||
|
||||
<!-- good -->
|
||||
<my-component />
|
||||
```
|
||||
|
||||
### Prop 名大小写
|
||||
|
||||
在声明 prop 的时候,其命名应该始终使用 camelCase,而在模板中应该始终使用 kebab-case。
|
||||
|
||||
```js
|
||||
// bad
|
||||
export default {
|
||||
props: {
|
||||
'greeting-text': String,
|
||||
},
|
||||
};
|
||||
|
||||
// good
|
||||
export default {
|
||||
props: {
|
||||
greetingText: String,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- bad -->
|
||||
<welcome-message greetingText="hi" />
|
||||
|
||||
<!-- good -->
|
||||
<welcome-message greeting-text="hi" />
|
||||
```
|
||||
|
||||
### 指令缩写
|
||||
|
||||
指令缩写,用 `:` 表示 `v-bind:` ,用 `@` 表示 `v-on:`
|
||||
|
||||
```html
|
||||
<!-- bad -->
|
||||
<input v-bind:value="value" v-on:input="onInput" />
|
||||
|
||||
<!-- good -->
|
||||
<input :value="value" @input="onInput" />
|
||||
```
|
||||
|
||||
### Props 顺序
|
||||
|
||||
标签的 Props 应该有统一的顺序,依次为指令、属性和事件。
|
||||
|
||||
```html
|
||||
<my-component
|
||||
v-if="if"
|
||||
v-show="show"
|
||||
v-model="value"
|
||||
ref="ref"
|
||||
:key="key"
|
||||
:text="text"
|
||||
@input="onInput"
|
||||
@change="onChange"
|
||||
/>
|
||||
```
|
||||
|
||||
### 组件选项的顺序
|
||||
|
||||
组件选项应该有统一的顺序。
|
||||
|
||||
```js
|
||||
export default {
|
||||
name: '',
|
||||
|
||||
components: {},
|
||||
|
||||
props: {},
|
||||
|
||||
emits: [],
|
||||
|
||||
setup() {},
|
||||
|
||||
data() {},
|
||||
|
||||
computed: {},
|
||||
|
||||
watch: {},
|
||||
|
||||
created() {},
|
||||
|
||||
mounted() {},
|
||||
|
||||
unmounted() {},
|
||||
|
||||
methods: {},
|
||||
};
|
||||
```
|
||||
|
||||
### 组件选项中的空行
|
||||
|
||||
组件选项较多时,建议在属性之间添加空行。
|
||||
|
||||
```js
|
||||
export default {
|
||||
computed: {
|
||||
formattedValue() {
|
||||
// ...
|
||||
},
|
||||
|
||||
styles() {
|
||||
// ...
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onInput() {
|
||||
// ...
|
||||
},
|
||||
|
||||
onChange() {
|
||||
// ...
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 单文件组件顶级标签的顺序
|
||||
|
||||
单文件组件应该总是让顶级标签的顺序保持一致,且标签之间留有空行。
|
||||
|
||||
```html
|
||||
<template> ... </template>
|
||||
|
||||
<script>
|
||||
/* ... */
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* ... */
|
||||
</style>
|
||||
```
|
||||
@@ -0,0 +1,215 @@
|
||||
# Custom Theme
|
||||
|
||||
### Deprecated
|
||||
|
||||
This document is deprecated. Vant provides a more convenient [ConfigProvider](#/en-US/config-provider) component for theme configuration. Less variables **will be removed in the next major version**.
|
||||
|
||||
### Intro
|
||||
|
||||
Vant use [Less](http://lesscss.org/) as css preprocessor,you can override the default less variables to custom theme.
|
||||
|
||||
### Less variables
|
||||
|
||||
There are some [basic variables](<(https://github.com/youzan/vant/blob/dev/packages/vant/src/style/var.less)>) below, for component less variables, please refer to the documentation of each component, or view the `var.less` file in the component source directory.
|
||||
|
||||
```less
|
||||
// Color Palette
|
||||
@black: #000;
|
||||
@white: #fff;
|
||||
@gray-1: #f7f8fa;
|
||||
@gray-2: #f2f3f5;
|
||||
@gray-3: #ebedf0;
|
||||
@gray-4: #dcdee0;
|
||||
@gray-5: #c8c9cc;
|
||||
@gray-6: #969799;
|
||||
@gray-7: #646566;
|
||||
@gray-8: #323233;
|
||||
@red: #ee0a24;
|
||||
@blue: #1989fa;
|
||||
@orange: #ff976a;
|
||||
@orange-dark: #ed6a0c;
|
||||
@orange-light: #fffbe8;
|
||||
@green: #07c160;
|
||||
|
||||
// Gradient Colors
|
||||
@gradient-red: linear-gradient(to right, #ff6034, #ee0a24);
|
||||
@gradient-orange: linear-gradient(to right, #ffd01e, #ff8917);
|
||||
|
||||
// Component Colors
|
||||
@text-color: @gray-8;
|
||||
@active-color: @gray-2;
|
||||
@active-opacity: 0.7;
|
||||
@disabled-opacity: 0.5;
|
||||
@background-color: @gray-1;
|
||||
@background-color-light: #fafafa;
|
||||
@text-link-color: #576b95;
|
||||
|
||||
// Padding
|
||||
@padding-base: 4px;
|
||||
@padding-xs: @padding-base * 2;
|
||||
@padding-sm: @padding-base * 3;
|
||||
@padding-md: @padding-base * 4;
|
||||
@padding-lg: @padding-base * 6;
|
||||
@padding-xl: @padding-base * 8;
|
||||
|
||||
// Font
|
||||
@font-size-xs: 10px;
|
||||
@font-size-sm: 12px;
|
||||
@font-size-md: 14px;
|
||||
@font-size-lg: 16px;
|
||||
@font-weight-bold: 500;
|
||||
@line-height-xs: 14px;
|
||||
@line-height-sm: 18px;
|
||||
@line-height-md: 20px;
|
||||
@line-height-lg: 22px;
|
||||
@base-font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue',
|
||||
Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'miui', 'Hiragino Sans GB',
|
||||
'Microsoft Yahei', sans-serif;
|
||||
@price-integer-font-family: Avenir-Heavy, PingFang SC, Helvetica Neue, Arial,
|
||||
sans-serif;
|
||||
|
||||
// Animation
|
||||
@animation-duration-base: 0.3s;
|
||||
@animation-duration-fast: 0.2s;
|
||||
@animation-timing-function-enter: ease-out;
|
||||
@animation-timing-function-leave: ease-in;
|
||||
|
||||
// Border
|
||||
@border-color: @gray-3;
|
||||
@border-width-base: 1px;
|
||||
@border-radius-sm: 2px;
|
||||
@border-radius-md: 4px;
|
||||
@border-radius-lg: 8px;
|
||||
@border-radius-max: 999px;
|
||||
```
|
||||
|
||||
## How to custom theme
|
||||
|
||||
### Step 1: import less file
|
||||
|
||||
First you should import the less source file to your project. you can use babel-plugin-import to automatically import or just manually import less file.
|
||||
|
||||
#### Automatically import style
|
||||
|
||||
Configure babel plugin in babel.config.js, if you are using babel6, please manually import less file.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'import',
|
||||
{
|
||||
libraryName: 'vant',
|
||||
libraryDirectory: 'es',
|
||||
// specify less file path
|
||||
style: (name) => `${name}/style/less`,
|
||||
},
|
||||
'vant',
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
#### Manually import style
|
||||
|
||||
```js
|
||||
// import all styles
|
||||
import 'vant/lib/index.less';
|
||||
|
||||
// import style of single component
|
||||
import 'vant/lib/button/style/less';
|
||||
```
|
||||
|
||||
### Step 2: modify less variables
|
||||
|
||||
Use [modifyVars](http://lesscss.org/usage/#using-less-in-the-browser-modify-variables) provided by less.js to modify less variables,webpack config for reference:
|
||||
|
||||
```js
|
||||
// webpack.config.js
|
||||
module.exports = {
|
||||
rules: [
|
||||
{
|
||||
test: /\.less$/,
|
||||
use: [
|
||||
// ...other loaders
|
||||
{
|
||||
loader: 'less-loader',
|
||||
options: {
|
||||
lessOptions: {
|
||||
modifyVars: {
|
||||
// override with less vars
|
||||
'text-color': '#111',
|
||||
'border-color': '#eee',
|
||||
// or override with less file
|
||||
hack: `true; @import "your-less-file-path.less";`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
If you build a project by vue-cli,it can be configured in `vue.config.js`:
|
||||
|
||||
```js
|
||||
// vue.config.js
|
||||
module.exports = {
|
||||
css: {
|
||||
loaderOptions: {
|
||||
less: {
|
||||
lessOptions: {
|
||||
modifyVars: {
|
||||
// override with less vars
|
||||
'text-color': '#111',
|
||||
'border-color': '#eee',
|
||||
// or override with less file
|
||||
hack: `true; @import "your-less-file-path.less";`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Vite
|
||||
|
||||
Add the following config in `vite.config.js`.
|
||||
|
||||
```js
|
||||
// vite.config.js
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import styleImport from 'vite-plugin-style-import';
|
||||
|
||||
export default {
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
less: {
|
||||
javascriptEnabled: true,
|
||||
modifyVars: {
|
||||
'text-color': '#111',
|
||||
'border-color': '#eee',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
alias: [{ find: /^~/, replacement: '' }],
|
||||
},
|
||||
plugins: [
|
||||
vue(),
|
||||
styleImport({
|
||||
libs: [
|
||||
{
|
||||
libraryName: 'vant',
|
||||
esModule: true,
|
||||
resolveStyle: (name) => `vant/es/${name}/style/less`,
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,225 @@
|
||||
# 定制主题
|
||||
|
||||
### 废弃提示
|
||||
|
||||
本文档已废弃,Vant 提供了更方便的 [ConfigProvider 全局配置](#/zh-CN/config-provider) 组件进行主题配置。基于 Less 变量进行定制的方式**将在下个大版本废弃**。
|
||||
|
||||
### 介绍
|
||||
|
||||
Vant 提供了一套默认主题,CSS 命名采用 BEM 的风格,方便使用者覆盖样式。如果你想完全替换主题色或者其他样式,可以按照本文档进行主题定制。
|
||||
|
||||
### 示例工程
|
||||
|
||||
我们提供了一个基于 Vue Cli 3 的示例工程,仓库地址为 [Vant Demo](https://github.com/youzan/vant-demo),其中包含了定制主题的基本配置,可以作为参考。
|
||||
|
||||
### 样式变量
|
||||
|
||||
Vant 使用了 [Less](http://lesscss.org/) 对样式进行预处理,并内置了一些样式变量,通过替换样式变量即可定制你自己需要的主题。
|
||||
|
||||
下面是所有的[基础样式变量](https://github.com/youzan/vant/blob/dev/packages/vant/src/style/var.less),组件的样式变量请参考各个组件的文档,或查看组件源码目录下的 `var.less` 文件。
|
||||
|
||||
```less
|
||||
// Color Palette
|
||||
@black: #000;
|
||||
@white: #fff;
|
||||
@gray-1: #f7f8fa;
|
||||
@gray-2: #f2f3f5;
|
||||
@gray-3: #ebedf0;
|
||||
@gray-4: #dcdee0;
|
||||
@gray-5: #c8c9cc;
|
||||
@gray-6: #969799;
|
||||
@gray-7: #646566;
|
||||
@gray-8: #323233;
|
||||
@red: #ee0a24;
|
||||
@blue: #1989fa;
|
||||
@orange: #ff976a;
|
||||
@orange-dark: #ed6a0c;
|
||||
@orange-light: #fffbe8;
|
||||
@green: #07c160;
|
||||
|
||||
// Gradient Colors
|
||||
@gradient-red: linear-gradient(to right, #ff6034, #ee0a24);
|
||||
@gradient-orange: linear-gradient(to right, #ffd01e, #ff8917);
|
||||
|
||||
// Component Colors
|
||||
@text-color: @gray-8;
|
||||
@active-color: @gray-2;
|
||||
@active-opacity: 0.7;
|
||||
@disabled-opacity: 0.5;
|
||||
@background-color: @gray-1;
|
||||
@background-color-light: #fafafa;
|
||||
@text-link-color: #576b95;
|
||||
|
||||
// Padding
|
||||
@padding-base: 4px;
|
||||
@padding-xs: @padding-base * 2;
|
||||
@padding-sm: @padding-base * 3;
|
||||
@padding-md: @padding-base * 4;
|
||||
@padding-lg: @padding-base * 6;
|
||||
@padding-xl: @padding-base * 8;
|
||||
|
||||
// Font
|
||||
@font-size-xs: 10px;
|
||||
@font-size-sm: 12px;
|
||||
@font-size-md: 14px;
|
||||
@font-size-lg: 16px;
|
||||
@font-weight-bold: 500;
|
||||
@line-height-xs: 14px;
|
||||
@line-height-sm: 18px;
|
||||
@line-height-md: 20px;
|
||||
@line-height-lg: 22px;
|
||||
@base-font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue',
|
||||
Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'miui', 'Hiragino Sans GB',
|
||||
'Microsoft Yahei', sans-serif;
|
||||
@price-integer-font-family: Avenir-Heavy, PingFang SC, Helvetica Neue, Arial,
|
||||
sans-serif;
|
||||
|
||||
// Animation
|
||||
@animation-duration-base: 0.3s;
|
||||
@animation-duration-fast: 0.2s;
|
||||
@animation-timing-function-enter: ease-out;
|
||||
@animation-timing-function-leave: ease-in;
|
||||
|
||||
// Border
|
||||
@border-color: @gray-3;
|
||||
@border-width-base: 1px;
|
||||
@border-radius-sm: 2px;
|
||||
@border-radius-md: 4px;
|
||||
@border-radius-lg: 8px;
|
||||
@border-radius-max: 999px;
|
||||
```
|
||||
|
||||
## 定制方法
|
||||
|
||||
### 步骤一 引入样式源文件
|
||||
|
||||
定制主题时,需要引入组件对应的 Less 样式文件,支持按需引入和手动引入两种方式。
|
||||
|
||||
#### 按需引入样式(推荐)
|
||||
|
||||
在 babel.config.js 中配置按需引入样式源文件,注意 babel 6 不支持按需引入样式,请手动引入样式。
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'import',
|
||||
{
|
||||
libraryName: 'vant',
|
||||
libraryDirectory: 'es',
|
||||
// 指定样式路径
|
||||
style: (name) => `${name}/style/less`,
|
||||
},
|
||||
'vant',
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
#### 手动引入样式
|
||||
|
||||
```js
|
||||
// 引入全部样式
|
||||
import 'vant/lib/index.less';
|
||||
|
||||
// 引入单个组件样式
|
||||
import 'vant/lib/button/style/less';
|
||||
```
|
||||
|
||||
### 步骤二 修改样式变量
|
||||
|
||||
使用 Less 提供的 [modifyVars](http://lesscss.org/usage/#using-less-in-the-browser-modify-variables) 即可对变量进行修改,下面是参考的 webpack 配置。
|
||||
|
||||
```js
|
||||
// webpack.config.js
|
||||
module.exports = {
|
||||
rules: [
|
||||
{
|
||||
test: /\.less$/,
|
||||
use: [
|
||||
// ...其他 loader 配置
|
||||
{
|
||||
loader: 'less-loader',
|
||||
options: {
|
||||
// 若 less-loader 版本小于 6.0,请移除 lessOptions 这一级,直接配置选项。
|
||||
lessOptions: {
|
||||
modifyVars: {
|
||||
// 直接覆盖变量
|
||||
'text-color': '#111',
|
||||
'border-color': '#eee',
|
||||
// 或者可以通过 less 文件覆盖(文件路径为绝对路径)
|
||||
hack: `true; @import "your-less-file-path.less";`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
如果 vue-cli 搭建的项目,可以在 `vue.config.js` 中进行配置。
|
||||
|
||||
```js
|
||||
// vue.config.js
|
||||
module.exports = {
|
||||
css: {
|
||||
loaderOptions: {
|
||||
less: {
|
||||
// 若 less-loader 版本小于 6.0,请移除 lessOptions 这一级,直接配置选项。
|
||||
lessOptions: {
|
||||
modifyVars: {
|
||||
// 直接覆盖变量
|
||||
'text-color': '#111',
|
||||
'border-color': '#eee',
|
||||
// 或者可以通过 less 文件覆盖(文件路径为绝对路径)
|
||||
hack: `true; @import "your-less-file-path.less";`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Vite 项目
|
||||
|
||||
如果是 vite 项目,可以跳过以上步骤,直接在 `vite.config.js` 中添加如下配置即可。
|
||||
|
||||
```js
|
||||
// vite.config.js
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import styleImport from 'vite-plugin-style-import';
|
||||
|
||||
export default {
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
less: {
|
||||
javascriptEnabled: true,
|
||||
// 覆盖样式变量
|
||||
modifyVars: {
|
||||
'text-color': '#111',
|
||||
'border-color': '#eee',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
alias: [{ find: /^~/, replacement: '' }],
|
||||
},
|
||||
plugins: [
|
||||
vue(),
|
||||
// 按需引入样式源文件
|
||||
styleImport({
|
||||
libs: [
|
||||
{
|
||||
libraryName: 'vant',
|
||||
esModule: true,
|
||||
resolveStyle: (name) => `vant/es/${name}/style/less`,
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,85 @@
|
||||
# useClickAway
|
||||
|
||||
### Intro
|
||||
|
||||
Triggers a callback when user clicks outside of the target element.
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```html
|
||||
<div ref="root" />
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { useClickAway } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const root = ref();
|
||||
useClickAway(root, () => {
|
||||
console.log('click outside!');
|
||||
});
|
||||
|
||||
return { root };
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Custom Event
|
||||
|
||||
```html
|
||||
<div ref="root" />
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { useClickAway } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const root = ref();
|
||||
useClickAway(
|
||||
root,
|
||||
() => {
|
||||
console.log('touch outside!');
|
||||
},
|
||||
{ eventName: 'touchstart' }
|
||||
);
|
||||
|
||||
return { root };
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Type Declarations
|
||||
|
||||
```ts
|
||||
type Options = {
|
||||
eventName?: string;
|
||||
};
|
||||
|
||||
function useClickAway(
|
||||
target: Element | Ref<Element | undefined>,
|
||||
listener: EventListener,
|
||||
options?: Options
|
||||
): void;
|
||||
```
|
||||
|
||||
### Params
|
||||
|
||||
| Name | Description | Type | Default Value |
|
||||
| --- | --- | --- | --- |
|
||||
| target | Target element | _Element \| Ref\<Element>_ | - |
|
||||
| listener | Callback function when the outside is clicked | _EventListener_ | - |
|
||||
| options | Options | _Options_ | `{ eventName: 'click' }` |
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Description | Type | Default Value |
|
||||
| --------- | ----------- | -------- | ------------- |
|
||||
| eventName | Event name | _string_ | `click` |
|
||||
@@ -0,0 +1,87 @@
|
||||
# useClickAway
|
||||
|
||||
### 介绍
|
||||
|
||||
监听点击元素外部的事件。
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基本用法
|
||||
|
||||
```html
|
||||
<div ref="root" />
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { useClickAway } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const root = ref();
|
||||
useClickAway(root, () => {
|
||||
console.log('click outside!');
|
||||
});
|
||||
|
||||
return { root };
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 自定义事件
|
||||
|
||||
通过 `eventName` 选项可以自定义需要监听的事件类型。
|
||||
|
||||
```html
|
||||
<div ref="root" />
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { useClickAway } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const root = ref();
|
||||
useClickAway(
|
||||
root,
|
||||
() => {
|
||||
console.log('touch outside!');
|
||||
},
|
||||
{ eventName: 'touchstart' }
|
||||
);
|
||||
|
||||
return { root };
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### 类型定义
|
||||
|
||||
```ts
|
||||
type Options = {
|
||||
eventName?: string;
|
||||
};
|
||||
|
||||
function useClickAway(
|
||||
target: Element | Ref<Element | undefined>,
|
||||
listener: EventListener,
|
||||
options?: Options
|
||||
): void;
|
||||
```
|
||||
|
||||
### 参数
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| -------- | ------------------------ | -------------------------- | ------ |
|
||||
| target | 绑定事件的元素 | _Element \| Ref\<Element>_ | - |
|
||||
| listener | 点击外部时触发的回调函数 | _EventListener_ | - |
|
||||
| options | 可选的配置项 | _Options_ | 见下表 |
|
||||
|
||||
### Options
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --------- | -------------- | -------- | ------- |
|
||||
| eventName | 监听的事件类型 | _string_ | `click` |
|
||||
@@ -0,0 +1,116 @@
|
||||
# useCountDown
|
||||
|
||||
### Intro
|
||||
|
||||
Used to manage the countdown.
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```html
|
||||
<span>Total time:{{ current.total }}</span>
|
||||
<span>Remain days:{{ current.days }}</span>
|
||||
<span>Remain hours:{{ current.hours }}</span>
|
||||
<span>Remain minutes:{{ current.minutes }}</span>
|
||||
<span>Remain seconds:{{ current.seconds }}</span>
|
||||
<span>Remain milliseconds:{{ current.milliseconds }}</span>
|
||||
```
|
||||
|
||||
```js
|
||||
import { useCountDown } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const countDown = useCountDown({
|
||||
time: 24 * 60 * 60 * 1000,
|
||||
});
|
||||
|
||||
countDown.start();
|
||||
|
||||
return {
|
||||
current: countDown.current,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Millisecond
|
||||
|
||||
```js
|
||||
import { useCountDown } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const countDown = useCountDown({
|
||||
time: 24 * 60 * 60 * 1000,
|
||||
millisecond: true,
|
||||
});
|
||||
countDown.start();
|
||||
|
||||
return {
|
||||
current: countDown.current,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Type Declarations
|
||||
|
||||
```ts
|
||||
type CurrentTime = {
|
||||
days: number;
|
||||
hours: number;
|
||||
total: number;
|
||||
minutes: number;
|
||||
seconds: number;
|
||||
milliseconds: number;
|
||||
};
|
||||
|
||||
type CountDown = {
|
||||
start: () => void;
|
||||
pause: () => void;
|
||||
reset: (totalTime: number) => void;
|
||||
current: ComputedRef<CurrentTime>;
|
||||
};
|
||||
|
||||
type UseCountDownOptions = {
|
||||
time: number;
|
||||
millisecond?: boolean;
|
||||
onChange?: (current: CurrentTime) => void;
|
||||
onFinish?: () => void;
|
||||
};
|
||||
|
||||
function useCountDown(options: UseCountDownOptions): CountDown;
|
||||
```
|
||||
|
||||
### Params
|
||||
|
||||
| Name | Description | Type | Default Value |
|
||||
| --- | --- | --- | --- |
|
||||
| time | Total time, unit milliseconds | _number_ | - |
|
||||
| millisecond | Whether to enable millisecond render | _boolean_ | `false` |
|
||||
| onChange | Triggered when count down changed | _(current: CurrentTime) => void_ | - |
|
||||
| onFinish | Triggered when count down finished | - |
|
||||
|
||||
### Return Value
|
||||
|
||||
| Name | Description | Type |
|
||||
| ------- | ------------------- | ----------------------- |
|
||||
| current | Current remain time | _CurrentTime_ |
|
||||
| start | Start count down | _() => void_ |
|
||||
| pause | Pause count down | _() => void_ |
|
||||
| reset | Reset count down | _(time?: number): void_ |
|
||||
|
||||
### CurrentTime Structure
|
||||
|
||||
| Name | Description | Type |
|
||||
| ------------ | ----------------------------- | -------- |
|
||||
| total | Total time, unit milliseconds | _number_ |
|
||||
| days | Remain days | _number_ |
|
||||
| hours | Remain hours | _number_ |
|
||||
| minutes | Remain minutes | _number_ |
|
||||
| seconds | Remain seconds | _number_ |
|
||||
| milliseconds | Remain milliseconds | _number_ |
|
||||
@@ -0,0 +1,120 @@
|
||||
# useCountDown
|
||||
|
||||
### 介绍
|
||||
|
||||
提供倒计时管理能力。
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基本用法
|
||||
|
||||
```html
|
||||
<span>总时间:{{ current.total }}</span>
|
||||
<span>剩余天数:{{ current.days }}</span>
|
||||
<span>剩余小时:{{ current.hours }}</span>
|
||||
<span>剩余分钟:{{ current.minutes }}</span>
|
||||
<span>剩余秒数:{{ current.seconds }}</span>
|
||||
<span>剩余毫秒:{{ current.milliseconds }}</span>
|
||||
```
|
||||
|
||||
```js
|
||||
import { useCountDown } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const countDown = useCountDown({
|
||||
// 倒计时 24 小时
|
||||
time: 24 * 60 * 60 * 1000,
|
||||
});
|
||||
|
||||
// 开始倒计时
|
||||
countDown.start();
|
||||
|
||||
return {
|
||||
current: countDown.current,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 毫秒级渲染
|
||||
|
||||
倒计时默认每秒渲染一次,设置 millisecond 选项可以开启毫秒级渲染。
|
||||
|
||||
```js
|
||||
import { useCountDown } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const countDown = useCountDown({
|
||||
time: 24 * 60 * 60 * 1000,
|
||||
millisecond: true,
|
||||
});
|
||||
countDown.start();
|
||||
|
||||
return {
|
||||
current: countDown.current,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### 类型定义
|
||||
|
||||
```ts
|
||||
type CurrentTime = {
|
||||
days: number;
|
||||
hours: number;
|
||||
total: number;
|
||||
minutes: number;
|
||||
seconds: number;
|
||||
milliseconds: number;
|
||||
};
|
||||
|
||||
type CountDown = {
|
||||
start: () => void;
|
||||
pause: () => void;
|
||||
reset: (totalTime: number) => void;
|
||||
current: ComputedRef<CurrentTime>;
|
||||
};
|
||||
|
||||
type UseCountDownOptions = {
|
||||
time: number;
|
||||
millisecond?: boolean;
|
||||
onChange?: (current: CurrentTime) => void;
|
||||
onFinish?: () => void;
|
||||
};
|
||||
|
||||
function useCountDown(options: UseCountDownOptions): CountDown;
|
||||
```
|
||||
|
||||
### 参数
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| time | 倒计时时长,单位毫秒 | _number_ | - |
|
||||
| millisecond | 是否开启毫秒级渲染 | _boolean_ | `false` |
|
||||
| onChange | 倒计时改变时触发的回调函数 | _(current: CurrentTime) => void_ | - |
|
||||
| onFinish | 倒计时结束时触发的回调函数 | - |
|
||||
|
||||
### 返回值
|
||||
|
||||
| 参数 | 说明 | 类型 |
|
||||
| ------- | ---------------------------------- | ----------------------- |
|
||||
| current | 当前剩余的时间 | _CurrentTime_ |
|
||||
| start | 开始倒计时 | _() => void_ |
|
||||
| pause | 暂停倒计时 | _() => void_ |
|
||||
| reset | 重置倒计时,支持传入新的倒计时时长 | _(time?: number): void_ |
|
||||
|
||||
### CurrentTime 格式
|
||||
|
||||
| 名称 | 说明 | 类型 |
|
||||
| ------------ | ---------------------- | -------- |
|
||||
| total | 剩余总时间(单位毫秒) | _number_ |
|
||||
| days | 剩余天数 | _number_ |
|
||||
| hours | 剩余小时 | _number_ |
|
||||
| minutes | 剩余分钟 | _number_ |
|
||||
| seconds | 剩余秒数 | _number_ |
|
||||
| milliseconds | 剩余毫秒 | _number_ |
|
||||
@@ -0,0 +1,50 @@
|
||||
# useCustomFieldValue
|
||||
|
||||
### Intro
|
||||
|
||||
Used to custom Field value.
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
If you want to custom Form items, you can insert your component into the `input` slot of the Field component, and call the `useCustomFieldValue` method inside your custom component.
|
||||
|
||||
#### MyComponent
|
||||
|
||||
```js
|
||||
// MyComponent.vue
|
||||
import { useCustomFieldValue } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
useCustomFieldValue(() => 'Some value');
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
#### Form
|
||||
|
||||
```html
|
||||
<van-form>
|
||||
<van-field name="my-field" label="Custom Field">
|
||||
<template #input>
|
||||
<my-component />
|
||||
</template>
|
||||
</van-field>
|
||||
</van-form>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Type Declarations
|
||||
|
||||
```ts
|
||||
function useCustomFieldValue(customValue: () => unknown): void;
|
||||
```
|
||||
|
||||
### Params
|
||||
|
||||
| Name | Description | Type | Default Value |
|
||||
| ----------- | --------------------------- | --------------- | ------------- |
|
||||
| customValue | Function to get field value | _() => unknown_ | - |
|
||||
@@ -0,0 +1,57 @@
|
||||
# useCustomFieldValue
|
||||
|
||||
### 介绍
|
||||
|
||||
用于自定义 Form 组件中的表单项。
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基本用法
|
||||
|
||||
如果需要自定义表单项,可以在 Field 组件的 `input` 插槽中插入你的自定义组件,并在自定义组件内部调用 `useCustomFieldValue` 方法。
|
||||
|
||||
#### 自定义组件
|
||||
|
||||
首先,在你的自定义组件中,调用 `useCustomFieldValue` 方法,并传入一个回调函数,这个函数返回值为表单项的值。
|
||||
|
||||
```js
|
||||
// MyComponent.vue
|
||||
import { useCustomFieldValue } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
// 此处传入的值会替代 Field 组件内部的 value
|
||||
useCustomFieldValue(() => 'Some value');
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
#### 表单
|
||||
|
||||
接着,在 Form 组件中嵌入你的自定义组件,当提交表单时,即可获取到自定义表单项的值。
|
||||
|
||||
```html
|
||||
<van-form>
|
||||
<!-- 这是一个自定义表单项 -->
|
||||
<!-- 当表单提交时,会包括 useCustomFieldValue 中传入的值 -->
|
||||
<van-field name="my-field" label="自定义表单项">
|
||||
<template #input>
|
||||
<my-component />
|
||||
</template>
|
||||
</van-field>
|
||||
</van-form>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### 类型定义
|
||||
|
||||
```ts
|
||||
function useCustomFieldValue(customValue: () => unknown): void;
|
||||
```
|
||||
|
||||
### 参数
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| ----------- | ------------------ | --------------- | ------ |
|
||||
| customValue | 获取表单项值的函数 | _() => unknown_ | - |
|
||||
@@ -0,0 +1,67 @@
|
||||
# useEventListener
|
||||
|
||||
### 介绍
|
||||
|
||||
方便地进行事件绑定,在组件 `mounted` 和 `activated` 时绑定事件,`unmounted` 和 `deactivated` 时解绑事件。
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基本用法
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { useEventListener } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
// 在 window 上绑定 resize 事件
|
||||
// 未指定监听对象时,默认会监听 window 的事件
|
||||
useEventListener('resize', () => {
|
||||
console.log('window resize');
|
||||
});
|
||||
|
||||
// 在 body 元素上绑定 click 事件
|
||||
useEventListener(
|
||||
'click',
|
||||
() => {
|
||||
console.log('click body');
|
||||
},
|
||||
{ target: document.body }
|
||||
);
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 类型定义
|
||||
|
||||
```ts
|
||||
type Options = {
|
||||
target?: EventTarget | Ref<EventTarget>;
|
||||
capture?: boolean;
|
||||
passive?: boolean;
|
||||
};
|
||||
|
||||
function useEventListener(
|
||||
type: string,
|
||||
listener: EventListener,
|
||||
options?: Options
|
||||
): void;
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### 参数
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| -------- | ------------------------ | --------------- | ------ |
|
||||
| type | 监听的事件类型 | _string_ | - |
|
||||
| listener | 点击外部时触发的回调函数 | _EventListener_ | - |
|
||||
| options | 可选的配置项 | _Options_ | - |
|
||||
|
||||
### Options
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| target | 绑定事件的元素 | _EventTarget \| Ref\<EventTarget>_ | `window` |
|
||||
| capture | 是否在事件捕获阶段触发 | _boolean_ | `false` |
|
||||
| passive | 设置为 `true` 时,表示 `listener` 永远不会调用 `preventDefault` | _boolean_ | `false` |
|
||||
@@ -0,0 +1,40 @@
|
||||
# usePageVisibility
|
||||
|
||||
### 介绍
|
||||
|
||||
获取页面的可见状态。
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基本用法
|
||||
|
||||
```js
|
||||
import { watch } from 'vue';
|
||||
import { usePageVisibility } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const pageVisibility = usePageVisibility();
|
||||
|
||||
watch(pageVisibility, (value) => {
|
||||
console.log('visibility: ', value);
|
||||
});
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### 类型定义
|
||||
|
||||
```ts
|
||||
type VisibilityState = 'visible' | 'hidden';
|
||||
|
||||
function usePageVisibility(): Ref<VisibilityState>;
|
||||
```
|
||||
|
||||
### 返回值
|
||||
|
||||
| 参数 | 说明 | 类型 |
|
||||
| --- | --- | --- |
|
||||
| visibilityState | 页面当前的可见状态,`visible` 为可见,`hidden` 为隐藏 | _Ref\<VisibilityState>_ |
|
||||
@@ -0,0 +1,50 @@
|
||||
# useRect
|
||||
|
||||
### 介绍
|
||||
|
||||
获取元素的大小及其相对于视口的位置,等价于 [Element.getBoundingClientRect](https://developer.mozilla.org/zh-CN/docs/Web/API/Element/getBoundingClientRect)。
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基本用法
|
||||
|
||||
```html
|
||||
<div ref="root" />
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { useRect } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const root = ref();
|
||||
const rect = useRect(root);
|
||||
|
||||
console.log(rect); // -> 元素的大小及其相对于视口的位置
|
||||
|
||||
return { root };
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### 类型定义
|
||||
|
||||
```ts
|
||||
function useRect(
|
||||
element: Element | Window | Ref<Element | Window | undefined>
|
||||
): DOMRect;
|
||||
```
|
||||
|
||||
### 返回值
|
||||
|
||||
| 参数 | 说明 | 类型 |
|
||||
| ------ | -------------------------- | -------- |
|
||||
| width | 宽度 | _number_ |
|
||||
| height | 高度 | _number_ |
|
||||
| top | 顶部与视图窗口左上角的距离 | _number_ |
|
||||
| left | 左侧与视图窗口左上角的距离 | _number_ |
|
||||
| right | 右侧与视图窗口左上角的距离 | _number_ |
|
||||
| bottom | 底部与视图窗口左上角的距离 | _number_ |
|
||||
@@ -0,0 +1,80 @@
|
||||
# useRelation
|
||||
|
||||
### 介绍
|
||||
|
||||
建立父子组件之间的关联关系,进行数据通信和方法调用,基于 `provide` 和 `inject` 实现。
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基本用法
|
||||
|
||||
在父组件中使用 `useChildren` 关联子组件:
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { useChildren } from '@vant/use';
|
||||
|
||||
const RELATION_KEY = Symbol('my-relation');
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const { linkChildren } = useChildren(RELATION_KEY);
|
||||
|
||||
const count = ref(0);
|
||||
const add = () => {
|
||||
count.value++;
|
||||
};
|
||||
|
||||
// 向子组件提供数据和方法
|
||||
linkChildren({ add, count });
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
在子组件中使用 `useParent` 获取父组件提供的数据和方法:
|
||||
|
||||
```js
|
||||
import { useParent } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const { parent } = useParent(RELATION_KEY);
|
||||
|
||||
// 调用父组件提供的数据和方法
|
||||
if (parent) {
|
||||
parent.add();
|
||||
console.log(parent.count.value); // -> 1
|
||||
}
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### 类型定义
|
||||
|
||||
```ts
|
||||
function useParent<T>(key: string | symbol): {
|
||||
parent?: T;
|
||||
index?: Ref<number>;
|
||||
};
|
||||
|
||||
function useChildren(key: string | symbol): {
|
||||
children: ComponentPublicInstance[];
|
||||
linkChildren: (value: any) => void;
|
||||
};
|
||||
```
|
||||
|
||||
### useParent 返回值
|
||||
|
||||
| 参数 | 说明 | 类型 |
|
||||
| ------ | -------------------------------------------- | -------------- |
|
||||
| parent | 父组件提供的值 | _any_ |
|
||||
| index | 当前组件在父组件的所有子组件中对应的索引位置 | _Ref\<number>_ |
|
||||
|
||||
### useChildren 返回值
|
||||
|
||||
| 参数 | 说明 | 类型 |
|
||||
| ------------ | -------------------- | --------------------------- |
|
||||
| children | 子组件列表 | _ComponentPublicInstance[]_ |
|
||||
| linkChildren | 向子组件提供值的方法 | _(value: any) => void_ |
|
||||
@@ -0,0 +1,57 @@
|
||||
# useScrollParent
|
||||
|
||||
### 介绍
|
||||
|
||||
获取元素最近的可滚动父元素。
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基本用法
|
||||
|
||||
```html
|
||||
<div ref="root" />
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref, watch } from 'vue';
|
||||
import { useScrollParent, useEventListener } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const root = ref();
|
||||
const scrollParent = useScrollParent(root);
|
||||
|
||||
useEventListener(
|
||||
'scroll',
|
||||
() => {
|
||||
console.log('scroll');
|
||||
},
|
||||
{ target: scrollParent }
|
||||
);
|
||||
|
||||
return { root };
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### 类型定义
|
||||
|
||||
```ts
|
||||
function useScrollParent(
|
||||
element: Ref<Element | undefined>
|
||||
): Ref<Element | Window | undefined>;
|
||||
```
|
||||
|
||||
### 参数
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| ------- | -------- | --------------- | ------ |
|
||||
| element | 当前元素 | _Ref\<Element>_ | - |
|
||||
|
||||
### 返回值
|
||||
|
||||
| 参数 | 说明 | 类型 |
|
||||
| ------------ | ------------------ | --------------- |
|
||||
| scrollParent | 最近的可滚动父元素 | _Ref\<Element>_ |
|
||||
@@ -0,0 +1,64 @@
|
||||
# useToggle
|
||||
|
||||
### Intro
|
||||
|
||||
Used to switch between `true` and `false`.
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```js
|
||||
import { useToggle } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const [state, toggle] = useToggle();
|
||||
|
||||
toggle(true);
|
||||
console.log(state.value); // -> true
|
||||
|
||||
toggle(false);
|
||||
console.log(state.value); // -> false
|
||||
|
||||
toggle();
|
||||
console.log(state.value); // -> true
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Default Value
|
||||
|
||||
```js
|
||||
import { useToggle } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const [state, toggle] = useToggle(true);
|
||||
console.log(state.value); // -> true
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Type Declarations
|
||||
|
||||
```ts
|
||||
function useToggle(
|
||||
defaultValue: boolean
|
||||
): [Ref<boolean>, (newValue: boolean) => void];
|
||||
```
|
||||
|
||||
### Params
|
||||
|
||||
| Name | Description | Type | Default Value |
|
||||
| ------------ | ------------- | --------- | ------------- |
|
||||
| defaultValue | Default value | _boolean_ | `false` |
|
||||
|
||||
### Return Value
|
||||
|
||||
| Name | Description | Type |
|
||||
| ------ | ------------------------ | ------------------------------ |
|
||||
| state | State | _Ref\<boolean>_ |
|
||||
| toggle | Function to switch state | _(newValue?: boolean) => void_ |
|
||||
@@ -0,0 +1,64 @@
|
||||
# useToggle
|
||||
|
||||
### 介绍
|
||||
|
||||
用于在 `true` 和 `false` 之间进行切换。
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基本用法
|
||||
|
||||
```js
|
||||
import { useToggle } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const [state, toggle] = useToggle();
|
||||
|
||||
toggle(true);
|
||||
console.log(state.value); // -> true
|
||||
|
||||
toggle(false);
|
||||
console.log(state.value); // -> false
|
||||
|
||||
toggle();
|
||||
console.log(state.value); // -> true
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 设置默认值
|
||||
|
||||
```js
|
||||
import { useToggle } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const [state, toggle] = useToggle(true);
|
||||
console.log(state.value); // -> true
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### 类型定义
|
||||
|
||||
```ts
|
||||
function useToggle(
|
||||
defaultValue: boolean
|
||||
): [Ref<boolean>, (newValue: boolean) => void];
|
||||
```
|
||||
|
||||
### 参数
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| ------------ | ------ | --------- | ------- |
|
||||
| defaultValue | 默认值 | _boolean_ | `false` |
|
||||
|
||||
### 返回值
|
||||
|
||||
| 参数 | 说明 | 类型 |
|
||||
| ------ | ---------------- | ------------------------------ |
|
||||
| state | 状态值 | _Ref\<boolean>_ |
|
||||
| toggle | 切换状态值的函数 | _(newValue?: boolean) => void_ |
|
||||
@@ -0,0 +1,45 @@
|
||||
# useWindowSize
|
||||
|
||||
### 介绍
|
||||
|
||||
获取浏览器窗口的视口宽度和高度,并在窗口大小变化时自动更新。
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基本用法
|
||||
|
||||
```js
|
||||
import { watch } from 'vue';
|
||||
import { useWindowSize } from '@vant/use';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const { width, height } = useWindowSize();
|
||||
|
||||
console.log(width.value); // -> 窗口宽度
|
||||
console.log(height.value); // -> 窗口高度
|
||||
|
||||
watch([width, height], () => {
|
||||
console.log('window resized');
|
||||
});
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### 类型定义
|
||||
|
||||
```ts
|
||||
function useWindowSize(): {
|
||||
width: Ref<number>;
|
||||
height: Ref<number>;
|
||||
};
|
||||
```
|
||||
|
||||
### 返回值
|
||||
|
||||
| 参数 | 说明 | 类型 |
|
||||
| ------ | -------------- | -------------- |
|
||||
| width | 浏览器窗口宽度 | _Ref\<number>_ |
|
||||
| height | 浏览器窗口高度 | _Ref\<number>_ |
|
||||
@@ -0,0 +1,24 @@
|
||||
# Composables
|
||||
|
||||
### Intro
|
||||
|
||||
Vant provide some built-in composition APIs, you can directly use these APIs for development.
|
||||
|
||||
### Demo
|
||||
|
||||
```js
|
||||
import { useWindowSize } from '@vant/use';
|
||||
|
||||
const { width, height } = useWindowSize();
|
||||
|
||||
console.log(width.value); // -> window width
|
||||
console.log(height.value); // -> window height
|
||||
```
|
||||
|
||||
### API List
|
||||
|
||||
| Name | Description |
|
||||
| --- | --- |
|
||||
| [useClickAway](#/en-US/use-click-away) | Triggers a callback when user clicks outside of the target element |
|
||||
| [useCountDown](#/en-US/use-count-down) | Used to manage the countdown |
|
||||
| [useToggle](#/en-US/use-toggle) | Used to switch between `true` and `false` |
|
||||
@@ -0,0 +1,34 @@
|
||||
# 组合式 API
|
||||
|
||||
### 介绍
|
||||
|
||||
Vant 内置了一系列的组合式 API,对于安装了 `vant` 的项目,可以直接使用这些 API 进行开发。
|
||||
|
||||
### 示例
|
||||
|
||||
下面是一个 Vant 组合式 API 的用法示例,我们从 `@vant/use` 这个包中引入 `useWindowSize` 方法,然后进行调用,即可获取到当前 Window 的宽度和高度。
|
||||
|
||||
```js
|
||||
import { useWindowSize } from '@vant/use';
|
||||
|
||||
const { width, height } = useWindowSize();
|
||||
|
||||
console.log(width.value); // -> 窗口宽度
|
||||
console.log(height.value); // -> 窗口高度
|
||||
```
|
||||
|
||||
### API 列表
|
||||
|
||||
下面是 Vant 对外提供的所有组合式 API,点击名称可以查看详细介绍:
|
||||
|
||||
| 名称 | 描述 |
|
||||
| --- | --- |
|
||||
| [useClickAway](#/zh-CN/use-click-away) | 监听点击元素外部的事件 |
|
||||
| [useCountDown](#/zh-CN/use-count-down) | 提供倒计时管理能力 |
|
||||
| [useEventListener](#/zh-CN/use-event-listener) | 方便地进行事件绑定 |
|
||||
| [usePageVisibility](#/zh-CN/use-page-visibility) | 获取页面的可见状态 |
|
||||
| [useRect](#/zh-CN/use-rect) | 获取元素的大小及其相对于视口的位置 |
|
||||
| [useRelation](#/zh-CN/use-relation) | 建立父子组件之间的关联关系 |
|
||||
| [useScrollParent](#/zh-CN/use-scroll-parent) | 获取元素最近的可滚动父元素 |
|
||||
| [useToggle](#/zh-CN/use-toggle) | 用于在布尔值之间进行切换 |
|
||||
| [useWindowSize](#/zh-CN/use-window-size) | 获取浏览器窗口的视口宽度和高度 |
|
||||
@@ -0,0 +1,79 @@
|
||||
import Locale from '../../src/locale';
|
||||
import enUS from '../../src/locale/lang/en-US';
|
||||
|
||||
export function initDemoLocale() {
|
||||
Locale.add({
|
||||
'en-US': enUS,
|
||||
});
|
||||
|
||||
// switch lang after routing
|
||||
if (window.vueRouter) {
|
||||
window.vueRouter.afterEach((to) => {
|
||||
const { lang } = to.meta || {};
|
||||
|
||||
if (lang) {
|
||||
Locale.use(lang);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// add some basic locale messages
|
||||
Locale.add({
|
||||
'zh-CN': {
|
||||
add: '增加',
|
||||
decrease: '减少',
|
||||
red: '红色',
|
||||
orange: '橙色',
|
||||
yellow: '黄色',
|
||||
purple: '紫色',
|
||||
tab: '标签',
|
||||
tag: '标签',
|
||||
desc: '描述信息',
|
||||
back: '返回',
|
||||
title: '标题',
|
||||
status: '状态',
|
||||
button: '按钮',
|
||||
option: '选项',
|
||||
search: '搜索',
|
||||
content: '内容',
|
||||
custom: '自定义',
|
||||
username: '用户名',
|
||||
password: '密码',
|
||||
disabled: '禁用状态',
|
||||
uneditable: '不可编辑',
|
||||
basicUsage: '基础用法',
|
||||
advancedUsage: '高级用法',
|
||||
loadingStatus: '加载状态',
|
||||
usernamePlaceholder: '请输入用户名',
|
||||
passwordPlaceholder: '请输入密码',
|
||||
},
|
||||
'en-US': {
|
||||
add: 'Add',
|
||||
decrease: 'Decrease',
|
||||
red: 'Red',
|
||||
orange: 'Orange',
|
||||
yellow: 'Yellow',
|
||||
purple: 'Purple',
|
||||
tab: 'Tab',
|
||||
tag: 'Tag',
|
||||
desc: 'Description',
|
||||
back: 'Back',
|
||||
title: 'Title',
|
||||
status: 'Status',
|
||||
button: 'Button',
|
||||
option: 'Option',
|
||||
search: 'Search',
|
||||
content: 'Content',
|
||||
custom: 'Custom',
|
||||
username: 'Username',
|
||||
password: 'Password',
|
||||
loadingStatus: 'Loading',
|
||||
disabled: 'Disabled',
|
||||
uneditable: 'Uneditable',
|
||||
basicUsage: 'Basic Usage',
|
||||
advancedUsage: 'Advanced Usage',
|
||||
usernamePlaceholder: 'Username',
|
||||
passwordPlaceholder: 'Password',
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { initDemoLocale } from './demo-locale';
|
||||
import Lazyload from '../../src/lazyload';
|
||||
|
||||
initDemoLocale();
|
||||
|
||||
const { app } = window;
|
||||
if (app) {
|
||||
app.use(Lazyload, {
|
||||
lazyComponent: true,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import Locale from '../../src/locale';
|
||||
import { camelize } from '../../src/utils/format/string';
|
||||
import { createTranslate } from '../../src/utils/create/translate';
|
||||
|
||||
let demoUid = 0;
|
||||
|
||||
export function useTranslate(i18n: Record<string, any>) {
|
||||
const demoName = `demo-i18n-${demoUid++}`;
|
||||
|
||||
if (i18n) {
|
||||
const locales: Record<string, any> = {};
|
||||
const camelizedName = camelize(demoName);
|
||||
|
||||
Object.keys(i18n).forEach((key) => {
|
||||
locales[key] = { [camelizedName]: i18n[key] };
|
||||
});
|
||||
|
||||
Locale.add(locales);
|
||||
}
|
||||
|
||||
return createTranslate(demoName);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
testPathIgnorePatterns: ['/node_modules/'],
|
||||
collectCoverageFrom: [
|
||||
'src/**/*.{js,jsx,ts,tsx,vue}',
|
||||
'!**/demo/**',
|
||||
'!**/test/**',
|
||||
'!**/lang/**',
|
||||
],
|
||||
moduleNameMapper: {
|
||||
'^@demo(.*)$': '<rootDir>/docs/site$1',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"name": "vant",
|
||||
"version": "3.2.2",
|
||||
"description": "Mobile UI Components built on Vue",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
"style": "lib/index.css",
|
||||
"typings": "lib/index.d.ts",
|
||||
"files": [
|
||||
"es",
|
||||
"lib",
|
||||
"vetur"
|
||||
],
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vant-cli dev",
|
||||
"lint": "vant-cli lint",
|
||||
"test": "vant-cli test",
|
||||
"build": "vant-cli build",
|
||||
"build:site": "vant-cli build-site",
|
||||
"release": "vant-cli release --tag next",
|
||||
"release:site": "yarn build:site && gh-pages -d site --add --dest v3",
|
||||
"test:watch": "vant-cli test --watch",
|
||||
"test:coverage": "open test/coverage/index.html"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.md": "prettier --write",
|
||||
"*.{ts,tsx,js,vue,less}": "prettier --write",
|
||||
"*.{ts,tsx,js,vue}": "eslint --fix",
|
||||
"*.{vue,css,less}": "stylelint --fix"
|
||||
},
|
||||
"npm": {
|
||||
"tag": "next"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:youzan/vant.git"
|
||||
},
|
||||
"keywords": [
|
||||
"ui",
|
||||
"vue",
|
||||
"vue3",
|
||||
"mobile",
|
||||
"frontend",
|
||||
"component",
|
||||
"components"
|
||||
],
|
||||
"author": "youzanfe",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vant/icons": "^1.7.0",
|
||||
"@vant/lazyload": "^1.2.0",
|
||||
"@vant/popperjs": "^1.1.0",
|
||||
"@vant/use": "^1.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vant/cli": "^4.0.0-beta.1",
|
||||
"@vant/area-data": "^1.1.1",
|
||||
"@vue/compiler-sfc": "^3.2.6",
|
||||
"vue": "^3.2.6"
|
||||
},
|
||||
"sideEffects": [
|
||||
"es/**/style/*",
|
||||
"lib/**/style/*",
|
||||
"*.css",
|
||||
"*.less"
|
||||
],
|
||||
"vetur": {
|
||||
"tags": "vetur/tags.json",
|
||||
"attributes": "vetur/attributes.json"
|
||||
},
|
||||
"web-types": "vetur/web-types.json",
|
||||
"unpkg": "lib/vant.min.js",
|
||||
"jsdelivr": "lib/vant.min.js"
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import { computed, PropType, defineComponent } from 'vue';
|
||||
import { extend, createNamespace } from '../utils';
|
||||
import { ACTION_BAR_KEY } from '../action-bar/ActionBar';
|
||||
|
||||
// Composables
|
||||
import { useParent } from '@vant/use';
|
||||
import { useExpose } from '../composables/use-expose';
|
||||
import { useRoute, routeProps } from '../composables/use-route';
|
||||
|
||||
// Components
|
||||
import { Button, ButtonType } from '../button';
|
||||
|
||||
const [name, bem] = createNamespace('action-bar-button');
|
||||
|
||||
export default defineComponent({
|
||||
name,
|
||||
|
||||
props: extend({}, routeProps, {
|
||||
type: String as PropType<ButtonType>,
|
||||
text: String,
|
||||
icon: String,
|
||||
color: String,
|
||||
loading: Boolean,
|
||||
disabled: Boolean,
|
||||
}),
|
||||
|
||||
setup(props, { slots }) {
|
||||
const route = useRoute();
|
||||
const { parent, index } = useParent(ACTION_BAR_KEY);
|
||||
|
||||
const isFirst = computed(() => {
|
||||
if (parent) {
|
||||
const prev = parent.children[index.value - 1];
|
||||
return !(prev && 'isButton' in prev);
|
||||
}
|
||||
});
|
||||
|
||||
const isLast = computed(() => {
|
||||
if (parent) {
|
||||
const next = parent.children[index.value + 1];
|
||||
return !(next && 'isButton' in next);
|
||||
}
|
||||
});
|
||||
|
||||
useExpose({ isButton: true });
|
||||
|
||||
return () => {
|
||||
const { type, icon, text, color, loading, disabled } = props;
|
||||
|
||||
return (
|
||||
<Button
|
||||
class={bem([
|
||||
type,
|
||||
{
|
||||
last: isLast.value,
|
||||
first: isFirst.value,
|
||||
},
|
||||
])}
|
||||
size="large"
|
||||
type={type}
|
||||
icon={icon}
|
||||
color={color}
|
||||
loading={loading}
|
||||
disabled={disabled}
|
||||
onClick={route}
|
||||
>
|
||||
{slots.default ? slots.default() : text}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
@import './var.less';
|
||||
|
||||
:root {
|
||||
--van-action-bar-button-height: @action-bar-button-height;
|
||||
--van-action-bar-button-warning-color: @action-bar-button-warning-color;
|
||||
--van-action-bar-button-danger-color: @action-bar-button-danger-color;
|
||||
}
|
||||
|
||||
.van-action-bar-button {
|
||||
flex: 1;
|
||||
height: var(--van-action-bar-button-height);
|
||||
font-weight: var(--van-font-weight-bold);
|
||||
font-size: var(--van-font-size-md);
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
|
||||
&--first {
|
||||
margin-left: 5px;
|
||||
border-top-left-radius: var(--van-border-radius-max);
|
||||
border-bottom-left-radius: var(--van-border-radius-max);
|
||||
}
|
||||
|
||||
&--last {
|
||||
margin-right: 5px;
|
||||
border-top-right-radius: var(--van-border-radius-max);
|
||||
border-bottom-right-radius: var(--van-border-radius-max);
|
||||
}
|
||||
|
||||
&--warning {
|
||||
background: var(--van-action-bar-button-warning-color);
|
||||
}
|
||||
|
||||
&--danger {
|
||||
background: var(--van-action-bar-button-danger-color);
|
||||
}
|
||||
|
||||
@media (max-width: 321px) {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { withInstall } from '../utils';
|
||||
import _ActionBarButton from './ActionBarButton';
|
||||
|
||||
export const ActionBarButton = withInstall(_ActionBarButton);
|
||||
export default ActionBarButton;
|
||||
@@ -0,0 +1,13 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should render default slot correctly 1`] = `
|
||||
<button type="button"
|
||||
class="van-button van-button--default van-button--large van-action-bar-button"
|
||||
>
|
||||
<div class="van-button__content">
|
||||
<span class="van-button__text">
|
||||
Content
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
`;
|
||||
@@ -0,0 +1,11 @@
|
||||
import { mount } from '../../../test';
|
||||
import { ActionBarButton } from '..';
|
||||
|
||||
test('should render default slot correctly', () => {
|
||||
const wrapper = mount(ActionBarButton, {
|
||||
slots: {
|
||||
default: 'Content',
|
||||
},
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
@import '../style/var.less';
|
||||
|
||||
@action-bar-button-height: 40px;
|
||||
@action-bar-button-warning-color: var(--van-gradient-orange);
|
||||
@action-bar-button-danger-color: var(--van-gradient-red);
|
||||
@@ -0,0 +1,64 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { extend, createNamespace, unknownProp } from '../utils';
|
||||
import { ACTION_BAR_KEY } from '../action-bar/ActionBar';
|
||||
|
||||
// Composables
|
||||
import { useParent } from '@vant/use';
|
||||
import { useRoute, routeProps } from '../composables/use-route';
|
||||
|
||||
// Components
|
||||
import { Icon } from '../icon';
|
||||
import { Badge } from '../badge';
|
||||
|
||||
const [name, bem] = createNamespace('action-bar-icon');
|
||||
|
||||
export default defineComponent({
|
||||
name,
|
||||
|
||||
props: extend({}, routeProps, {
|
||||
dot: Boolean,
|
||||
text: String,
|
||||
icon: String,
|
||||
color: String,
|
||||
badge: [Number, String],
|
||||
iconClass: unknownProp,
|
||||
iconPrefix: String,
|
||||
}),
|
||||
|
||||
setup(props, { slots }) {
|
||||
const route = useRoute();
|
||||
|
||||
useParent(ACTION_BAR_KEY);
|
||||
|
||||
const renderIcon = () => {
|
||||
const { dot, badge, icon, color, iconClass, iconPrefix } = props;
|
||||
|
||||
if (slots.icon) {
|
||||
return (
|
||||
<Badge dot={dot} content={badge} class={bem('icon')}>
|
||||
{slots.icon()}
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Icon
|
||||
tag="div"
|
||||
dot={dot}
|
||||
name={icon}
|
||||
badge={badge}
|
||||
color={color}
|
||||
class={[bem('icon'), iconClass]}
|
||||
classPrefix={iconPrefix}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return () => (
|
||||
<div role="button" class={bem()} tabindex={0} onClick={route}>
|
||||
{renderIcon()}
|
||||
{slots.default ? slots.default() : props.text}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
@import './var.less';
|
||||
|
||||
:root {
|
||||
--van-action-bar-icon-width: @action-bar-icon-width;
|
||||
--van-action-bar-icon-height: @action-bar-icon-height;
|
||||
--van-action-bar-icon-color: @action-bar-icon-color;
|
||||
--van-action-bar-icon-size: @action-bar-icon-size;
|
||||
--van-action-bar-icon-font-size: @action-bar-icon-font-size;
|
||||
--van-action-bar-icon-active-color: @action-bar-icon-active-color;
|
||||
--van-action-bar-icon-text-color: @action-bar-icon-text-color;
|
||||
--van-action-bar-icon-background-color: @action-bar-icon-background-color;
|
||||
}
|
||||
|
||||
.van-action-bar-icon {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
min-width: var(--van-action-bar-icon-width);
|
||||
height: var(--van-action-bar-icon-height);
|
||||
color: var(--van-action-bar-icon-text-color);
|
||||
font-size: var(--van-action-bar-icon-font-size);
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
background-color: var(--van-action-bar-icon-background-color);
|
||||
cursor: pointer;
|
||||
|
||||
&:active {
|
||||
background-color: var(--van-action-bar-icon-active-color);
|
||||
}
|
||||
|
||||
&__icon {
|
||||
margin: 0 auto var(--van-padding-base);
|
||||
color: var(--van-action-bar-icon-color);
|
||||
font-size: var(--van-action-bar-icon-size);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { withInstall } from '../utils';
|
||||
import _ActionBarIcon from './ActionBarIcon';
|
||||
|
||||
export const ActionBarIcon = withInstall(_ActionBarIcon);
|
||||
export default ActionBarIcon;
|
||||
@@ -0,0 +1,63 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should render default slot correctly 1`] = `
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-icon van-icon-undefined van-action-bar-icon__icon">
|
||||
</div>
|
||||
Content
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should render icon slot correctly 1`] = `
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-action-bar-icon__icon">
|
||||
Custom Icon
|
||||
</div>
|
||||
Content
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should render icon slot with badge correctly 1`] = `
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-action-bar-icon__icon">
|
||||
Custom Icon
|
||||
<div class="van-badge van-badge--fixed">
|
||||
1
|
||||
</div>
|
||||
</div>
|
||||
Content
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should render icon slot with dot correctly 1`] = `
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-action-bar-icon__icon">
|
||||
Custom Icon
|
||||
<div class="van-badge van-badge--dot van-badge--fixed">
|
||||
</div>
|
||||
</div>
|
||||
Content
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should render icon-prefix correctly 1`] = `
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper my-icon my-icon-success van-action-bar-icon__icon">
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,61 @@
|
||||
import { mount } from '../../../test';
|
||||
import { ActionBarIcon } from '..';
|
||||
|
||||
test('should render default slot correctly', () => {
|
||||
const wrapper = mount(ActionBarIcon, {
|
||||
slots: {
|
||||
default: 'Content',
|
||||
},
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render icon slot correctly', () => {
|
||||
const wrapper = mount(ActionBarIcon, {
|
||||
slots: {
|
||||
default: 'Content',
|
||||
icon: 'Custom Icon',
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render icon-prefix correctly', () => {
|
||||
const wrapper = mount(ActionBarIcon, {
|
||||
props: {
|
||||
icon: 'success',
|
||||
iconPrefix: 'my-icon',
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render icon slot with badge correctly', () => {
|
||||
const wrapper = mount(ActionBarIcon, {
|
||||
props: {
|
||||
badge: '1',
|
||||
},
|
||||
slots: {
|
||||
default: 'Content',
|
||||
icon: 'Custom Icon',
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render icon slot with dot correctly', () => {
|
||||
const wrapper = mount(ActionBarIcon, {
|
||||
props: {
|
||||
dot: true,
|
||||
},
|
||||
slots: {
|
||||
default: 'Content',
|
||||
icon: 'Custom Icon',
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
@import '../style/var.less';
|
||||
|
||||
@action-bar-icon-width: 48px;
|
||||
@action-bar-icon-height: 100%;
|
||||
@action-bar-icon-color: var(--van-text-color);
|
||||
@action-bar-icon-size: 18px;
|
||||
@action-bar-icon-font-size: var(--van-font-size-xs);
|
||||
@action-bar-icon-active-color: var(--van-active-color);
|
||||
@action-bar-icon-text-color: var(--van-gray-7);
|
||||
@action-bar-icon-background-color: var(--van-white);
|
||||
@@ -0,0 +1,29 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { truthProp, createNamespace } from '../utils';
|
||||
import { useChildren } from '@vant/use';
|
||||
|
||||
const [name, bem] = createNamespace('action-bar');
|
||||
|
||||
export const ACTION_BAR_KEY = Symbol(name);
|
||||
|
||||
export default defineComponent({
|
||||
name,
|
||||
|
||||
props: {
|
||||
safeAreaInsetBottom: truthProp,
|
||||
},
|
||||
|
||||
setup(props, { slots }) {
|
||||
const { linkChildren } = useChildren(ACTION_BAR_KEY);
|
||||
|
||||
linkChildren();
|
||||
|
||||
return () => (
|
||||
<div
|
||||
class={[bem(), { 'van-safe-area-bottom': props.safeAreaInsetBottom }]}
|
||||
>
|
||||
{slots.default?.()}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,156 @@
|
||||
# ActionBar
|
||||
|
||||
### Intro
|
||||
|
||||
Used to provide convenient interaction for page-related operations.
|
||||
|
||||
### 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 { ActionBar, ActionBarIcon, ActionBarButton } from 'vant';
|
||||
|
||||
const app = createApp();
|
||||
app.use(ActionBar);
|
||||
app.use(ActionBarIcon);
|
||||
app.use(ActionBarButton);
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```html
|
||||
<van-action-bar>
|
||||
<van-action-bar-icon icon="chat-o" text="Icon1" @click="onClickIcon" />
|
||||
<van-action-bar-icon icon="cart-o" text="Icon2" @click="onClickIcon" />
|
||||
<van-action-bar-icon icon="shop-o" text="Icon3" @click="onClickIcon" />
|
||||
<van-action-bar-button type="danger" text="Button" @click="onClickButton" />
|
||||
</van-action-bar>
|
||||
```
|
||||
|
||||
```js
|
||||
import { Toast } from 'vant';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const onClickIcon = () => Toast('Click Icon');
|
||||
const onClickButton = () => Toast('Click Button');
|
||||
return {
|
||||
onClickIcon,
|
||||
onClickButton,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Icon Badge
|
||||
|
||||
Use `badge` prop to show badge in icon.
|
||||
|
||||
```html
|
||||
<van-action-bar>
|
||||
<van-action-bar-icon icon="chat-o" text="Icon1" dot />
|
||||
<van-action-bar-icon icon="cart-o" text="Icon2" badge="5" />
|
||||
<van-action-bar-icon icon="shop-o" text="Icon3" badge="12" />
|
||||
<van-action-bar-button type="warning" text="Button" />
|
||||
<van-action-bar-button type="danger" text="Button" />
|
||||
</van-action-bar>
|
||||
```
|
||||
|
||||
### Custom Icon Color
|
||||
|
||||
```html
|
||||
<van-action-bar>
|
||||
<van-action-bar-icon icon="chat-o" text="Icon1" color="#ee0a24" />
|
||||
<van-action-bar-icon icon="cart-o" text="Icon2" />
|
||||
<van-action-bar-icon icon="star" text="Collected" color="#ff5000" />
|
||||
<van-action-bar-button type="warning" text="Button" />
|
||||
<van-action-bar-button type="danger" text="Button" />
|
||||
</van-action-bar>
|
||||
```
|
||||
|
||||
### Custom Button Color
|
||||
|
||||
```html
|
||||
<van-action-bar>
|
||||
<van-action-bar-icon icon="chat-o" text="Icon1" />
|
||||
<van-action-bar-icon icon="shop-o" text="Icon2" />
|
||||
<van-action-bar-button color="#be99ff" type="warning" text="Button" />
|
||||
<van-action-bar-button color="#7232dd" type="danger" text="Button" />
|
||||
</van-action-bar>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### ActionBar Props
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| safe-area-inset-bottom | Whether to enable bottom safe area adaptation | _boolean_ | `true` |
|
||||
|
||||
### ActionBarIcon Props
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| text | Button text | _string_ | - |
|
||||
| icon | Icon | _string_ | - |
|
||||
| color | Icon color | _string_ | `#323233` |
|
||||
| icon-class | Icon class name | _string \| Array \| object_ | `''` |
|
||||
| icon-prefix `v3.0.17` | Icon className prefix | _string_ | `van-icon` |
|
||||
| dot | Whether to show red dot | _boolean_ | - |
|
||||
| badge | Content of the badge | _number \| string_ | - |
|
||||
| url | Link | _string_ | - |
|
||||
| to | Target route of the link, same as to of vue-router | _string \| object_ | - |
|
||||
| replace | If true, the navigation will not leave a history record | _boolean_ | `false` |
|
||||
|
||||
### ActionBarButton Props
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| text | Button text | _string_ | - |
|
||||
| type | Button type, Can be set to `primary` `info` `warning` `danger` | _string_ | `default` |
|
||||
| color | Button color, support linear-gradient | _string_ | - |
|
||||
| icon | Left Icon | _string_ | - |
|
||||
| disabled | Whether to disable button | _boolean_ | `false` |
|
||||
| loading | Whether show loading status | _boolean_ | `false` |
|
||||
| url | Link | _string_ | - |
|
||||
| to | Target route of the link, same as to of vue-router | _string \| object_ | - |
|
||||
| replace | If true, the navigation will not leave a history record | _boolean_ | `false` |
|
||||
|
||||
### ActionBarIcon Slots
|
||||
|
||||
| Name | Description |
|
||||
| ------- | ----------- |
|
||||
| default | Text |
|
||||
| icon | Custom icon |
|
||||
|
||||
### ActionBarButton Slots
|
||||
|
||||
| Name | Description |
|
||||
| ------- | -------------- |
|
||||
| default | Button content |
|
||||
|
||||
## Theming
|
||||
|
||||
### CSS Variables
|
||||
|
||||
The component provides the following CSS variables, which can be used to customize styles. Please refer to [ConfigProvider component](#/en-US/config-provider).
|
||||
|
||||
| Name | Default Value | Description |
|
||||
| --- | --- | --- |
|
||||
| --van-action-bar-background-color | _var(--van-white)_ | - |
|
||||
| --van-action-bar-height | _50px_ | - |
|
||||
| --van-action-bar-icon-width | _48px_ | - |
|
||||
| --van-action-bar-icon-height | _100%_ | - |
|
||||
| --van-action-bar-icon-color | _var(--van-text-color)_ | - |
|
||||
| --van-action-bar-icon-size | _18px_ | - |
|
||||
| --van-action-bar-icon-font-size | _var(--van-font-size-xs)_ | - |
|
||||
| --van-action-bar-icon-active-color | _var(--van-active-color)_ | - |
|
||||
| --van-action-bar-icon-text-color | _var(--van-gray-7)_ | - |
|
||||
| --van-action-bar-icon-background-color | _var(--van-white)_ | - |
|
||||
| --van-action-bar-button-height | _40px_ | - |
|
||||
| --van-action-bar-button-warning-color | _var(--van-gradient-orange)_ | - |
|
||||
| --van-action-bar-button-danger-color | _var(--van-gradient-red)_ | - |
|
||||
@@ -0,0 +1,160 @@
|
||||
# ActionBar 动作栏
|
||||
|
||||
### 介绍
|
||||
|
||||
用于为页面相关操作提供便捷交互。
|
||||
|
||||
### 引入
|
||||
|
||||
通过以下方式来全局注册组件,更多注册方式请参考[组件注册](#/zh-CN/advanced-usage#zu-jian-zhu-ce)。
|
||||
|
||||
```js
|
||||
import { createApp } from 'vue';
|
||||
import { ActionBar, ActionBarIcon, ActionBarButton } from 'vant';
|
||||
|
||||
const app = createApp();
|
||||
app.use(ActionBar);
|
||||
app.use(ActionBarIcon);
|
||||
app.use(ActionBarButton);
|
||||
```
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基础用法
|
||||
|
||||
```html
|
||||
<van-action-bar>
|
||||
<van-action-bar-icon icon="chat-o" text="客服" @click="onClickIcon" />
|
||||
<van-action-bar-icon icon="cart-o" text="购物车" @click="onClickIcon" />
|
||||
<van-action-bar-icon icon="shop-o" text="店铺" @click="onClickIcon" />
|
||||
<van-action-bar-button type="danger" text="立即购买" @click="onClickButton" />
|
||||
</van-action-bar>
|
||||
```
|
||||
|
||||
```js
|
||||
import { Toast } from 'vant';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const onClickIcon = () => Toast('点击图标');
|
||||
const onClickButton = () => Toast('点击按钮');
|
||||
return {
|
||||
onClickIcon,
|
||||
onClickButton,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 徽标提示
|
||||
|
||||
在 ActionBarIcon 组件上设置 `dot` 属性后,会在图标右上角展示一个小红点;设置 `badge` 属性后,会在图标右上角展示相应的徽标。
|
||||
|
||||
```html
|
||||
<van-action-bar>
|
||||
<van-action-bar-icon icon="chat-o" text="客服" dot />
|
||||
<van-action-bar-icon icon="cart-o" text="购物车" badge="5" />
|
||||
<van-action-bar-icon icon="shop-o" text="店铺" badge="12" />
|
||||
<van-action-bar-button type="warning" text="加入购物车" />
|
||||
<van-action-bar-button type="danger" text="立即购买" />
|
||||
</van-action-bar>
|
||||
```
|
||||
|
||||
### 自定义图标颜色
|
||||
|
||||
通过 ActionBarIcon 的 `color` 属性可以自定义图标的颜色。
|
||||
|
||||
```html
|
||||
<van-action-bar>
|
||||
<van-action-bar-icon icon="chat-o" text="客服" color="#ee0a24" />
|
||||
<van-action-bar-icon icon="cart-o" text="购物车" />
|
||||
<van-action-bar-icon icon="star" text="已收藏" color="#ff5000" />
|
||||
<van-action-bar-button type="warning" text="加入购物车" />
|
||||
<van-action-bar-button type="danger" text="立即购买" />
|
||||
</van-action-bar>
|
||||
```
|
||||
|
||||
### 自定义按钮颜色
|
||||
|
||||
通过 ActionBarButton 的 `color` 属性可以自定义按钮的颜色,支持传入 `linear-gradient` 渐变色。
|
||||
|
||||
```html
|
||||
<van-action-bar>
|
||||
<van-action-bar-icon icon="chat-o" text="客服" />
|
||||
<van-action-bar-icon icon="shop-o" text="店铺" />
|
||||
<van-action-bar-button color="#be99ff" type="warning" text="加入购物车" />
|
||||
<van-action-bar-button color="#7232dd" type="danger" text="立即购买" />
|
||||
</van-action-bar>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### ActionBar Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| safe-area-inset-bottom | 是否开启[底部安全区适配](#/zh-CN/advanced-usage#di-bu-an-quan-qu-gua-pei) | _boolean_ | `true` |
|
||||
|
||||
### ActionBarIcon Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| text | 按钮文字 | _string_ | - |
|
||||
| icon | 图标 | _string_ | - |
|
||||
| color | 图标颜色 | _string_ | `#323233` |
|
||||
| icon-class | 图标额外类名 | _string \| Array \| object_ | - |
|
||||
| icon-prefix `v3.0.17` | 图标类名前缀,等同于 Icon 组件的 [class-prefix 属性](#/zh-CN/icon#props) | _string_ | `van-icon` |
|
||||
| dot | 是否显示图标右上角小红点 | _boolean_ | `false` |
|
||||
| badge | 图标右上角徽标的内容 | _number \| string_ | - |
|
||||
| url | 点击后跳转的链接地址 | _string_ | - |
|
||||
| to | 点击后跳转的目标路由对象,等同于 vue-router 的 [to 属性](https://router.vuejs.org/zh/api/#to) | _string \| object_ | - |
|
||||
| replace | 是否在跳转时替换当前页面历史 | _boolean_ | `false` |
|
||||
|
||||
### ActionBarButton Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| text | 按钮文字 | _string_ | - |
|
||||
| type | 按钮类型,可选值为 `primary` `info` `warning` `danger` | _string_ | `default` |
|
||||
| color | 按钮颜色,支持传入 `linear-gradient` 渐变色 | _string_ | - |
|
||||
| icon | 左侧[图标名称](#/zh-CN/icon)或图片链接 | _string_ | - |
|
||||
| disabled | 是否禁用按钮 | _boolean_ | `false` |
|
||||
| loading | 是否显示为加载状态 | _boolean_ | `false` |
|
||||
| url | 点击后跳转的链接地址 | _string_ | - |
|
||||
| to | 点击后跳转的目标路由对象,等同于 vue-router 的 [to 属性](https://router.vuejs.org/zh/api/#to) | _string \| object_ | - |
|
||||
| replace | 是否在跳转时替换当前页面历史 | _boolean_ | `false` |
|
||||
|
||||
### ActionBarIcon Slots
|
||||
|
||||
| 名称 | 说明 |
|
||||
| ------- | ---------- |
|
||||
| default | 文本内容 |
|
||||
| icon | 自定义图标 |
|
||||
|
||||
### ActionBarButton Slots
|
||||
|
||||
| 名称 | 说明 |
|
||||
| ------- | ------------ |
|
||||
| default | 按钮显示内容 |
|
||||
|
||||
## 主题定制
|
||||
|
||||
### 样式变量
|
||||
|
||||
组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 [ConfigProvider 组件](#/zh-CN/config-provider)。
|
||||
|
||||
| 名称 | 默认值 | 描述 |
|
||||
| -------------------------------------- | ---------------------------- | ---- |
|
||||
| --van-action-bar-background-color | _var(--van-white)_ | - |
|
||||
| --van-action-bar-height | _50px_ | - |
|
||||
| --van-action-bar-icon-width | _48px_ | - |
|
||||
| --van-action-bar-icon-height | _100%_ | - |
|
||||
| --van-action-bar-icon-color | _var(--van-text-color)_ | - |
|
||||
| --van-action-bar-icon-size | _18px_ | - |
|
||||
| --van-action-bar-icon-font-size | _var(--van-font-size-xs)_ | - |
|
||||
| --van-action-bar-icon-active-color | _var(--van-active-color)_ | - |
|
||||
| --van-action-bar-icon-text-color | _var(--van-gray-7)_ | - |
|
||||
| --van-action-bar-icon-background-color | _var(--van-white)_ | - |
|
||||
| --van-action-bar-button-height | _40px_ | - |
|
||||
| --van-action-bar-button-warning-color | _var(--van-gradient-orange)_ | - |
|
||||
| --van-action-bar-button-danger-color | _var(--van-gradient-red)_ | - |
|
||||
@@ -0,0 +1,108 @@
|
||||
<script setup lang="ts">
|
||||
import { useTranslate } from '@demo/use-translate';
|
||||
import { Toast } from '../../toast';
|
||||
|
||||
const t = useTranslate({
|
||||
'zh-CN': {
|
||||
icon1: '客服',
|
||||
icon2: '购物车',
|
||||
icon3: '店铺',
|
||||
button1: '加入购物车',
|
||||
button2: '立即购买',
|
||||
iconBadge: '徽标提示',
|
||||
collected: '已收藏',
|
||||
clickIcon: '点击图标',
|
||||
clickButton: '点击按钮',
|
||||
customIconColor: '自定义图标颜色',
|
||||
customButtonColor: '自定义按钮颜色',
|
||||
},
|
||||
'en-US': {
|
||||
icon1: 'Icon1',
|
||||
icon2: 'Icon2',
|
||||
icon3: 'Icon3',
|
||||
button1: 'Button',
|
||||
button2: 'Button',
|
||||
iconBadge: 'Icon Badge',
|
||||
collected: 'Collected',
|
||||
clickIcon: 'Click Icon',
|
||||
clickButton: 'Click Button',
|
||||
customIconColor: 'Custom Icon Color',
|
||||
customButtonColor: 'Custom Button Color',
|
||||
},
|
||||
});
|
||||
const onClickIcon = () => Toast(t('clickIcon'));
|
||||
const onClickButton = () => Toast(t('clickButton'));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<demo-block :title="t('basicUsage')">
|
||||
<van-action-bar>
|
||||
<van-action-bar-icon
|
||||
icon="chat-o"
|
||||
:text="t('icon1')"
|
||||
@click="onClickIcon"
|
||||
/>
|
||||
<van-action-bar-icon
|
||||
icon="cart-o"
|
||||
:text="t('icon2')"
|
||||
@click="onClickIcon"
|
||||
/>
|
||||
<van-action-bar-icon
|
||||
icon="shop-o"
|
||||
:text="t('icon3')"
|
||||
@click="onClickIcon"
|
||||
/>
|
||||
<van-action-bar-button
|
||||
type="danger"
|
||||
:text="t('button2')"
|
||||
@click="onClickButton"
|
||||
/>
|
||||
</van-action-bar>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="t('iconBadge')">
|
||||
<van-action-bar>
|
||||
<van-action-bar-icon icon="chat-o" dot :text="t('icon1')" />
|
||||
<van-action-bar-icon icon="cart-o" badge="5" :text="t('icon2')" />
|
||||
<van-action-bar-icon icon="shop-o" badge="12" :text="t('icon3')" />
|
||||
<van-action-bar-button type="warning" :text="t('button1')" />
|
||||
<van-action-bar-button type="danger" :text="t('button2')" />
|
||||
</van-action-bar>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="t('customIconColor')">
|
||||
<van-action-bar>
|
||||
<van-action-bar-icon icon="chat-o" :text="t('icon1')" color="#ee0a24" />
|
||||
<van-action-bar-icon icon="cart-o" :text="t('icon2')" />
|
||||
<van-action-bar-icon icon="star" :text="t('collected')" color="#ff5000" />
|
||||
<van-action-bar-button type="warning" :text="t('button1')" />
|
||||
<van-action-bar-button type="danger" :text="t('button2')" />
|
||||
</van-action-bar>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="t('customButtonColor')">
|
||||
<van-action-bar>
|
||||
<van-action-bar-icon icon="chat-o" :text="t('icon1')" />
|
||||
<van-action-bar-icon icon="cart-o" :text="t('icon2')" />
|
||||
<van-action-bar-button
|
||||
color="#be99ff"
|
||||
type="warning"
|
||||
:text="t('button1')"
|
||||
/>
|
||||
<van-action-bar-button
|
||||
color="#7232dd"
|
||||
type="danger"
|
||||
:text="t('button2')"
|
||||
/>
|
||||
</van-action-bar>
|
||||
</demo-block>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.demo-action-bar {
|
||||
.van-action-bar {
|
||||
position: relative;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,18 @@
|
||||
@import './var.less';
|
||||
|
||||
:root {
|
||||
--van-action-bar-background-color: @action-bar-background-color;
|
||||
--van-action-bar-height: @action-bar-height;
|
||||
}
|
||||
|
||||
.van-action-bar {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-sizing: content-box;
|
||||
height: var(--van-action-bar-height);
|
||||
background-color: var(--van-action-bar-background-color);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { withInstall } from '../utils';
|
||||
import _ActionBar from './ActionBar';
|
||||
|
||||
export const ActionBar = withInstall(_ActionBar);
|
||||
export default ActionBar;
|
||||
@@ -0,0 +1,185 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should render demo and match snapshot 1`] = `
|
||||
<div>
|
||||
<div class="van-action-bar van-safe-area-bottom">
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-icon van-icon-chat-o van-action-bar-icon__icon">
|
||||
</div>
|
||||
Icon1
|
||||
</div>
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-icon van-icon-cart-o van-action-bar-icon__icon">
|
||||
</div>
|
||||
Icon2
|
||||
</div>
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-icon van-icon-shop-o van-action-bar-icon__icon">
|
||||
</div>
|
||||
Icon3
|
||||
</div>
|
||||
<button type="button"
|
||||
class="van-button van-button--danger van-button--large van-action-bar-button van-action-bar-button--danger van-action-bar-button--last van-action-bar-button--first"
|
||||
>
|
||||
<div class="van-button__content">
|
||||
<span class="van-button__text">
|
||||
Button
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-action-bar van-safe-area-bottom">
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-icon van-icon-chat-o van-action-bar-icon__icon">
|
||||
<div class="van-badge van-badge--dot van-badge--fixed">
|
||||
</div>
|
||||
</div>
|
||||
Icon1
|
||||
</div>
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-icon van-icon-cart-o van-action-bar-icon__icon">
|
||||
<div class="van-badge van-badge--fixed">
|
||||
5
|
||||
</div>
|
||||
</div>
|
||||
Icon2
|
||||
</div>
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-icon van-icon-shop-o van-action-bar-icon__icon">
|
||||
<div class="van-badge van-badge--fixed">
|
||||
12
|
||||
</div>
|
||||
</div>
|
||||
Icon3
|
||||
</div>
|
||||
<button type="button"
|
||||
class="van-button van-button--warning van-button--large van-action-bar-button van-action-bar-button--warning van-action-bar-button--first"
|
||||
>
|
||||
<div class="van-button__content">
|
||||
<span class="van-button__text">
|
||||
Button
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="van-button van-button--danger van-button--large van-action-bar-button van-action-bar-button--danger van-action-bar-button--last"
|
||||
>
|
||||
<div class="van-button__content">
|
||||
<span class="van-button__text">
|
||||
Button
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-action-bar van-safe-area-bottom">
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-icon van-icon-chat-o van-action-bar-icon__icon"
|
||||
style="color: rgb(238, 10, 36);"
|
||||
>
|
||||
</div>
|
||||
Icon1
|
||||
</div>
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-icon van-icon-cart-o van-action-bar-icon__icon">
|
||||
</div>
|
||||
Icon2
|
||||
</div>
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-icon van-icon-star van-action-bar-icon__icon"
|
||||
style="color: rgb(255, 80, 0);"
|
||||
>
|
||||
</div>
|
||||
Collected
|
||||
</div>
|
||||
<button type="button"
|
||||
class="van-button van-button--warning van-button--large van-action-bar-button van-action-bar-button--warning van-action-bar-button--first"
|
||||
>
|
||||
<div class="van-button__content">
|
||||
<span class="van-button__text">
|
||||
Button
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="van-button van-button--danger van-button--large van-action-bar-button van-action-bar-button--danger van-action-bar-button--last"
|
||||
>
|
||||
<div class="van-button__content">
|
||||
<span class="van-button__text">
|
||||
Button
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-action-bar van-safe-area-bottom">
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-icon van-icon-chat-o van-action-bar-icon__icon">
|
||||
</div>
|
||||
Icon1
|
||||
</div>
|
||||
<div role="button"
|
||||
class="van-action-bar-icon"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-badge__wrapper van-icon van-icon-cart-o van-action-bar-icon__icon">
|
||||
</div>
|
||||
Icon2
|
||||
</div>
|
||||
<button type="button"
|
||||
class="van-button van-button--warning van-button--large van-action-bar-button van-action-bar-button--warning van-action-bar-button--first"
|
||||
style="color: white; border-color: #be99ff; background: rgb(190, 153, 255);"
|
||||
>
|
||||
<div class="van-button__content">
|
||||
<span class="van-button__text">
|
||||
Button
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="van-button van-button--danger van-button--large van-action-bar-button van-action-bar-button--danger van-action-bar-button--last"
|
||||
style="color: white; background: rgb(114, 50, 221); border-color: #7232dd;"
|
||||
>
|
||||
<div class="van-button__content">
|
||||
<span class="van-button__text">
|
||||
Button
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should allow to disable safe-area-inset-bottom prop 1`] = `
|
||||
<div class="van-action-bar">
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,4 @@
|
||||
import Demo from '../demo/index.vue';
|
||||
import { snapshotDemo } from '../../../test/demo';
|
||||
|
||||
snapshotDemo(Demo);
|
||||
@@ -0,0 +1,12 @@
|
||||
import { ActionBar } from '..';
|
||||
import { mount } from '../../../test';
|
||||
|
||||
test('should allow to disable safe-area-inset-bottom prop', () => {
|
||||
const wrapper = mount(ActionBar, {
|
||||
props: {
|
||||
safeAreaInsetBottom: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
@import '../style/var.less';
|
||||
|
||||
@action-bar-background-color: var(--van-white);
|
||||
@action-bar-height: 50px;
|
||||
@@ -0,0 +1,156 @@
|
||||
import { nextTick, PropType, defineComponent } from 'vue';
|
||||
|
||||
// Utils
|
||||
import { pick, extend, truthProp, createNamespace } from '../utils';
|
||||
|
||||
// Components
|
||||
import { Icon } from '../icon';
|
||||
import { Popup } from '../popup';
|
||||
import { Loading } from '../loading';
|
||||
import { popupSharedProps, popupSharedPropKeys } from '../popup/shared';
|
||||
|
||||
const [name, bem] = createNamespace('action-sheet');
|
||||
|
||||
export type ActionSheetAction = {
|
||||
name?: string;
|
||||
color?: string;
|
||||
subname?: string;
|
||||
loading?: boolean;
|
||||
disabled?: boolean;
|
||||
callback?: (action: ActionSheetAction) => void;
|
||||
className?: unknown;
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name,
|
||||
|
||||
props: extend({}, popupSharedProps, {
|
||||
title: String,
|
||||
round: truthProp,
|
||||
actions: Array as PropType<ActionSheetAction[]>,
|
||||
closeable: truthProp,
|
||||
cancelText: String,
|
||||
description: String,
|
||||
closeOnPopstate: Boolean,
|
||||
closeOnClickAction: Boolean,
|
||||
safeAreaInsetBottom: truthProp,
|
||||
closeIcon: {
|
||||
type: String,
|
||||
default: 'cross',
|
||||
},
|
||||
}),
|
||||
|
||||
emits: ['select', 'cancel', 'update:show'],
|
||||
|
||||
setup(props, { slots, emit }) {
|
||||
const updateShow = (show: boolean) => emit('update:show', show);
|
||||
|
||||
const onCancel = () => {
|
||||
updateShow(false);
|
||||
emit('cancel');
|
||||
};
|
||||
|
||||
const renderHeader = () => {
|
||||
if (props.title) {
|
||||
return (
|
||||
<div class={bem('header')}>
|
||||
{props.title}
|
||||
{props.closeable && (
|
||||
<Icon
|
||||
name={props.closeIcon}
|
||||
class={bem('close')}
|
||||
onClick={onCancel}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const renderCancel = () => {
|
||||
if (slots.cancel || props.cancelText) {
|
||||
return [
|
||||
<div class={bem('gap')} />,
|
||||
<button type="button" class={bem('cancel')} onClick={onCancel}>
|
||||
{slots.cancel ? slots.cancel() : props.cancelText}
|
||||
</button>,
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
const renderOption = (item: ActionSheetAction, index: number) => {
|
||||
const { name, color, subname, loading, callback, disabled, className } =
|
||||
item;
|
||||
|
||||
const Content = loading ? (
|
||||
<Loading class={bem('loading-icon')} />
|
||||
) : (
|
||||
[
|
||||
<span class={bem('name')}>{name}</span>,
|
||||
subname && <div class={bem('subname')}>{subname}</div>,
|
||||
]
|
||||
);
|
||||
|
||||
const onClick = () => {
|
||||
if (disabled || loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback(item);
|
||||
}
|
||||
|
||||
if (props.closeOnClickAction) {
|
||||
updateShow(false);
|
||||
}
|
||||
|
||||
nextTick(() => emit('select', item, index));
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
style={{ color }}
|
||||
class={[bem('item', { loading, disabled }), className]}
|
||||
onClick={onClick}
|
||||
>
|
||||
{Content}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
const renderDescription = () => {
|
||||
if (props.description || slots.description) {
|
||||
const content = slots.description
|
||||
? slots.description()
|
||||
: props.description;
|
||||
return <div class={bem('description')}>{content}</div>;
|
||||
}
|
||||
};
|
||||
|
||||
const renderOptions = () => {
|
||||
if (props.actions) {
|
||||
return props.actions.map(renderOption);
|
||||
}
|
||||
};
|
||||
|
||||
return () => (
|
||||
<Popup
|
||||
class={bem()}
|
||||
round={props.round}
|
||||
position="bottom"
|
||||
safeAreaInsetBottom={props.safeAreaInsetBottom}
|
||||
{...pick(props, popupSharedPropKeys)}
|
||||
{...{ 'onUpdate:show': updateShow }}
|
||||
>
|
||||
{renderHeader()}
|
||||
{renderDescription()}
|
||||
<div class={bem('content')}>
|
||||
{renderOptions()}
|
||||
{slots.default?.()}
|
||||
</div>
|
||||
{renderCancel()}
|
||||
</Popup>
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,264 @@
|
||||
# ActionSheet
|
||||
|
||||
### Intro
|
||||
|
||||
The pop-up modal panel at the bottom contains multiple options related to the current situation.
|
||||
|
||||
### 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 { ActionSheet } from 'vant';
|
||||
|
||||
const app = createApp();
|
||||
app.use(ActionSheet);
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Use `actions` prop to set options of action-sheet.
|
||||
|
||||
```html
|
||||
<van-cell is-link title="Basic Usage" @click="show = true" />
|
||||
<van-action-sheet v-model:show="show" :actions="actions" @select="onSelect" />
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { Toast } from 'vant';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const show = ref(false);
|
||||
const actions = [
|
||||
{ name: 'Option 1' },
|
||||
{ name: 'Option 2' },
|
||||
{ name: 'Option 3' },
|
||||
];
|
||||
const onSelect = (item) => {
|
||||
show.value = false;
|
||||
Toast(item.name);
|
||||
};
|
||||
|
||||
return {
|
||||
show,
|
||||
actions,
|
||||
onSelect,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Show Cancel Button
|
||||
|
||||
```html
|
||||
<van-action-sheet
|
||||
v-model:show="show"
|
||||
:actions="actions"
|
||||
cancel-text="Cancel"
|
||||
close-on-click-action
|
||||
@cancel="onCancel"
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { Toast } from 'vant';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const show = ref(false);
|
||||
const actions = [
|
||||
{ name: 'Option 1' },
|
||||
{ name: 'Option 2' },
|
||||
{ name: 'Option 3' },
|
||||
];
|
||||
const onCancel = () => Toast('cancel');
|
||||
|
||||
return {
|
||||
show,
|
||||
actions,
|
||||
onCancel,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Show Description
|
||||
|
||||
```html
|
||||
<van-action-sheet
|
||||
v-model:show="show"
|
||||
:actions="actions"
|
||||
cancel-text="Cancel"
|
||||
description="Description"
|
||||
close-on-click-action
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const show = ref(false);
|
||||
const actions = [
|
||||
{ name: 'Option 1' },
|
||||
{ name: 'Option 2' },
|
||||
{ name: 'Option 3', subname: 'Description' },
|
||||
];
|
||||
|
||||
return {
|
||||
show,
|
||||
actions,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Option Status
|
||||
|
||||
```html
|
||||
<van-action-sheet
|
||||
v-model:show="show"
|
||||
:actions="actions"
|
||||
cancel-text="Cancel"
|
||||
close-on-click-action
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const show = ref(false);
|
||||
const actions = [
|
||||
{ name: 'Colored Option', color: '#ee0a24' },
|
||||
{ name: 'Disabled Option', disabled: true },
|
||||
{ name: 'Loading Option', loading: true },
|
||||
];
|
||||
|
||||
return {
|
||||
show,
|
||||
actions,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Custom Panel
|
||||
|
||||
```html
|
||||
<van-action-sheet v-model:show="show" title="Title">
|
||||
<div class="content">Content</div>
|
||||
</van-action-sheet>
|
||||
|
||||
<style>
|
||||
.content {
|
||||
padding: 16px 16px 160px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| v-model:show | Whether to show ActionSheet | _boolean_ | `false` |
|
||||
| actions | Options | _ActionSheetAction[]_ | `[]` |
|
||||
| title | Title | _string_ | - |
|
||||
| cancel-text | Text of cancel button | _string_ | - |
|
||||
| description | Description above the options | _string_ | - |
|
||||
| closeable | Whether to show close icon | _boolean_ | `true` |
|
||||
| close-icon | Close icon name | _string_ | `cross` |
|
||||
| duration | Transition duration, unit second | _number \| string_ | `0.3` |
|
||||
| round | Whether to show round corner | _boolean_ | `true` |
|
||||
| overlay | Whether to show overlay | _boolean_ | `true` |
|
||||
| overlay-class | Custom overlay class | _string \| Array \| object_ | - |
|
||||
| overlay-style | Custom overlay style | _object_ | - |
|
||||
| lock-scroll | Whether to lock background scroll | _boolean_ | `true` |
|
||||
| lazy-render | Whether to lazy render util appeared | _boolean_ | `true` |
|
||||
| close-on-popstate | Whether to close when popstate | _boolean_ | `false` |
|
||||
| close-on-click-action | Whether to close when an action is clicked | _boolean_ | `false` |
|
||||
| close-on-click-overlay | Whether to close when overlay is clicked | _boolean_ | `true` |
|
||||
| safe-area-inset-bottom | Whether to enable bottom safe area adaptation | _boolean_ | `true` |
|
||||
| teleport | Specifies a target element where ActionSheet will be mounted | _string \| Element_ | - |
|
||||
| before-close `v3.1.4` | Callback function before close | _(action: string) => boolean \| Promise\<boolean\>_ | - |
|
||||
|
||||
### Data Structure of ActionSheetAction
|
||||
|
||||
| Key | Description | Type |
|
||||
| --------- | ------------------------------- | --------------------------- |
|
||||
| name | Title | _string_ |
|
||||
| subname | Subtitle | _string_ |
|
||||
| color | Text color | _string_ |
|
||||
| className | className for the option | _string \| Array \| object_ |
|
||||
| loading | Whether to be loading status | _boolean_ |
|
||||
| disabled | Whether to be disabled | _boolean_ |
|
||||
| callback | Callback function after clicked | _action: ActionSheetAction_ |
|
||||
|
||||
### Events
|
||||
|
||||
| Event | Description | Arguments |
|
||||
| --- | --- | --- |
|
||||
| select | Emitted when an option is clicked | _action: ActionSheetAction, index: number_ |
|
||||
| cancel | Emitted when the cancel button is clicked | - |
|
||||
| open | Emitted when opening ActionSheet | - |
|
||||
| close | Emitted when closing ActionSheet | - |
|
||||
| opened | Emitted when ActionSheet is opened | - |
|
||||
| closed | Emitted when ActionSheet is closed | - |
|
||||
| click-overlay | Emitted when overlay is clicked | _event: MouseEvent_ |
|
||||
|
||||
### Slots
|
||||
|
||||
| Name | Description |
|
||||
| ---------------- | ------------------------------------ |
|
||||
| default | Custom content |
|
||||
| description | Custom description above the options |
|
||||
| cancel `v3.0.10` | Custom the content of cancel button |
|
||||
|
||||
### Types
|
||||
|
||||
The component exports the following type definitions:
|
||||
|
||||
```ts
|
||||
import type { ActionSheetAction } from 'vant';
|
||||
```
|
||||
|
||||
## Theming
|
||||
|
||||
### CSS Variables
|
||||
|
||||
The component provides the following CSS variables, which can be used to customize styles. Please refer to [ConfigProvider component](#/en-US/config-provider).
|
||||
|
||||
| Name | Default Value | Description |
|
||||
| --- | --- | --- |
|
||||
| --van-action-sheet-max-height | _80%_ | - |
|
||||
| --van-action-sheet-header-height | _48px_ | - |
|
||||
| --van-action-sheet-header-font-size | _var(--van-font-size-lg)_ | - |
|
||||
| --van-action-sheet-description-color | _var(--van-gray-6)_ | - |
|
||||
| --van-action-sheet-description-font-size | _var(--van-font-size-md)_ | - |
|
||||
| --van-action-sheet-description-line-height | _var(--van-line-height-md)_ | - |
|
||||
| --van-action-sheet-item-background | _var(--van-white)_ | - |
|
||||
| --van-action-sheet-item-font-size | _var(--van-font-size-lg)_ | - |
|
||||
| --van-action-sheet-item-line-height | _var(--van-line-height-lg)_ | - |
|
||||
| --van-action-sheet-item-text-color | _var(--van-text-color)_ | - |
|
||||
| --van-action-sheet-item-disabled-text-color | _var(--van-gray-5)_ | - |
|
||||
| --van-action-sheet-subname-color | _var(--van-gray-6)_ | - |
|
||||
| --van-action-sheet-subname-font-size | _var(--van-font-size-sm)_ | - |
|
||||
| --van-action-sheet-subname-line-height | _var(--van-line-height-sm)_ | - |
|
||||
| --van-action-sheet-close-icon-size | _22px_ | - |
|
||||
| --van-action-sheet-close-icon-color | _var(--van-gray-5)_ | - |
|
||||
| --van-action-sheet-close-icon-active-color | _var(--van-gray-6)_ | - |
|
||||
| --van-action-sheet-close-icon-padding | _0 var(--van-padding-md)_ | - |
|
||||
| --van-action-sheet-cancel-text-color | _var(--van-gray-7)_ | - |
|
||||
| --van-action-sheet-cancel-padding-top | _var(--van-padding-xs)_ | - |
|
||||
| --van-action-sheet-cancel-padding-color | _var(--van-background-color)_ | - |
|
||||
| --van-action-sheet-loading-icon-size | _22px_ | - |
|
||||
@@ -0,0 +1,276 @@
|
||||
# ActionSheet 动作面板
|
||||
|
||||
### 介绍
|
||||
|
||||
底部弹起的模态面板,包含与当前情境相关的多个选项。
|
||||
|
||||
### 引入
|
||||
|
||||
通过以下方式来全局注册组件,更多注册方式请参考[组件注册](#/zh-CN/advanced-usage#zu-jian-zhu-ce)。
|
||||
|
||||
```js
|
||||
import { createApp } from 'vue';
|
||||
import { ActionSheet } from 'vant';
|
||||
|
||||
const app = createApp();
|
||||
app.use(ActionSheet);
|
||||
```
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基础用法
|
||||
|
||||
动作面板通过 `actions` 属性来定义选项,`actions` 属性是一个由对象构成的数组,数组中的每个对象配置一列,对象格式见文档下方表格。
|
||||
|
||||
```html
|
||||
<van-cell is-link title="基础用法" @click="show = true" />
|
||||
<van-action-sheet v-model:show="show" :actions="actions" @select="onSelect" />
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { Toast } from 'vant';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const show = ref(false);
|
||||
const actions = [
|
||||
{ name: '选项一' },
|
||||
{ name: '选项二' },
|
||||
{ name: '选项三' },
|
||||
];
|
||||
const onSelect = (item) => {
|
||||
// 默认情况下点击选项时不会自动收起
|
||||
// 可以通过 close-on-click-action 属性开启自动收起
|
||||
show.value = false;
|
||||
Toast(item.name);
|
||||
};
|
||||
|
||||
return {
|
||||
show,
|
||||
actions,
|
||||
onSelect,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 展示取消按钮
|
||||
|
||||
设置 `cancel-text` 属性后,会在底部展示取消按钮,点击后关闭当前面板并触发 `cancel` 事件。
|
||||
|
||||
```html
|
||||
<van-action-sheet
|
||||
v-model:show="show"
|
||||
:actions="actions"
|
||||
cancel-text="取消"
|
||||
close-on-click-action
|
||||
@cancel="onCancel"
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { Toast } from 'vant';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const show = ref(false);
|
||||
const actions = [
|
||||
{ name: '选项一' },
|
||||
{ name: '选项二' },
|
||||
{ name: '选项三' },
|
||||
];
|
||||
const onCancel = () => Toast('取消');
|
||||
|
||||
return {
|
||||
show,
|
||||
actions,
|
||||
onCancel,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 展示描述信息
|
||||
|
||||
通过 `description` 可以在菜单顶部显示描述信息,通过选项的 `subname` 属性可以在选项文字的右侧展示描述信息。
|
||||
|
||||
```html
|
||||
<van-action-sheet
|
||||
v-model:show="show"
|
||||
:actions="actions"
|
||||
cancel-text="取消"
|
||||
description="这是一段描述信息"
|
||||
close-on-click-action
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const show = ref(false);
|
||||
const actions = [
|
||||
{ name: '选项一' },
|
||||
{ name: '选项二' },
|
||||
{ name: '选项三', subname: '描述信息' },
|
||||
];
|
||||
|
||||
return {
|
||||
show,
|
||||
actions,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 选项状态
|
||||
|
||||
可以通过 `loading` 和 `disabled` 将选项设置为加载状态或禁用状态,或者通过`color`设置选项的颜色
|
||||
|
||||
```html
|
||||
<van-action-sheet
|
||||
v-model:show="show"
|
||||
:actions="actions"
|
||||
cancel-text="取消"
|
||||
close-on-click-action
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const show = ref(false);
|
||||
const actions = [
|
||||
{ name: '着色选项', color: '#ee0a24' },
|
||||
{ name: '禁用选项', disabled: true },
|
||||
{ name: '加载选项', loading: true },
|
||||
];
|
||||
|
||||
return {
|
||||
show,
|
||||
actions,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### 自定义面板
|
||||
|
||||
通过插槽可以自定义面板的展示内容,同时可以使用`title`属性展示标题栏
|
||||
|
||||
```html
|
||||
<van-action-sheet v-model:show="show" title="标题">
|
||||
<div class="content">内容</div>
|
||||
</van-action-sheet>
|
||||
|
||||
<style>
|
||||
.content {
|
||||
padding: 16px 16px 160px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| v-model:show | 是否显示动作面板 | _boolean_ | `false` |
|
||||
| actions | 面板选项列表 | _ActionSheetAction[]_ | `[]` |
|
||||
| title | 顶部标题 | _string_ | - |
|
||||
| cancel-text | 取消按钮文字 | _string_ | - |
|
||||
| description | 选项上方的描述信息 | _string_ | - |
|
||||
| closeable | 是否显示关闭图标 | _boolean_ | `true` |
|
||||
| close-icon | 关闭[图标名称](#/zh-CN/icon)或图片链接 | _string_ | `cross` |
|
||||
| duration | 动画时长,单位秒,设置为 0 可以禁用动画 | _number \| string_ | `0.3` |
|
||||
| round | 是否显示圆角 | _boolean_ | `true` |
|
||||
| overlay | 是否显示遮罩层 | _boolean_ | `true` |
|
||||
| overlay-class | 自定义遮罩层类名 | _string \| Array \| object_ | - |
|
||||
| overlay-style | 自定义遮罩层样式 | _object_ | - |
|
||||
| lock-scroll | 是否锁定背景滚动 | _boolean_ | `true` |
|
||||
| lazy-render | 是否在显示弹层时才渲染节点 | _boolean_ | `true` |
|
||||
| close-on-popstate | 是否在页面回退时自动关闭 | _boolean_ | `false` |
|
||||
| close-on-click-action | 是否在点击选项后关闭 | _boolean_ | `false` |
|
||||
| close-on-click-overlay | 是否在点击遮罩层后关闭 | _boolean_ | `true` |
|
||||
| safe-area-inset-bottom | 是否开启[底部安全区适配](#/zh-CN/advanced-usage#di-bu-an-quan-qu-gua-pei) | _boolean_ | `true` |
|
||||
| teleport | 指定挂载的节点,等同于 Teleport 组件的 [to 属性](https://v3.cn.vuejs.org/api/built-in-components.html#teleport) | _string \| Element_ | - |
|
||||
| before-close `v3.1.4` | 关闭前的回调函数,返回 `false` 可阻止关闭,支持返回 Promise | _(action: string) => boolean \| Promise\<boolean\>_ | - |
|
||||
|
||||
### Action 数据结构
|
||||
|
||||
`actions` 属性是一个由对象构成的数组,数组中的每个对象配置一列,对象可以包含以下值:
|
||||
|
||||
| 键名 | 说明 | 类型 |
|
||||
| --------- | ------------------------ | --------------------------- |
|
||||
| name | 标题 | _string_ |
|
||||
| subname | 二级标题 | _string_ |
|
||||
| color | 选项文字颜色 | _string_ |
|
||||
| className | 为对应列添加额外的 class | _string \| Array \| object_ |
|
||||
| loading | 是否为加载状态 | _boolean_ |
|
||||
| disabled | 是否为禁用状态 | _boolean_ |
|
||||
| callback | 点击时触发的回调函数 | _action: ActionSheetAction_ |
|
||||
|
||||
### Events
|
||||
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
| --- | --- | --- |
|
||||
| select | 点击选项时触发,禁用或加载状态下不会触发 | _action: ActionSheetAction, index: number_ |
|
||||
| cancel | 点击取消按钮时触发 | - |
|
||||
| open | 打开面板时触发 | - |
|
||||
| close | 关闭面板时触发 | - |
|
||||
| opened | 打开面板且动画结束后触发 | - |
|
||||
| closed | 关闭面板且动画结束后触发 | - |
|
||||
| click-overlay | 点击遮罩层时触发 | _event: MouseEvent_ |
|
||||
|
||||
### Slots
|
||||
|
||||
| 名称 | 说明 |
|
||||
| ---------------- | -------------------- |
|
||||
| default | 自定义面板的展示内容 |
|
||||
| description | 自定义描述文案 |
|
||||
| cancel `v3.0.10` | 自定义取消按钮内容 |
|
||||
|
||||
### 类型定义
|
||||
|
||||
组件导出以下类型定义:
|
||||
|
||||
```ts
|
||||
import type { ActionSheetAction } from 'vant';
|
||||
```
|
||||
|
||||
## 主题定制
|
||||
|
||||
### 样式变量
|
||||
|
||||
组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 [ConfigProvider 组件](#/zh-CN/config-provider)。
|
||||
|
||||
| 名称 | 默认值 | 描述 |
|
||||
| --- | --- | --- |
|
||||
| --van-action-sheet-max-height | _80%_ | - |
|
||||
| --van-action-sheet-header-height | _48px_ | - |
|
||||
| --van-action-sheet-header-font-size | _var(--van-font-size-lg)_ | - |
|
||||
| --van-action-sheet-description-color | _var(--van-gray-6)_ | - |
|
||||
| --van-action-sheet-description-font-size | _var(--van-font-size-md)_ | - |
|
||||
| --van-action-sheet-description-line-height | _var(--van-line-height-md)_ | - |
|
||||
| --van-action-sheet-item-background | _var(--van-white)_ | - |
|
||||
| --van-action-sheet-item-font-size | _var(--van-font-size-lg)_ | - |
|
||||
| --van-action-sheet-item-line-height | _var(--van-line-height-lg)_ | - |
|
||||
| --van-action-sheet-item-text-color | _var(--van-text-color)_ | - |
|
||||
| --van-action-sheet-item-disabled-text-color | _var(--van-gray-5)_ | - |
|
||||
| --van-action-sheet-subname-color | _var(--van-gray-6)_ | - |
|
||||
| --van-action-sheet-subname-font-size | _var(--van-font-size-sm)_ | - |
|
||||
| --van-action-sheet-subname-line-height | _var(--van-line-height-sm)_ | - |
|
||||
| --van-action-sheet-close-icon-size | _22px_ | - |
|
||||
| --van-action-sheet-close-icon-color | _var(--van-gray-5)_ | - |
|
||||
| --van-action-sheet-close-icon-active-color | _var(--van-gray-6)_ | - |
|
||||
| --van-action-sheet-close-icon-padding | _0 var(--van-padding-md)_ | - |
|
||||
| --van-action-sheet-cancel-text-color | _var(--van-gray-7)_ | - |
|
||||
| --van-action-sheet-cancel-padding-top | _var(--van-padding-xs)_ | - |
|
||||
| --van-action-sheet-cancel-padding-color | _var(--van-background-color)_ | - |
|
||||
| --van-action-sheet-loading-icon-size | _22px_ | - |
|
||||
@@ -0,0 +1,129 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import { useTranslate } from '@demo/use-translate';
|
||||
import { ActionSheetAction } from '..';
|
||||
import { Toast } from '../../toast';
|
||||
|
||||
const t = useTranslate({
|
||||
'zh-CN': {
|
||||
option1: '选项一',
|
||||
option2: '选项二',
|
||||
option3: '选项三',
|
||||
subname: '描述信息',
|
||||
showCancel: '展示取消按钮',
|
||||
buttonText: '弹出菜单',
|
||||
customPanel: '自定义面板',
|
||||
description: '这是一段描述信息',
|
||||
optionStatus: '选项状态',
|
||||
coloredOption: '着色选项',
|
||||
disabledOption: '禁用选项',
|
||||
showDescription: '展示描述信息',
|
||||
},
|
||||
'en-US': {
|
||||
option1: 'Option 1',
|
||||
option2: 'Option 2',
|
||||
option3: 'Option 3',
|
||||
subname: 'Description',
|
||||
showCancel: 'Show Cancel Button',
|
||||
buttonText: 'Show ActionSheet',
|
||||
customPanel: 'Custom Panel',
|
||||
description: 'Description',
|
||||
optionStatus: 'Option Status',
|
||||
coloredOption: 'Colored Option',
|
||||
disabledOption: 'Disabled Option',
|
||||
showDescription: 'Show Description',
|
||||
},
|
||||
});
|
||||
const showBasic = ref(false);
|
||||
const showCancel = ref(false);
|
||||
const showTitle = ref(false);
|
||||
const showStatus = ref(false);
|
||||
const showDescription = ref(false);
|
||||
|
||||
const simpleActions = computed<ActionSheetAction[]>(() => [
|
||||
{ name: t('option1') },
|
||||
{ name: t('option2') },
|
||||
{ name: t('option3') },
|
||||
]);
|
||||
|
||||
const statusActions = computed<ActionSheetAction[]>(() => [
|
||||
{ name: t('coloredOption'), color: '#ee0a24' },
|
||||
{ name: t('disabledOption'), disabled: true },
|
||||
{ loading: true },
|
||||
]);
|
||||
|
||||
const actionsWithDescription = computed<ActionSheetAction[]>(() => [
|
||||
{ name: t('option1') },
|
||||
{ name: t('option2') },
|
||||
{ name: t('option3'), subname: t('subname') },
|
||||
]);
|
||||
|
||||
const onSelect = (item: ActionSheetAction) => {
|
||||
showBasic.value = false;
|
||||
Toast(item.name);
|
||||
};
|
||||
|
||||
const onCancel = () => Toast(t('cancel'));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<demo-block card :title="t('basicUsage')">
|
||||
<van-cell is-link :title="t('basicUsage')" @click="showBasic = true" />
|
||||
<van-cell is-link :title="t('showCancel')" @click="showCancel = true" />
|
||||
<van-cell
|
||||
is-link
|
||||
:title="t('showDescription')"
|
||||
@click="showDescription = true"
|
||||
/>
|
||||
</demo-block>
|
||||
|
||||
<demo-block card :title="t('optionStatus')">
|
||||
<van-cell is-link :title="t('optionStatus')" @click="showStatus = true" />
|
||||
</demo-block>
|
||||
|
||||
<demo-block card :title="t('customPanel')">
|
||||
<van-cell is-link :title="t('customPanel')" @click="showTitle = true" />
|
||||
</demo-block>
|
||||
|
||||
<van-action-sheet
|
||||
v-model:show="showBasic"
|
||||
:actions="simpleActions"
|
||||
@select="onSelect"
|
||||
/>
|
||||
|
||||
<van-action-sheet
|
||||
v-model:show="showCancel"
|
||||
:actions="simpleActions"
|
||||
close-on-click-action
|
||||
:cancel-text="t('cancel')"
|
||||
@cancel="onCancel"
|
||||
/>
|
||||
|
||||
<van-action-sheet
|
||||
v-model:show="showDescription"
|
||||
:actions="actionsWithDescription"
|
||||
close-on-click-action
|
||||
:cancel-text="t('cancel')"
|
||||
:description="t('description')"
|
||||
/>
|
||||
|
||||
<van-action-sheet
|
||||
v-model:show="showStatus"
|
||||
close-on-click-action
|
||||
:actions="statusActions"
|
||||
:cancel-text="t('cancel')"
|
||||
/>
|
||||
|
||||
<van-action-sheet v-model:show="showTitle" :title="t('title')">
|
||||
<div class="demo-action-sheet-content">{{ t('content') }}</div>
|
||||
</van-action-sheet>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.demo-action-sheet {
|
||||
&-content {
|
||||
padding: var(--van-padding-md) var(--van-padding-md)
|
||||
calc(var(--van-padding-md) * 10);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,137 @@
|
||||
@import './var.less';
|
||||
@import '../style/mixins/hairline';
|
||||
|
||||
:root {
|
||||
--van-action-sheet-max-height: @action-sheet-max-height;
|
||||
--van-action-sheet-header-height: @action-sheet-header-height;
|
||||
--van-action-sheet-header-font-size: @action-sheet-header-font-size;
|
||||
--van-action-sheet-description-color: @action-sheet-description-color;
|
||||
--van-action-sheet-description-font-size: @action-sheet-description-font-size;
|
||||
--van-action-sheet-description-line-height: @action-sheet-description-line-height;
|
||||
--van-action-sheet-item-background: @action-sheet-item-background;
|
||||
--van-action-sheet-item-font-size: @action-sheet-item-font-size;
|
||||
--van-action-sheet-item-line-height: @action-sheet-item-line-height;
|
||||
--van-action-sheet-item-text-color: @action-sheet-item-text-color;
|
||||
--van-action-sheet-item-disabled-text-color: @action-sheet-item-disabled-text-color;
|
||||
--van-action-sheet-subname-color: @action-sheet-subname-color;
|
||||
--van-action-sheet-subname-font-size: @action-sheet-subname-font-size;
|
||||
--van-action-sheet-subname-line-height: @action-sheet-subname-line-height;
|
||||
--van-action-sheet-close-icon-size: @action-sheet-close-icon-size;
|
||||
--van-action-sheet-close-icon-color: @action-sheet-close-icon-color;
|
||||
--van-action-sheet-close-icon-active-color: @action-sheet-close-icon-active-color;
|
||||
--van-action-sheet-close-icon-padding: @action-sheet-close-icon-padding;
|
||||
--van-action-sheet-cancel-text-color: @action-sheet-cancel-text-color;
|
||||
--van-action-sheet-cancel-padding-top: @action-sheet-cancel-padding-top;
|
||||
--van-action-sheet-cancel-padding-color: @action-sheet-cancel-padding-color;
|
||||
--van-action-sheet-loading-icon-size: @action-sheet-loading-icon-size;
|
||||
}
|
||||
|
||||
.van-action-sheet {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: var(--van-action-sheet-max-height);
|
||||
overflow: hidden;
|
||||
color: var(--van-action-sheet-item-text-color);
|
||||
|
||||
&__content {
|
||||
flex: 1 auto;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
&__item,
|
||||
&__cancel {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 14px var(--van-padding-md);
|
||||
font-size: var(--van-action-sheet-item-font-size);
|
||||
background-color: var(--van-action-sheet-item-background);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
|
||||
&:active {
|
||||
background-color: var(--van-active-color);
|
||||
}
|
||||
}
|
||||
|
||||
&__item {
|
||||
line-height: var(--van-action-sheet-item-line-height);
|
||||
|
||||
&--loading,
|
||||
&--disabled {
|
||||
color: var(--van-action-sheet-item-disabled-text-color);
|
||||
|
||||
&:active {
|
||||
background-color: var(--van-action-sheet-item-background);
|
||||
}
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&--loading {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
&__cancel {
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
color: var(--van-action-sheet-cancel-text-color);
|
||||
}
|
||||
|
||||
&__subname {
|
||||
margin-top: var(--van-padding-xs);
|
||||
color: var(--van-action-sheet-subname-color);
|
||||
font-size: var(--van-action-sheet-subname-font-size);
|
||||
line-height: var(--van-action-sheet-subname-line-height);
|
||||
}
|
||||
|
||||
&__gap {
|
||||
display: block;
|
||||
height: var(--van-action-sheet-cancel-padding-top);
|
||||
background-color: var(--van-action-sheet-cancel-padding-color);
|
||||
}
|
||||
|
||||
&__header {
|
||||
flex-shrink: 0;
|
||||
font-weight: var(--van-font-weight-bold);
|
||||
font-size: var(--van-action-sheet-header-font-size);
|
||||
line-height: var(--van-action-sheet-header-height);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__description {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
padding: 20px var(--van-padding-md);
|
||||
color: var(--van-action-sheet-description-color);
|
||||
font-size: var(--van-action-sheet-description-font-size);
|
||||
line-height: var(--van-action-sheet-description-line-height);
|
||||
text-align: center;
|
||||
|
||||
&::after {
|
||||
.hairline-bottom(var(--van-border-color), var(--van-padding-md), var(--van-padding-md));
|
||||
}
|
||||
}
|
||||
|
||||
&__loading-icon .van-loading__spinner {
|
||||
width: var(--van-action-sheet-loading-icon-size);
|
||||
height: var(--van-action-sheet-loading-icon-size);
|
||||
}
|
||||
|
||||
&__close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: var(--van-action-sheet-close-icon-padding);
|
||||
color: var(--van-action-sheet-close-icon-color);
|
||||
font-size: var(--van-action-sheet-close-icon-size);
|
||||
line-height: inherit;
|
||||
|
||||
&:active {
|
||||
color: var(--van-action-sheet-close-icon-active-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { withInstall } from '../utils';
|
||||
import _ActionSheet from './ActionSheet';
|
||||
|
||||
export const ActionSheet = withInstall(_ActionSheet);
|
||||
export default ActionSheet;
|
||||
export type { ActionSheetAction } from './ActionSheet';
|
||||
@@ -0,0 +1,90 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should render demo and match snapshot 1`] = `
|
||||
<div>
|
||||
<div class="van-cell van-cell--clickable"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-cell__title">
|
||||
<span>
|
||||
Basic Usage
|
||||
</span>
|
||||
</div>
|
||||
<i class="van-badge__wrapper van-icon van-icon-arrow van-cell__right-icon">
|
||||
</i>
|
||||
</div>
|
||||
<div class="van-cell van-cell--clickable"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-cell__title">
|
||||
<span>
|
||||
Show Cancel Button
|
||||
</span>
|
||||
</div>
|
||||
<i class="van-badge__wrapper van-icon van-icon-arrow van-cell__right-icon">
|
||||
</i>
|
||||
</div>
|
||||
<div class="van-cell van-cell--clickable"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-cell__title">
|
||||
<span>
|
||||
Show Description
|
||||
</span>
|
||||
</div>
|
||||
<i class="van-badge__wrapper van-icon van-icon-arrow van-cell__right-icon">
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-cell van-cell--clickable"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-cell__title">
|
||||
<span>
|
||||
Option Status
|
||||
</span>
|
||||
</div>
|
||||
<i class="van-badge__wrapper van-icon van-icon-arrow van-cell__right-icon">
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-cell van-cell--clickable"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-cell__title">
|
||||
<span>
|
||||
Custom Panel
|
||||
</span>
|
||||
</div>
|
||||
<i class="van-badge__wrapper van-icon van-icon-arrow van-cell__right-icon">
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
<transition-stub>
|
||||
</transition-stub>
|
||||
<transition-stub>
|
||||
</transition-stub>
|
||||
<transition-stub>
|
||||
</transition-stub>
|
||||
<transition-stub>
|
||||
</transition-stub>
|
||||
<transition-stub>
|
||||
</transition-stub>
|
||||
<transition-stub>
|
||||
</transition-stub>
|
||||
<transition-stub>
|
||||
</transition-stub>
|
||||
<transition-stub>
|
||||
</transition-stub>
|
||||
<transition-stub>
|
||||
</transition-stub>
|
||||
<transition-stub>
|
||||
</transition-stub>
|
||||
`;
|
||||
@@ -0,0 +1,58 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should allow to custom close icon with closeIcon prop 1`] = `
|
||||
<i class="van-badge__wrapper van-icon van-icon-cross van-action-sheet__close">
|
||||
</i>
|
||||
`;
|
||||
|
||||
exports[`should render cancel slot correctly 1`] = `
|
||||
<button type="button"
|
||||
class="van-action-sheet__cancel"
|
||||
>
|
||||
Custom Cancel
|
||||
</button>
|
||||
`;
|
||||
|
||||
exports[`should render default slot correctly 1`] = `
|
||||
<transition-stub>
|
||||
<div class="van-overlay">
|
||||
</div>
|
||||
</transition-stub>
|
||||
<transition-stub>
|
||||
<div class="van-popup van-popup--round van-popup--bottom van-safe-area-bottom van-action-sheet">
|
||||
<div class="van-action-sheet__header">
|
||||
Title
|
||||
<i class="van-badge__wrapper van-icon van-icon-cross van-action-sheet__close">
|
||||
</i>
|
||||
</div>
|
||||
<div class="van-action-sheet__content">
|
||||
Default
|
||||
</div>
|
||||
</div>
|
||||
</transition-stub>
|
||||
`;
|
||||
|
||||
exports[`should render description correctly 1`] = `
|
||||
<div class="van-action-sheet__description">
|
||||
This is a description
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should render description slot when match snapshot 1`] = `
|
||||
<div class="van-action-sheet__description">
|
||||
Custom Description
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should render subname correctly 1`] = `
|
||||
<button type="button"
|
||||
class="van-action-sheet__item"
|
||||
>
|
||||
<span class="van-action-sheet__name">
|
||||
Option
|
||||
</span>
|
||||
<div class="van-action-sheet__subname">
|
||||
Subname
|
||||
</div>
|
||||
</button>
|
||||
`;
|
||||
@@ -0,0 +1,4 @@
|
||||
import Demo from '../demo/index.vue';
|
||||
import { snapshotDemo } from '../../../test/demo';
|
||||
|
||||
snapshotDemo(Demo);
|
||||
@@ -0,0 +1,260 @@
|
||||
import { nextTick } from 'vue';
|
||||
import { mount } from '../../../test';
|
||||
import { ActionSheet } from '..';
|
||||
|
||||
test('should emit select event after clicking option', async () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
actions: [{ name: 'Option' }],
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.find('.van-action-sheet__item').trigger('click');
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.emitted('select')!.length).toEqual(1);
|
||||
expect(wrapper.emitted('select')![0]).toEqual([
|
||||
{
|
||||
name: 'Option',
|
||||
},
|
||||
0,
|
||||
]);
|
||||
});
|
||||
|
||||
test('should call callback function after clicking option', () => {
|
||||
const callback = jest.fn();
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
actions: [{ name: 'Option', callback }],
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.find('.van-action-sheet__item').trigger('click');
|
||||
expect(callback).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should not emit select event after clicking loading option', async () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
actions: [{ name: 'Option', loading: true }],
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.find('.van-action-sheet__item').trigger('click');
|
||||
await nextTick();
|
||||
expect(wrapper.emitted('select')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should not emit select event after clicking disabled option', async () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
actions: [{ name: 'Option', disabled: true }],
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.find('.van-action-sheet__item').trigger('click');
|
||||
await nextTick();
|
||||
expect(wrapper.emitted('select')).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should emit cancel event after clicking cancel button', () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
actions: [{ name: 'Option' }],
|
||||
cancelText: 'Cancel',
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.find('.van-action-sheet__cancel').trigger('click');
|
||||
expect(wrapper.emitted('cancel')!.length).toEqual(1);
|
||||
});
|
||||
|
||||
test('should render subname correctly', () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
actions: [{ name: 'Option', subname: 'Subname' }],
|
||||
cancelText: 'Cancel',
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find('.van-action-sheet__item').html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render content after disabling the lazy-render prop', async () => {
|
||||
const wrapper = mount(ActionSheet);
|
||||
expect(wrapper.find('.van-action-sheet__content').exists()).toBeFalsy();
|
||||
|
||||
await wrapper.setProps({ lazyRender: false });
|
||||
expect(wrapper.find('.van-action-sheet__content').exists()).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should render default slot correctly', () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
title: 'Title',
|
||||
},
|
||||
slots: {
|
||||
default: () => 'Default',
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should allow to use the teleport prop', () => {
|
||||
const root = document.createElement('div');
|
||||
mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
teleport: root,
|
||||
},
|
||||
});
|
||||
|
||||
expect(root.querySelector('.van-action-sheet')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should have "van-popup--round" class when setting the round prop', () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
round: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find('.van-popup--round').exists()).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should change option color when using the color prop', () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
actions: [{ name: 'Option', color: 'red' }],
|
||||
},
|
||||
});
|
||||
|
||||
const item = wrapper.find('.van-action-sheet__item');
|
||||
expect(item.style.color).toEqual('red');
|
||||
});
|
||||
|
||||
test('should hide close icon when the closeable prop is false', async () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
title: 'Title',
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find('.van-action-sheet__close').exists()).toBeTruthy();
|
||||
|
||||
await wrapper.setProps({ closeable: false });
|
||||
expect(wrapper.find('.van-action-sheet__close').exists()).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should allow to custom close icon with closeIcon prop', () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
title: 'Title',
|
||||
closeIcon: 'cross',
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find('.van-action-sheet__close').html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render description correctly', () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
description: 'This is a description',
|
||||
},
|
||||
});
|
||||
|
||||
expect(
|
||||
wrapper.find('.van-action-sheet__description').html()
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render cancel slot correctly', () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
},
|
||||
slots: {
|
||||
cancel: () => 'Custom Cancel',
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find('.van-action-sheet__cancel').html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render description slot when match snapshot', () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
},
|
||||
slots: {
|
||||
description: () => 'Custom Description',
|
||||
},
|
||||
});
|
||||
|
||||
expect(
|
||||
wrapper.find('.van-action-sheet__description').html()
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should close after clicking option if close-on-click-action prop is true', () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
actions: [{ name: 'Option' }],
|
||||
closeOnClickAction: true,
|
||||
},
|
||||
});
|
||||
|
||||
const option = wrapper.find('.van-action-sheet__item');
|
||||
option.trigger('click');
|
||||
|
||||
expect(wrapper.emitted('update:show')!.length).toEqual(1);
|
||||
expect(wrapper.emitted('update:show')![0]).toEqual([false]);
|
||||
});
|
||||
|
||||
test('should emit click-overlay event and closed after clicking the overlay', () => {
|
||||
const onClickOverlay = jest.fn();
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
onClickOverlay,
|
||||
},
|
||||
});
|
||||
|
||||
wrapper.find('.van-overlay').trigger('click');
|
||||
expect(wrapper.emitted('update:show')![0]).toEqual([false]);
|
||||
expect(onClickOverlay).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should allow to control safe-area with safe-area-inset-bottom prop', async () => {
|
||||
const wrapper = mount(ActionSheet, {
|
||||
props: {
|
||||
show: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find('.van-action-sheet').classes()).toContain(
|
||||
'van-safe-area-bottom'
|
||||
);
|
||||
|
||||
await wrapper.setProps({
|
||||
safeAreaInsetBottom: false,
|
||||
});
|
||||
expect(wrapper.find('.van-action-sheet').classes()).not.toContain(
|
||||
'van-safe-area-bottom'
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
@import '../style/var.less';
|
||||
|
||||
@action-sheet-max-height: 80%;
|
||||
@action-sheet-header-height: 48px;
|
||||
@action-sheet-header-font-size: var(--van-font-size-lg);
|
||||
@action-sheet-description-color: var(--van-gray-6);
|
||||
@action-sheet-description-font-size: var(--van-font-size-md);
|
||||
@action-sheet-description-line-height: var(--van-line-height-md);
|
||||
@action-sheet-item-background: var(--van-white);
|
||||
@action-sheet-item-font-size: var(--van-font-size-lg);
|
||||
@action-sheet-item-line-height: var(--van-line-height-lg);
|
||||
@action-sheet-item-text-color: var(--van-text-color);
|
||||
@action-sheet-item-disabled-text-color: var(--van-gray-5);
|
||||
@action-sheet-subname-color: var(--van-gray-6);
|
||||
@action-sheet-subname-font-size: var(--van-font-size-sm);
|
||||
@action-sheet-subname-line-height: var(--van-line-height-sm);
|
||||
@action-sheet-close-icon-size: 22px;
|
||||
@action-sheet-close-icon-color: var(--van-gray-5);
|
||||
@action-sheet-close-icon-active-color: var(--van-gray-6);
|
||||
@action-sheet-close-icon-padding: 0 var(--van-padding-md);
|
||||
@action-sheet-cancel-text-color: var(--van-gray-7);
|
||||
@action-sheet-cancel-padding-top: var(--van-padding-xs);
|
||||
@action-sheet-cancel-padding-color: var(--van-background-color);
|
||||
@action-sheet-loading-icon-size: 22px;
|
||||
@@ -0,0 +1,435 @@
|
||||
import {
|
||||
ref,
|
||||
watch,
|
||||
computed,
|
||||
nextTick,
|
||||
reactive,
|
||||
PropType,
|
||||
defineComponent,
|
||||
ExtractPropTypes,
|
||||
} from 'vue';
|
||||
|
||||
// Utils
|
||||
import {
|
||||
extend,
|
||||
isObject,
|
||||
isMobile,
|
||||
truthProp,
|
||||
createNamespace,
|
||||
} from '../utils';
|
||||
|
||||
// Composables
|
||||
import { useExpose } from '../composables/use-expose';
|
||||
|
||||
// Components
|
||||
import { Area, AreaList, AreaColumnOption, AreaInstance } from '../area';
|
||||
import { Cell } from '../cell';
|
||||
import { Field } from '../field';
|
||||
import { Popup } from '../popup';
|
||||
import { Toast } from '../toast';
|
||||
import { Button } from '../button';
|
||||
import { Dialog } from '../dialog';
|
||||
import { Switch } from '../switch';
|
||||
import AddressEditDetail from './AddressEditDetail';
|
||||
|
||||
// Types
|
||||
import type { AddressEditInfo, AddressEditSearchItem } from './types';
|
||||
|
||||
const [name, bem, t] = createNamespace('address-edit');
|
||||
|
||||
const DEFAULT_DATA: AddressEditInfo = {
|
||||
name: '',
|
||||
tel: '',
|
||||
city: '',
|
||||
county: '',
|
||||
country: '',
|
||||
province: '',
|
||||
areaCode: '',
|
||||
isDefault: false,
|
||||
postalCode: '',
|
||||
addressDetail: '',
|
||||
};
|
||||
|
||||
function isPostal(value: string) {
|
||||
return /^\d{6}$/.test(value);
|
||||
}
|
||||
|
||||
const props = {
|
||||
areaList: Object as PropType<AreaList>,
|
||||
isSaving: Boolean,
|
||||
isDeleting: Boolean,
|
||||
validator: Function as PropType<
|
||||
(key: string, value: string) => string | undefined
|
||||
>,
|
||||
showArea: truthProp,
|
||||
showDetail: truthProp,
|
||||
showDelete: Boolean,
|
||||
showPostal: Boolean,
|
||||
disableArea: Boolean,
|
||||
searchResult: Array as PropType<AddressEditSearchItem[]>,
|
||||
telMaxlength: [Number, String],
|
||||
showSetDefault: Boolean,
|
||||
saveButtonText: String,
|
||||
areaPlaceholder: String,
|
||||
deleteButtonText: String,
|
||||
showSearchResult: Boolean,
|
||||
detailRows: {
|
||||
type: [Number, String],
|
||||
default: 1,
|
||||
},
|
||||
detailMaxlength: {
|
||||
type: [Number, String],
|
||||
default: 200,
|
||||
},
|
||||
addressInfo: {
|
||||
type: Object as PropType<Partial<AddressEditInfo>>,
|
||||
default: () => extend({}, DEFAULT_DATA),
|
||||
},
|
||||
telValidator: {
|
||||
type: Function as PropType<(val: string) => boolean>,
|
||||
default: isMobile,
|
||||
},
|
||||
postalValidator: {
|
||||
type: Function as PropType<(val: string) => boolean>,
|
||||
default: isPostal,
|
||||
},
|
||||
areaColumnsPlaceholder: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => [],
|
||||
},
|
||||
};
|
||||
|
||||
export type AddressEditProps = ExtractPropTypes<typeof props>;
|
||||
|
||||
export default defineComponent({
|
||||
name,
|
||||
|
||||
props,
|
||||
|
||||
emits: [
|
||||
'save',
|
||||
'focus',
|
||||
'delete',
|
||||
'click-area',
|
||||
'change-area',
|
||||
'change-detail',
|
||||
'cancel-delete',
|
||||
'select-search',
|
||||
'change-default',
|
||||
],
|
||||
|
||||
setup(props, { emit, slots }) {
|
||||
const areaRef = ref<AreaInstance>();
|
||||
|
||||
const state = reactive({
|
||||
data: {} as AddressEditInfo,
|
||||
showAreaPopup: false,
|
||||
detailFocused: false,
|
||||
errorInfo: {
|
||||
tel: '',
|
||||
name: '',
|
||||
areaCode: '',
|
||||
postalCode: '',
|
||||
addressDetail: '',
|
||||
} as Record<string, string>,
|
||||
});
|
||||
|
||||
const areaListLoaded = computed(
|
||||
() => isObject(props.areaList) && Object.keys(props.areaList).length
|
||||
);
|
||||
|
||||
const areaText = computed(() => {
|
||||
const { country, province, city, county, areaCode } = state.data;
|
||||
if (areaCode) {
|
||||
const arr = [country, province, city, county];
|
||||
if (province && province === city) {
|
||||
arr.splice(1, 1);
|
||||
}
|
||||
return arr.filter(Boolean).join('/');
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
// hide bottom field when use search && detail get focused
|
||||
const hideBottomFields = computed(
|
||||
() => props.searchResult?.length && state.detailFocused
|
||||
);
|
||||
|
||||
const assignAreaValues = () => {
|
||||
if (areaRef.value) {
|
||||
const detail: Record<string, string> = areaRef.value.getArea();
|
||||
detail.areaCode = detail.code;
|
||||
delete detail.code;
|
||||
extend(state.data, detail);
|
||||
}
|
||||
};
|
||||
|
||||
const onFocus = (key: string) => {
|
||||
state.errorInfo[key] = '';
|
||||
state.detailFocused = key === 'addressDetail';
|
||||
emit('focus', key);
|
||||
};
|
||||
|
||||
const getErrorMessage = (key: string) => {
|
||||
const value = String((state.data as any)[key] || '').trim();
|
||||
|
||||
if (props.validator) {
|
||||
const message = props.validator(key, value);
|
||||
if (message) {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case 'name':
|
||||
return value ? '' : t('nameEmpty');
|
||||
case 'tel':
|
||||
return props.telValidator(value) ? '' : t('telInvalid');
|
||||
case 'areaCode':
|
||||
return value ? '' : t('areaEmpty');
|
||||
case 'addressDetail':
|
||||
return value ? '' : t('addressEmpty');
|
||||
case 'postalCode':
|
||||
return value && !props.postalValidator(value) ? t('postalEmpty') : '';
|
||||
}
|
||||
};
|
||||
|
||||
const onSave = () => {
|
||||
const items = ['name', 'tel'];
|
||||
|
||||
if (props.showArea) {
|
||||
items.push('areaCode');
|
||||
}
|
||||
|
||||
if (props.showDetail) {
|
||||
items.push('addressDetail');
|
||||
}
|
||||
|
||||
if (props.showPostal) {
|
||||
items.push('postalCode');
|
||||
}
|
||||
|
||||
const isValid = items.every((item) => {
|
||||
const msg = getErrorMessage(item);
|
||||
if (msg) {
|
||||
state.errorInfo[item] = msg;
|
||||
}
|
||||
return !msg;
|
||||
});
|
||||
|
||||
if (isValid && !props.isSaving) {
|
||||
emit('save', state.data);
|
||||
}
|
||||
};
|
||||
|
||||
const onChangeDetail = (val: string) => {
|
||||
state.data.addressDetail = val;
|
||||
emit('change-detail', val);
|
||||
};
|
||||
|
||||
const onAreaConfirm = (values: AreaColumnOption[]) => {
|
||||
values = values.filter(Boolean);
|
||||
|
||||
if (values.some((value) => !value.code)) {
|
||||
Toast(t('areaEmpty'));
|
||||
return;
|
||||
}
|
||||
|
||||
state.showAreaPopup = false;
|
||||
assignAreaValues();
|
||||
emit('change-area', values);
|
||||
};
|
||||
|
||||
const onDelete = () => {
|
||||
Dialog.confirm({
|
||||
title: t('confirmDelete'),
|
||||
})
|
||||
.then(() => emit('delete', state.data))
|
||||
.catch(() => emit('cancel-delete', state.data));
|
||||
};
|
||||
|
||||
// get values of area component
|
||||
const getArea = () => (areaRef.value ? areaRef.value.getValues() : []);
|
||||
|
||||
// set area code to area component
|
||||
const setAreaCode = (code?: string) => {
|
||||
state.data.areaCode = code || '';
|
||||
|
||||
if (code) {
|
||||
nextTick(assignAreaValues);
|
||||
}
|
||||
};
|
||||
|
||||
const onDetailBlur = () => {
|
||||
// await for click search event
|
||||
setTimeout(() => {
|
||||
state.detailFocused = false;
|
||||
});
|
||||
};
|
||||
|
||||
const setAddressDetail = (value: string) => {
|
||||
state.data.addressDetail = value;
|
||||
};
|
||||
|
||||
const renderSetDefaultCell = () => {
|
||||
if (props.showSetDefault) {
|
||||
const slots = {
|
||||
'right-icon': () => (
|
||||
<Switch
|
||||
v-model={state.data.isDefault}
|
||||
size="24"
|
||||
onChange={(event) => emit('change-default', event)}
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
return (
|
||||
<Cell
|
||||
v-slots={slots}
|
||||
v-show={!hideBottomFields.value}
|
||||
center
|
||||
title={t('defaultAddress')}
|
||||
class={bem('default')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
useExpose({
|
||||
getArea,
|
||||
setAreaCode,
|
||||
setAddressDetail,
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.areaList,
|
||||
() => setAreaCode(state.data.areaCode)
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.addressInfo,
|
||||
(value) => {
|
||||
state.data = extend({}, DEFAULT_DATA, value);
|
||||
setAreaCode(value.areaCode);
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
const { data, errorInfo } = state;
|
||||
const { disableArea } = props;
|
||||
|
||||
return (
|
||||
<div class={bem()}>
|
||||
<div class={bem('fields')}>
|
||||
<Field
|
||||
v-model={data.name}
|
||||
clearable
|
||||
label={t('name')}
|
||||
placeholder={t('name')}
|
||||
errorMessage={errorInfo.name}
|
||||
onFocus={() => onFocus('name')}
|
||||
/>
|
||||
<Field
|
||||
v-model={data.tel}
|
||||
clearable
|
||||
type="tel"
|
||||
label={t('tel')}
|
||||
maxlength={props.telMaxlength}
|
||||
placeholder={t('tel')}
|
||||
errorMessage={errorInfo.tel}
|
||||
onFocus={() => onFocus('tel')}
|
||||
/>
|
||||
<Field
|
||||
v-show={props.showArea}
|
||||
readonly
|
||||
label={t('area')}
|
||||
is-link={!disableArea}
|
||||
modelValue={areaText.value}
|
||||
placeholder={props.areaPlaceholder || t('area')}
|
||||
errorMessage={errorInfo.areaCode}
|
||||
onFocus={() => onFocus('areaCode')}
|
||||
onClick={() => {
|
||||
emit('click-area');
|
||||
state.showAreaPopup = !disableArea;
|
||||
}}
|
||||
/>
|
||||
<AddressEditDetail
|
||||
show={props.showDetail}
|
||||
value={data.addressDetail}
|
||||
focused={state.detailFocused}
|
||||
detailRows={props.detailRows}
|
||||
errorMessage={errorInfo.addressDetail}
|
||||
searchResult={props.searchResult}
|
||||
detailMaxlength={props.detailMaxlength}
|
||||
showSearchResult={props.showSearchResult}
|
||||
onBlur={onDetailBlur}
|
||||
onFocus={() => onFocus('addressDetail')}
|
||||
onInput={onChangeDetail}
|
||||
onSelect-search={(event: Event) => emit('select-search', event)}
|
||||
/>
|
||||
{props.showPostal && (
|
||||
<Field
|
||||
v-show={!hideBottomFields.value}
|
||||
v-model={data.postalCode}
|
||||
type="tel"
|
||||
label={t('postal')}
|
||||
maxlength="6"
|
||||
placeholder={t('postal')}
|
||||
errorMessage={errorInfo.postalCode}
|
||||
onFocus={() => onFocus('postalCode')}
|
||||
/>
|
||||
)}
|
||||
{slots.default?.()}
|
||||
</div>
|
||||
{renderSetDefaultCell()}
|
||||
<div v-show={!hideBottomFields.value} class={bem('buttons')}>
|
||||
<Button
|
||||
block
|
||||
round
|
||||
type="danger"
|
||||
text={props.saveButtonText || t('save')}
|
||||
class={bem('button')}
|
||||
loading={props.isSaving}
|
||||
onClick={onSave}
|
||||
/>
|
||||
{props.showDelete && (
|
||||
<Button
|
||||
block
|
||||
round
|
||||
class={bem('button')}
|
||||
loading={props.isDeleting}
|
||||
text={props.deleteButtonText || t('delete')}
|
||||
onClick={onDelete}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<Popup
|
||||
v-model={[state.showAreaPopup, 'show']}
|
||||
round
|
||||
teleport="body"
|
||||
position="bottom"
|
||||
lazyRender={false}
|
||||
>
|
||||
<Area
|
||||
ref={areaRef}
|
||||
value={data.areaCode}
|
||||
loading={!areaListLoaded.value}
|
||||
areaList={props.areaList}
|
||||
columnsPlaceholder={props.areaColumnsPlaceholder}
|
||||
onConfirm={onAreaConfirm}
|
||||
onCancel={() => {
|
||||
state.showAreaPopup = false;
|
||||
}}
|
||||
/>
|
||||
</Popup>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,107 @@
|
||||
import { PropType, ref, defineComponent } from 'vue';
|
||||
|
||||
// Utils
|
||||
import { createNamespace } from '../utils';
|
||||
|
||||
// Components
|
||||
import { Cell } from '../cell';
|
||||
import { Field } from '../field';
|
||||
|
||||
// Types
|
||||
import type { AddressEditSearchItem } from './types';
|
||||
import type { FieldInstance } from '../field/types';
|
||||
|
||||
const [name, bem, t] = createNamespace('address-edit-detail');
|
||||
|
||||
export default defineComponent({
|
||||
name,
|
||||
|
||||
props: {
|
||||
show: Boolean,
|
||||
value: String,
|
||||
focused: Boolean,
|
||||
detailRows: [Number, String],
|
||||
searchResult: Array as PropType<AddressEditSearchItem[]>,
|
||||
errorMessage: String,
|
||||
detailMaxlength: [Number, String],
|
||||
showSearchResult: Boolean,
|
||||
},
|
||||
|
||||
emits: ['blur', 'focus', 'input', 'select-search'],
|
||||
|
||||
setup(props, { emit }) {
|
||||
const field = ref<FieldInstance>();
|
||||
|
||||
const showSearchResult = () =>
|
||||
props.focused && props.searchResult && props.showSearchResult;
|
||||
|
||||
const onSelect = (express: AddressEditSearchItem) => {
|
||||
emit('select-search', express);
|
||||
emit('input', `${express.address || ''} ${express.name || ''}`.trim());
|
||||
};
|
||||
|
||||
const renderSearchTitle = (express: AddressEditSearchItem) => {
|
||||
if (express.name) {
|
||||
const text = express.name.replace(
|
||||
props.value!,
|
||||
`<span class=${bem('keyword')}>${props.value}</span>`
|
||||
);
|
||||
|
||||
return <div innerHTML={text} />;
|
||||
}
|
||||
};
|
||||
|
||||
const renderSearchResult = () => {
|
||||
if (!showSearchResult()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { searchResult } = props;
|
||||
return searchResult!.map((express) => (
|
||||
<Cell
|
||||
v-slots={{
|
||||
title: () => renderSearchTitle(express),
|
||||
}}
|
||||
clickable
|
||||
key={express.name + express.address}
|
||||
icon="location-o"
|
||||
label={express.address}
|
||||
class={bem('search-item')}
|
||||
border={false}
|
||||
onClick={() => onSelect(express)}
|
||||
/>
|
||||
));
|
||||
};
|
||||
|
||||
const onBlur = (event: Event) => emit('blur', event);
|
||||
const onFocus = (event: Event) => emit('focus', event);
|
||||
const onInput = (value: string) => emit('input', value);
|
||||
|
||||
return () => {
|
||||
if (props.show) {
|
||||
return (
|
||||
<>
|
||||
<Field
|
||||
autosize
|
||||
clearable
|
||||
ref={field}
|
||||
class={bem()}
|
||||
rows={props.detailRows}
|
||||
type="textarea"
|
||||
label={t('label')}
|
||||
border={!showSearchResult()}
|
||||
maxlength={props.detailMaxlength}
|
||||
modelValue={props.value}
|
||||
placeholder={t('placeholder')}
|
||||
errorMessage={props.errorMessage}
|
||||
onBlur={onBlur}
|
||||
onFocus={onFocus}
|
||||
{...{ 'onUpdate:modelValue': onInput }}
|
||||
/>
|
||||
{renderSearchResult()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,188 @@
|
||||
# AddressEdit
|
||||
|
||||
### Intro
|
||||
|
||||
Used to create, update, and delete receiving addresses.
|
||||
|
||||
### 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 { AddressEdit } from 'vant';
|
||||
|
||||
const app = createApp();
|
||||
app.use(AddressEdit);
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```html
|
||||
<van-address-edit
|
||||
:area-list="areaList"
|
||||
show-postal
|
||||
show-delete
|
||||
show-set-default
|
||||
show-search-result
|
||||
:search-result="searchResult"
|
||||
:area-columns-placeholder="['Choose', 'Choose', 'Choose']"
|
||||
@save="onSave"
|
||||
@delete="onDelete"
|
||||
@change-detail="onChangeDetail"
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { Toast } from 'vant';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const searchResult = ref([]);
|
||||
|
||||
const onSave = () => Toast('save');
|
||||
const onDelete = () => Toast('delete');
|
||||
const onChangeDetail = (val) => {
|
||||
if (val) {
|
||||
searchResult.value = [
|
||||
{
|
||||
name: 'Name1',
|
||||
address: 'Address',
|
||||
},
|
||||
];
|
||||
} else {
|
||||
searchResult.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
onSave,
|
||||
onDelete,
|
||||
areaList,
|
||||
searchResult,
|
||||
onChangeDetail,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| area-list | Area List | _object_ | - |
|
||||
| area-columns-placeholder | placeholder of area columns | _string[]_ | `[]` |
|
||||
| area-placeholder | placeholder of area input field | _string_ | `Area` |
|
||||
| address-info | Address Info | _AddressEditInfo_ | `{}` |
|
||||
| search-result | Address search result | _AddressEditSearchItem[]_ | `[]` |
|
||||
| show-postal | Whether to show postal field | _boolean_ | `false` |
|
||||
| show-delete | Whether to show delete button | _boolean_ | `false` |
|
||||
| show-set-default | Whether to show default address switch | _boolean_ | `false` |
|
||||
| show-search-result | Whether to show address search result | _boolean_ | `false` |
|
||||
| show-area | Whether to show area cell | _boolean_ | `true` |
|
||||
| show-detail | Whether to show detail field | _boolean_ | `true` |
|
||||
| disable-area | Whether to disable area select | _boolean_ | `false` |
|
||||
| save-button-text | Save button text | _string_ | `Save` |
|
||||
| delete-button-text | Delete button text | _string_ | `Delete` |
|
||||
| detail-rows | Detail input rows | _number \| string_ | `1` |
|
||||
| detail-maxlength | Detail maxlength | _number \| string_ | `200` |
|
||||
| is-saving | Whether to show save button loading status | _boolean_ | `false` |
|
||||
| is-deleting | Whether to show delete button loading status | _boolean_ | `false` |
|
||||
| tel-validator | The method to validate tel | _(tel: string) => boolean_ | - |
|
||||
| tel-maxlength | Tel maxlength | _number \| string_ | - |
|
||||
| postal-validator | The method to validate postal | _(tel: string) => boolean_ | - |
|
||||
| validator | Custom validator | _(key, val) => string_ | - |
|
||||
|
||||
### Events
|
||||
|
||||
| Event | Description | Arguments |
|
||||
| --- | --- | --- |
|
||||
| save | Emitted when the save button is clicked | content:form content |
|
||||
| focus | Emitted when field is focused | key: field name |
|
||||
| delete | Emitted when confirming delete | content:form content |
|
||||
| cancel-delete | Emitted when canceling delete | content:form content |
|
||||
| select-search | Emitted when a search result is selected | value: search content |
|
||||
| click-area | Emitted when the area field is clicked | - |
|
||||
| change-area | Emitted when area changed | values: area values |
|
||||
| change-detail | Emitted when address detail changed | value: address detail |
|
||||
| change-default | Emitted when switching default address | value: checked |
|
||||
|
||||
### Slots
|
||||
|
||||
| Name | Description |
|
||||
| ------- | --------------------------- |
|
||||
| default | Custom content below postal |
|
||||
|
||||
### Methods
|
||||
|
||||
Use [ref](https://v3.vuejs.org/guide/component-template-refs.html) to get AddressEdit instance and call instance methods.
|
||||
|
||||
| Name | Description | Attribute | Return value |
|
||||
| --- | --- | --- | --- |
|
||||
| setAddressDetail | Set address detail | _addressDetail: string_ | - |
|
||||
|
||||
### Types
|
||||
|
||||
The component exports the following type definitions:
|
||||
|
||||
```ts
|
||||
import type {
|
||||
AddressEditInfo,
|
||||
AddressEditInstance,
|
||||
AddressEditSearchItem,
|
||||
} from 'vant';
|
||||
```
|
||||
|
||||
`AddressEditInstance` is the type of component instance:
|
||||
|
||||
```ts
|
||||
import { ref } from 'vue';
|
||||
import type { AddressEditInstance } from 'vant';
|
||||
|
||||
const addressEditRef = ref<AddressEditInstance>();
|
||||
|
||||
addressEditRef.value?.setAddressDetail('');
|
||||
```
|
||||
|
||||
### AddressEditInfo Data Structure
|
||||
|
||||
| key | Description | Type |
|
||||
| ------------- | ------------------ | --------- |
|
||||
| name | Name | _string_ |
|
||||
| tel | Phone | _string_ |
|
||||
| province | Province | _string_ |
|
||||
| city | City | _string_ |
|
||||
| county | County | _string_ |
|
||||
| addressDetail | Detailed Address | _string_ |
|
||||
| areaCode | Area code | _string_ |
|
||||
| postalCode | Postal code | _string_ |
|
||||
| isDefault | Is default address | _boolean_ |
|
||||
|
||||
### AddressEditSearchItem Data Structure
|
||||
|
||||
| key | Description | Type |
|
||||
| ------- | ----------- | -------- |
|
||||
| name | Name | _string_ |
|
||||
| address | Address | _string_ |
|
||||
|
||||
### Area Data Structure
|
||||
|
||||
Please refer to [Area](#/en-US/area) component.
|
||||
|
||||
## Theming
|
||||
|
||||
### CSS Variables
|
||||
|
||||
The component provides the following CSS variables, which can be used to customize styles. Please refer to [ConfigProvider component](#/en-US/config-provider).
|
||||
|
||||
| Name | Default Value | Description |
|
||||
| --- | --- | --- |
|
||||
| --van-address-edit-padding | _var(--van-padding-sm)_ | - |
|
||||
| --van-address-edit-buttons-padding | _var(--van-padding-xl) var(--van-padding-base)_ | - |
|
||||
| --van-address-edit-button-margin-bottom | _var(--van-padding-sm)_ | - |
|
||||
| --van-address-edit-button-font-size | _var(--van-font-size-lg)_ | - |
|
||||
@@ -0,0 +1,190 @@
|
||||
# AddressEdit 地址编辑
|
||||
|
||||
### 介绍
|
||||
|
||||
地址编辑组件,用于新建、更新、删除地址信息。
|
||||
|
||||
### 引入
|
||||
|
||||
通过以下方式来全局注册组件,更多注册方式请参考[组件注册](#/zh-CN/advanced-usage#zu-jian-zhu-ce)。
|
||||
|
||||
```js
|
||||
import { createApp } from 'vue';
|
||||
import { AddressEdit } from 'vant';
|
||||
|
||||
const app = createApp();
|
||||
app.use(AddressEdit);
|
||||
```
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基础用法
|
||||
|
||||
```html
|
||||
<van-address-edit
|
||||
:area-list="areaList"
|
||||
show-postal
|
||||
show-delete
|
||||
show-set-default
|
||||
show-search-result
|
||||
:search-result="searchResult"
|
||||
:area-columns-placeholder="['请选择', '请选择', '请选择']"
|
||||
@save="onSave"
|
||||
@delete="onDelete"
|
||||
@change-detail="onChangeDetail"
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { Toast } from 'vant';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const searchResult = ref([]);
|
||||
|
||||
const onSave = () => Toast('save');
|
||||
const onDelete = () => Toast('delete');
|
||||
const onChangeDetail = (val) => {
|
||||
if (val) {
|
||||
searchResult.value = [
|
||||
{
|
||||
name: '黄龙万科中心',
|
||||
address: '杭州市西湖区',
|
||||
},
|
||||
];
|
||||
} else {
|
||||
searchResult.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
onSave,
|
||||
onDelete,
|
||||
areaList,
|
||||
searchResult,
|
||||
onChangeDetail,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| area-list | 地区列表 | _object_ | - |
|
||||
| area-columns-placeholder | 地区选择列占位提示文字 | _string[]_ | `[]` |
|
||||
| area-placeholder | 地区输入框占位提示文字 | _string_ | `选择省 / 市 / 区` |
|
||||
| address-info | 地址信息初始值 | _AddressEditInfo_ | `{}` |
|
||||
| search-result | 详细地址搜索结果 | _AddressEditSearchItem[]_ | `[]` |
|
||||
| show-postal | 是否显示邮政编码 | _boolean_ | `false` |
|
||||
| show-delete | 是否显示删除按钮 | _boolean_ | `false` |
|
||||
| show-set-default | 是否显示默认地址栏 | _boolean_ | `false` |
|
||||
| show-search-result | 是否显示搜索结果 | _boolean_ | `false` |
|
||||
| show-area | 是否显示地区 | _boolean_ | `true` |
|
||||
| show-detail | 是否显示详细地址 | _boolean_ | `true` |
|
||||
| disable-area | 是否禁用地区选择 | _boolean_ | `false` |
|
||||
| save-button-text | 保存按钮文字 | _string_ | `保存` |
|
||||
| delete-button-text | 删除按钮文字 | _string_ | `删除` |
|
||||
| detail-rows | 详细地址输入框行数 | _number \| string_ | `1` |
|
||||
| detail-maxlength | 详细地址最大长度 | _number \| string_ | `200` |
|
||||
| is-saving | 是否显示保存按钮加载动画 | _boolean_ | `false` |
|
||||
| is-deleting | 是否显示删除按钮加载动画 | _boolean_ | `false` |
|
||||
| tel-validator | 手机号格式校验函数 | _string => boolean_ | - |
|
||||
| tel-maxlength | 手机号最大长度 | _number \| string_ | - |
|
||||
| postal-validator | 邮政编码格式校验函数 | _string => boolean_ | - |
|
||||
| validator | 自定义校验函数 | _(key, val) => string_ | - |
|
||||
|
||||
### Events
|
||||
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
| -------------- | -------------------------- | --------------------------- |
|
||||
| save | 点击保存按钮时触发 | content:表单内容 |
|
||||
| focus | 输入框聚焦时触发 | key: 聚焦的输入框对应的 key |
|
||||
| delete | 确认删除地址时触发 | content:表单内容 |
|
||||
| cancel-delete | 取消删除地址时触发 | content:表单内容 |
|
||||
| select-search | 选中搜索结果时触发 | value: 搜索结果 |
|
||||
| click-area | 点击收件地区时触发 | - |
|
||||
| change-area | 修改收件地区时触发 | values: 地区信息 |
|
||||
| change-detail | 修改详细地址时触发 | value: 详细地址内容 |
|
||||
| change-default | 切换是否使用默认地址时触发 | value: 是否选中 |
|
||||
|
||||
### Slots
|
||||
|
||||
| 名称 | 说明 |
|
||||
| ------- | ---------------------- |
|
||||
| default | 在邮政编码下方插入内容 |
|
||||
|
||||
### 方法
|
||||
|
||||
通过 ref 可以获取到 AddressEdit 实例并调用实例方法,详见[组件实例方法](#/zh-CN/advanced-usage#zu-jian-shi-li-fang-fa)。
|
||||
|
||||
| 方法名 | 说明 | 参数 | 返回值 |
|
||||
| ---------------- | ------------ | ----------------------- | ------ |
|
||||
| setAddressDetail | 设置详细地址 | _addressDetail: string_ | - |
|
||||
|
||||
### 类型定义
|
||||
|
||||
组件导出以下类型定义:
|
||||
|
||||
```ts
|
||||
import type {
|
||||
AddressEditInfo,
|
||||
AddressEditInstance,
|
||||
AddressEditSearchItem,
|
||||
} from 'vant';
|
||||
```
|
||||
|
||||
`AddressEditInstance` 是组件实例的类型,用法如下:
|
||||
|
||||
```ts
|
||||
import { ref } from 'vue';
|
||||
import type { AddressEditInstance } from 'vant';
|
||||
|
||||
const addressEditRef = ref<AddressEditInstance>();
|
||||
|
||||
addressEditRef.value?.setAddressDetail('');
|
||||
```
|
||||
|
||||
### AddressEditInfo 数据格式
|
||||
|
||||
注意:`AddressEditInfo` 仅作为初始值传入,表单最终内容可以在 save 事件中获取。
|
||||
|
||||
| key | 说明 | 类型 |
|
||||
| --- | --- | --- |
|
||||
| name | 姓名 | _string_ |
|
||||
| tel | 手机号 | _string_ |
|
||||
| province | 省份 | _string_ |
|
||||
| city | 城市 | _string_ |
|
||||
| county | 区县 | _string_ |
|
||||
| addressDetail | 详细地址 | _string_ |
|
||||
| areaCode | 地区编码,通过 [省市区选择](#/zh-CN/area) 获取(必填) | _string_ |
|
||||
| postalCode | 邮政编码 | _string_ |
|
||||
| isDefault | 是否为默认地址 | _boolean_ |
|
||||
|
||||
### AddressEditSearchItem 数据格式
|
||||
|
||||
| key | 说明 | 类型 |
|
||||
| ------- | -------- | -------- |
|
||||
| name | 地名 | _string_ |
|
||||
| address | 详细地址 | _string_ |
|
||||
|
||||
### 省市县列表数据格式
|
||||
|
||||
请参考 [Area 省市区选择](#/zh-CN/area) 组件。
|
||||
|
||||
## 主题定制
|
||||
|
||||
### 样式变量
|
||||
|
||||
组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 [ConfigProvider 组件](#/zh-CN/config-provider)。
|
||||
|
||||
| 名称 | 默认值 | 描述 |
|
||||
| --- | --- | --- |
|
||||
| --van-address-edit-padding | _var(--van-padding-sm)_ | - |
|
||||
| --van-address-edit-buttons-padding | _var(--van-padding-xl) var(--van-padding-base)_ | - |
|
||||
| --van-address-edit-button-margin-bottom | _var(--van-padding-sm)_ | - |
|
||||
| --van-address-edit-button-font-size | _var(--van-font-size-lg)_ | - |
|
||||
@@ -0,0 +1,73 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { areaList } from '@vant/area-data';
|
||||
import { useTranslate } from '@demo/use-translate';
|
||||
import { Toast } from '../../toast';
|
||||
|
||||
const t = useTranslate({
|
||||
'zh-CN': {
|
||||
areaColumnsPlaceholder: ['请选择', '请选择', '请选择'],
|
||||
searchResult: [
|
||||
{
|
||||
name: '黄龙万科中心',
|
||||
address: '杭州市西湖区',
|
||||
},
|
||||
{
|
||||
name: '黄龙万科中心G座',
|
||||
},
|
||||
{
|
||||
name: '黄龙万科中心H座',
|
||||
address: '杭州市西湖区',
|
||||
},
|
||||
],
|
||||
},
|
||||
'en-US': {
|
||||
areaColumnsPlaceholder: ['Choose', 'Choose', 'Choose'],
|
||||
searchResult: [
|
||||
{
|
||||
name: 'Name1',
|
||||
address: 'Address',
|
||||
},
|
||||
{
|
||||
name: 'Name2',
|
||||
},
|
||||
{
|
||||
name: 'Name3',
|
||||
address: 'Address',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
const searchResult = ref([]);
|
||||
|
||||
const onSave = () => Toast(t('save'));
|
||||
const onDelete = () => Toast(t('delete'));
|
||||
const onChangeDetail = (val: string) => {
|
||||
searchResult.value = val ? t('searchResult') : [];
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<demo-block :title="t('basicUsage')">
|
||||
<van-address-edit
|
||||
:area-list="areaList"
|
||||
show-postal
|
||||
show-delete
|
||||
show-set-default
|
||||
show-search-result
|
||||
:search-result="searchResult"
|
||||
:area-columns-placeholder="t('areaColumnsPlaceholder')"
|
||||
@save="onSave"
|
||||
@delete="onDelete"
|
||||
@change-detail="onChangeDetail"
|
||||
/>
|
||||
</demo-block>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.demo-address-edit {
|
||||
.van-doc-demo-block__title {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,46 @@
|
||||
@import './var.less';
|
||||
|
||||
:root {
|
||||
--van-address-edit-padding: @address-edit-padding;
|
||||
--van-address-edit-buttons-padding: @address-edit-buttons-padding;
|
||||
--van-address-edit-button-margin-bottom: @address-edit-button-margin-bottom;
|
||||
--van-contact-edit-button-font-size: @address-edit-button-font-size;
|
||||
}
|
||||
|
||||
.van-address-edit {
|
||||
padding: var(--van-address-edit-padding);
|
||||
|
||||
&__fields {
|
||||
overflow: hidden;
|
||||
border-radius: var(--van-padding-xs);
|
||||
|
||||
.van-field__label {
|
||||
width: 4.1em;
|
||||
}
|
||||
}
|
||||
|
||||
&__default {
|
||||
margin-top: var(--van-padding-sm);
|
||||
overflow: hidden;
|
||||
border-radius: var(--van-padding-xs);
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
padding: var(--van-address-edit-buttons-padding);
|
||||
}
|
||||
|
||||
&__button {
|
||||
margin-bottom: var(--van-address-edit-button-margin-bottom);
|
||||
font-size: var(--van-address-edit-button-font-size);
|
||||
}
|
||||
|
||||
&-detail {
|
||||
&__search-item {
|
||||
background-color: var(--van-gray-2);
|
||||
}
|
||||
|
||||
&__keyword {
|
||||
color: var(--van-danger-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { withInstall } from '../utils';
|
||||
import _AddressEdit from './AddressEdit';
|
||||
|
||||
export const AddressEdit = withInstall(_AddressEdit);
|
||||
export default AddressEdit;
|
||||
export type {
|
||||
AddressEditInfo,
|
||||
AddressEditInstance,
|
||||
AddressEditSearchItem,
|
||||
} from './types';
|
||||
@@ -0,0 +1,128 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should render demo and match snapshot 1`] = `
|
||||
<div>
|
||||
<div class="van-address-edit">
|
||||
<div class="van-address-edit__fields">
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Name
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
placeholder="Name"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Phone
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="tel"
|
||||
class="van-field__control"
|
||||
placeholder="Phone"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-cell--clickable van-field"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Area
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
readonly
|
||||
placeholder="Area"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<i class="van-badge__wrapper van-icon van-icon-arrow van-cell__right-icon">
|
||||
</i>
|
||||
</div>
|
||||
<div class="van-cell van-field van-address-edit-detail">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Address
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<textarea rows="1"
|
||||
class="van-field__control"
|
||||
placeholder="Address"
|
||||
style="height: auto;"
|
||||
>
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Postal
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="tel"
|
||||
class="van-field__control"
|
||||
placeholder="Postal"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-cell--center van-address-edit__default">
|
||||
<div class="van-cell__title">
|
||||
<span>
|
||||
Set as the default address
|
||||
</span>
|
||||
</div>
|
||||
<div role="switch"
|
||||
class="van-switch"
|
||||
style="font-size: 24px;"
|
||||
aria-checked="false"
|
||||
>
|
||||
<div class="van-switch__node">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-address-edit__buttons">
|
||||
<button type="button"
|
||||
class="van-button van-button--danger van-button--normal van-button--block van-button--round van-address-edit__button"
|
||||
>
|
||||
<div class="van-button__content">
|
||||
<span class="van-button__text">
|
||||
Save
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="van-button van-button--default van-button--normal van-button--block van-button--round van-address-edit__button"
|
||||
>
|
||||
<div class="van-button__content">
|
||||
<span class="van-button__text">
|
||||
Delete
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,418 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should allow to custom validator with validator prop 1`] = `
|
||||
<div class="van-field__error-message">
|
||||
foo name
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should render AddressEdit correctly 1`] = `
|
||||
<div class="van-address-edit">
|
||||
<div class="van-address-edit__fields">
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Name
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
placeholder="Name"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Phone
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="tel"
|
||||
class="van-field__control"
|
||||
placeholder="Phone"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-cell--clickable van-field"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Area
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
readonly
|
||||
placeholder="Area"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<i class="van-badge__wrapper van-icon van-icon-arrow van-cell__right-icon">
|
||||
</i>
|
||||
</div>
|
||||
<div class="van-cell van-field van-address-edit-detail">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Address
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<textarea rows="1"
|
||||
class="van-field__control"
|
||||
placeholder="Address"
|
||||
>
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-address-edit__buttons">
|
||||
<button type="button"
|
||||
class="van-button van-button--danger van-button--normal van-button--block van-button--round van-address-edit__button"
|
||||
>
|
||||
<div class="van-button__content">
|
||||
<span class="van-button__text">
|
||||
Save
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should render AddressEdit with props correctly 1`] = `
|
||||
<div class="van-address-edit">
|
||||
<div class="van-address-edit__fields">
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Name
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
placeholder="Name"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Phone
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="tel"
|
||||
class="van-field__control"
|
||||
placeholder="Phone"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-cell--clickable van-field"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Area
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
readonly
|
||||
placeholder="Area"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<i class="van-badge__wrapper van-icon van-icon-arrow van-cell__right-icon">
|
||||
</i>
|
||||
</div>
|
||||
<div class="van-cell van-field van-address-edit-detail">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Address
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<textarea rows="1"
|
||||
class="van-field__control"
|
||||
placeholder="Address"
|
||||
>
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Postal
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="tel"
|
||||
class="van-field__control"
|
||||
placeholder="Postal"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-cell--center van-address-edit__default">
|
||||
<div class="van-cell__title">
|
||||
<span>
|
||||
Set as the default address
|
||||
</span>
|
||||
</div>
|
||||
<div role="switch"
|
||||
class="van-switch van-switch--on"
|
||||
style="font-size: 24px;"
|
||||
aria-checked="true"
|
||||
>
|
||||
<div class="van-switch__node">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-address-edit__buttons">
|
||||
<button type="button"
|
||||
class="van-button van-button--danger van-button--normal van-button--block van-button--round van-address-edit__button"
|
||||
>
|
||||
<div class="van-button__content">
|
||||
<span class="van-button__text">
|
||||
Save
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should valid address detail and render error message correctly 1`] = `
|
||||
<div class="van-cell van-field van-address-edit-detail">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Address
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<textarea rows="1"
|
||||
class="van-field__control"
|
||||
placeholder="Address"
|
||||
style="height: auto;"
|
||||
>
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="van-field__error-message">
|
||||
Address can not be empty
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should valid address detail and render error message correctly 2`] = `
|
||||
<div class="van-cell van-field van-address-edit-detail">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Address
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<textarea rows="1"
|
||||
class="van-field__control"
|
||||
placeholder="Address"
|
||||
style="height: auto;"
|
||||
>
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should valid area code and render error message correctly 1`] = `
|
||||
<div class="van-cell van-cell--clickable van-field"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Area
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
readonly
|
||||
placeholder="Area"
|
||||
>
|
||||
</div>
|
||||
<div class="van-field__error-message">
|
||||
Please select a receiving area
|
||||
</div>
|
||||
</div>
|
||||
<i class="van-badge__wrapper van-icon van-icon-arrow van-cell__right-icon">
|
||||
</i>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should valid area code and render error message correctly 2`] = `
|
||||
<div class="van-cell van-cell--clickable van-field"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Area
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
readonly
|
||||
placeholder="Area"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<i class="van-badge__wrapper van-icon van-icon-arrow van-cell__right-icon">
|
||||
</i>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should valid name and render error message correctly 1`] = `
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Name
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
placeholder="Name"
|
||||
>
|
||||
</div>
|
||||
<div class="van-field__error-message">
|
||||
Please fill in the name
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should valid name and render error message correctly 2`] = `
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Name
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
placeholder="Name"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should valid postal code and render error message correctly 1`] = `
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Postal
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="tel"
|
||||
class="van-field__control"
|
||||
placeholder="Postal"
|
||||
>
|
||||
</div>
|
||||
<div class="van-field__error-message">
|
||||
Wrong postal code
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should valid postal code and render error message correctly 2`] = `
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Postal
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="tel"
|
||||
class="van-field__control"
|
||||
placeholder="Postal"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should valid tel and render error message correctly 1`] = `
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Phone
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="tel"
|
||||
class="van-field__control"
|
||||
placeholder="Phone"
|
||||
>
|
||||
</div>
|
||||
<div class="van-field__error-message">
|
||||
Malformed phone number
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`should valid tel and render error message correctly 2`] = `
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Phone
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="tel"
|
||||
class="van-field__control"
|
||||
placeholder="Phone"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,4 @@
|
||||
import Demo from '../demo/index.vue';
|
||||
import { snapshotDemo } from '../../../test/demo';
|
||||
|
||||
snapshotDemo(Demo);
|
||||
@@ -0,0 +1,267 @@
|
||||
import { AddressEdit } from '..';
|
||||
import { areaList } from '../../area/demo/area-simple';
|
||||
import { mount, later, trigger } from '../../../test';
|
||||
|
||||
const defaultAddressInfo = {
|
||||
name: '测试',
|
||||
tel: '13000000000',
|
||||
province: '北京市',
|
||||
city: '北京市',
|
||||
county: '朝阳区',
|
||||
addressDetail: 'address detail',
|
||||
areaCode: '110101',
|
||||
postalCode: '10000',
|
||||
isDefault: true,
|
||||
};
|
||||
|
||||
const createComponent = (addressInfo = {}) => {
|
||||
const wrapper = mount(AddressEdit, {
|
||||
props: {
|
||||
areaList,
|
||||
addressInfo: {
|
||||
...defaultAddressInfo,
|
||||
...addressInfo,
|
||||
},
|
||||
showPostal: true,
|
||||
showSetDefault: true,
|
||||
},
|
||||
});
|
||||
|
||||
const button = wrapper.find('.van-button');
|
||||
const fields = wrapper.findAll('.van-field');
|
||||
return {
|
||||
vm: wrapper.vm,
|
||||
fields,
|
||||
button,
|
||||
wrapper,
|
||||
};
|
||||
};
|
||||
|
||||
test('should render AddressEdit correctly', () => {
|
||||
expect(mount(AddressEdit).html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render AddressEdit with props correctly', () => {
|
||||
const wrapper = mount(AddressEdit, {
|
||||
props: {
|
||||
areaList,
|
||||
addressInfo: defaultAddressInfo,
|
||||
showPostal: true,
|
||||
showSetDefault: true,
|
||||
showSearchResult: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// test('set-default', () => {
|
||||
// const { wrapper } = createComponent();
|
||||
// wrapper.find('.van-switch').trigger('click');
|
||||
|
||||
// expect(wrapper.html()).toMatchSnapshot();
|
||||
// });
|
||||
|
||||
test('should allow to custom validator with validator prop', async () => {
|
||||
const wrapper = mount(AddressEdit, {
|
||||
props: {
|
||||
areaList,
|
||||
validator: (key, value) => `foo ${key}${value}`,
|
||||
},
|
||||
});
|
||||
|
||||
const button = wrapper.find('.van-button');
|
||||
await button.trigger('click');
|
||||
expect(wrapper.find('.van-field__error-message').html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should valid name and render error message correctly', async () => {
|
||||
const { fields, button } = createComponent({
|
||||
name: '',
|
||||
});
|
||||
|
||||
await button.trigger('click');
|
||||
expect(fields[0].html()).toMatchSnapshot();
|
||||
await fields[0].find('input').trigger('focus');
|
||||
expect(fields[0].html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should valid tel and render error message correctly', async () => {
|
||||
const { fields, button } = createComponent({
|
||||
tel: '',
|
||||
});
|
||||
|
||||
await button.trigger('click');
|
||||
expect(fields[1].html()).toMatchSnapshot();
|
||||
await fields[1].find('input').trigger('focus');
|
||||
expect(fields[1].html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should valid area code and render error message correctly', async () => {
|
||||
const { fields, button } = createComponent({
|
||||
areaCode: '',
|
||||
});
|
||||
|
||||
await button.trigger('click');
|
||||
expect(fields[2].html()).toMatchSnapshot();
|
||||
await fields[2].find('input').trigger('focus');
|
||||
expect(fields[2].html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should valid address detail and render error message correctly', async () => {
|
||||
const { fields, button } = createComponent({
|
||||
addressDetail: '',
|
||||
});
|
||||
|
||||
await button.trigger('click');
|
||||
expect(fields[3].html()).toMatchSnapshot();
|
||||
await fields[3].find('textarea').trigger('focus');
|
||||
expect(fields[3].html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should valid postal code and render error message correctly', async () => {
|
||||
const { fields, button } = createComponent({
|
||||
postalCode: '123',
|
||||
});
|
||||
|
||||
await button.trigger('click');
|
||||
expect(fields[4].html()).toMatchSnapshot();
|
||||
await fields[4].find('input').trigger('focus');
|
||||
expect(fields[4].html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should emit change-detail event after changing address detail', () => {
|
||||
const wrapper = mount(AddressEdit);
|
||||
const field = wrapper.findAll('.van-field__control')[3];
|
||||
|
||||
field.element.value = '123';
|
||||
field.trigger('input');
|
||||
expect(wrapper.emitted('change-detail')[0][0]).toEqual('123');
|
||||
});
|
||||
|
||||
test('should return current areas after calling getArea method', () => {
|
||||
const wrapper = mount(AddressEdit, {
|
||||
props: { areaList },
|
||||
});
|
||||
|
||||
expect(wrapper.vm.getArea()).toEqual([
|
||||
{ code: '110000', name: '北京市' },
|
||||
{ code: '110100', name: '北京市' },
|
||||
{ code: '110101', name: '东城区' },
|
||||
]);
|
||||
});
|
||||
|
||||
test('should update current areas after calling setAreaCode method', async () => {
|
||||
const wrapper = mount(AddressEdit, {
|
||||
props: { areaList },
|
||||
});
|
||||
|
||||
wrapper.vm.setAreaCode('110102');
|
||||
await later();
|
||||
expect(wrapper.vm.getArea()).toEqual([
|
||||
{ code: '110000', name: '北京市' },
|
||||
{ code: '110100', name: '北京市' },
|
||||
{ code: '110102', name: '西城区' },
|
||||
]);
|
||||
});
|
||||
|
||||
test('should show search result after focusing to address detail', async () => {
|
||||
const wrapper = mount(AddressEdit, {
|
||||
props: {
|
||||
showSearchResult: true,
|
||||
searchResult: [
|
||||
{ name: 'name1', address: 'address1' },
|
||||
{ name: 'name2' },
|
||||
{ address: 'address2' },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const field = wrapper.findAll('.van-field__control')[3];
|
||||
const input = field.element;
|
||||
await field.trigger('focus');
|
||||
|
||||
const items = wrapper.findAll('.van-icon-location-o');
|
||||
items[0].element.parentNode.click();
|
||||
await later();
|
||||
expect(input.value).toEqual('address1 name1');
|
||||
|
||||
items[1].element.parentNode.click();
|
||||
await later();
|
||||
expect(input.value).toEqual('name2');
|
||||
|
||||
items[2].element.parentNode.click();
|
||||
await later();
|
||||
expect(input.value).toEqual('address2');
|
||||
|
||||
await field.trigger('blur');
|
||||
await later(150);
|
||||
expect(wrapper.vm.detailFocused).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should emit delete event after clicking the delete button', async () => {
|
||||
const wrapper = mount(AddressEdit, {
|
||||
props: {
|
||||
showDelete: true,
|
||||
},
|
||||
});
|
||||
|
||||
const deleteButton = wrapper.findAll('.van-button')[1];
|
||||
deleteButton.trigger('click');
|
||||
await later();
|
||||
document.querySelector('.van-dialog__confirm').click();
|
||||
await later();
|
||||
expect(wrapper.emitted('delete')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should emit cancel-delete event after canceling deletion', async () => {
|
||||
const wrapper = mount(AddressEdit, {
|
||||
props: {
|
||||
showDelete: true,
|
||||
},
|
||||
});
|
||||
|
||||
const deleteButton = wrapper.findAll('.van-button')[1];
|
||||
deleteButton.trigger('click');
|
||||
await later();
|
||||
document.querySelector('.van-dialog__cancel').click();
|
||||
await later();
|
||||
expect(wrapper.emitted('cancel-delete')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should update address detail after calling the setAddressDetail method', async () => {
|
||||
const { vm, wrapper } = createComponent();
|
||||
const textarea = wrapper.find('.van-address-edit-detail').find('textarea');
|
||||
|
||||
expect(textarea.element.value).toEqual('address detail');
|
||||
|
||||
vm.setAddressDetail('test');
|
||||
await later();
|
||||
expect(textarea.element.value).toEqual('test');
|
||||
});
|
||||
|
||||
test('should emit click-area event after clicking the area field', () => {
|
||||
const wrapper = mount(AddressEdit, {
|
||||
props: {
|
||||
disableArea: true,
|
||||
},
|
||||
});
|
||||
|
||||
const field = wrapper.findAll('.van-field')[2];
|
||||
field.trigger('click');
|
||||
expect(wrapper.emitted('click-area')[0]).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should limit tel maxlength when using tel-maxlength prop', () => {
|
||||
const wrapper = mount(AddressEdit, {
|
||||
props: {
|
||||
telMaxlength: 4,
|
||||
},
|
||||
});
|
||||
|
||||
const telInput = wrapper.find('input[type="tel"]');
|
||||
telInput.element.value = '123456';
|
||||
trigger(telInput, 'input');
|
||||
|
||||
expect(telInput.element.value).toEqual('1234');
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { ComponentPublicInstance } from 'vue';
|
||||
import type { AreaColumnOption } from '../area';
|
||||
import type { AddressEditProps } from './AddressEdit';
|
||||
|
||||
export type AddressEditSearchItem = {
|
||||
name: string;
|
||||
address: string;
|
||||
};
|
||||
|
||||
export type AddressEditInfo = {
|
||||
tel: string;
|
||||
name: string;
|
||||
city: string;
|
||||
county: string;
|
||||
country: string;
|
||||
province: string;
|
||||
areaCode: string;
|
||||
isDefault?: boolean;
|
||||
postalCode?: string;
|
||||
addressDetail: string;
|
||||
};
|
||||
|
||||
export type AddressEditExpose = {
|
||||
getArea: () => AreaColumnOption[];
|
||||
setAreaCode: (code?: string | undefined) => void;
|
||||
setAddressDetail: (value: string) => void;
|
||||
};
|
||||
|
||||
export type AddressEditInstance = ComponentPublicInstance<
|
||||
AddressEditProps,
|
||||
AddressEditExpose
|
||||
>;
|
||||
@@ -0,0 +1,6 @@
|
||||
@import '../style/var.less';
|
||||
|
||||
@address-edit-padding: var(--van-padding-sm);
|
||||
@address-edit-buttons-padding: var(--van-padding-xl) var(--van-padding-base);
|
||||
@address-edit-button-margin-bottom: var(--van-padding-sm);
|
||||
@address-edit-button-font-size: var(--van-font-size-lg);
|
||||
@@ -0,0 +1,120 @@
|
||||
import { PropType, defineComponent } from 'vue';
|
||||
|
||||
// Utils
|
||||
import { truthProp, createNamespace } from '../utils';
|
||||
|
||||
// Components
|
||||
import { Button } from '../button';
|
||||
import { RadioGroup } from '../radio-group';
|
||||
import AddressListItem, { AddressListAddress } from './AddressListItem';
|
||||
|
||||
const [name, bem, t] = createNamespace('address-list');
|
||||
|
||||
export default defineComponent({
|
||||
name,
|
||||
|
||||
props: {
|
||||
modelValue: [Number, String],
|
||||
switchable: truthProp,
|
||||
disabledText: String,
|
||||
addButtonText: String,
|
||||
defaultTagText: String,
|
||||
list: {
|
||||
type: Array as PropType<AddressListAddress[]>,
|
||||
default: () => [],
|
||||
},
|
||||
disabledList: {
|
||||
type: Array as PropType<AddressListAddress[]>,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
|
||||
emits: [
|
||||
'add',
|
||||
'edit',
|
||||
'select',
|
||||
'click-item',
|
||||
'edit-disabled',
|
||||
'select-disabled',
|
||||
'update:modelValue',
|
||||
],
|
||||
|
||||
setup(props, { slots, emit }) {
|
||||
const renderItem = (
|
||||
item: AddressListAddress,
|
||||
index: number,
|
||||
disabled?: boolean
|
||||
) => {
|
||||
const onEdit = () => {
|
||||
const name = disabled ? 'edit-disabled' : 'edit';
|
||||
emit(name, item, index);
|
||||
};
|
||||
|
||||
const onClick = () => emit('click-item', item, index);
|
||||
|
||||
const onSelect = () => {
|
||||
const name = disabled ? 'select-disabled' : 'select';
|
||||
emit(name, item, index);
|
||||
|
||||
if (!disabled) {
|
||||
emit('update:modelValue', item.id);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<AddressListItem
|
||||
v-slots={{
|
||||
bottom: slots['item-bottom'],
|
||||
tag: slots.tag,
|
||||
}}
|
||||
key={item.id}
|
||||
address={item}
|
||||
disabled={disabled}
|
||||
switchable={props.switchable}
|
||||
defaultTagText={props.defaultTagText}
|
||||
onEdit={onEdit}
|
||||
onClick={onClick}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const renderList = (list: AddressListAddress[], disabled?: boolean) => {
|
||||
if (list) {
|
||||
return list.map((item, index) => renderItem(item, index, disabled));
|
||||
}
|
||||
};
|
||||
|
||||
const renderBottom = () => (
|
||||
<div class={[bem('bottom'), 'van-safe-area-bottom']}>
|
||||
<Button
|
||||
round
|
||||
block
|
||||
type="danger"
|
||||
text={props.addButtonText || t('add')}
|
||||
class={bem('add')}
|
||||
onClick={() => emit('add')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
return () => {
|
||||
const List = renderList(props.list);
|
||||
const DisabledList = renderList(props.disabledList, true);
|
||||
const DisabledText = props.disabledText && (
|
||||
<div class={bem('disabled-text')}>{props.disabledText}</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div class={bem()}>
|
||||
{slots.top?.()}
|
||||
<RadioGroup modelValue={props.modelValue}>{List}</RadioGroup>
|
||||
{DisabledText}
|
||||
{DisabledList}
|
||||
{slots.default?.()}
|
||||
{renderBottom()}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,110 @@
|
||||
import { PropType, defineComponent } from 'vue';
|
||||
|
||||
// Utils
|
||||
import { createNamespace, extend } from '../utils';
|
||||
|
||||
// Components
|
||||
import { Tag } from '../tag';
|
||||
import { Icon } from '../icon';
|
||||
import { Cell } from '../cell';
|
||||
import { Radio } from '../radio';
|
||||
|
||||
const [name, bem] = createNamespace('address-item');
|
||||
|
||||
export type AddressListAddress = {
|
||||
id: number | string;
|
||||
tel: number | string;
|
||||
name: string;
|
||||
address: string;
|
||||
isDefault?: boolean;
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name,
|
||||
|
||||
props: {
|
||||
disabled: Boolean,
|
||||
switchable: Boolean,
|
||||
defaultTagText: String,
|
||||
address: {
|
||||
type: Object as PropType<AddressListAddress>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
emits: ['edit', 'click', 'select'],
|
||||
|
||||
setup(props, { slots, emit }) {
|
||||
const onClick = () => {
|
||||
if (props.switchable) {
|
||||
emit('select');
|
||||
}
|
||||
emit('click');
|
||||
};
|
||||
|
||||
const renderRightIcon = () => (
|
||||
<Icon
|
||||
name="edit"
|
||||
class={bem('edit')}
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
emit('edit');
|
||||
emit('click');
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderTag = () => {
|
||||
if (slots.tag) {
|
||||
return slots.tag(props.address);
|
||||
}
|
||||
if (props.address.isDefault && props.defaultTagText) {
|
||||
return (
|
||||
<Tag type="danger" round class={bem('tag')}>
|
||||
{props.defaultTagText}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const renderContent = () => {
|
||||
const { address, disabled, switchable } = props;
|
||||
|
||||
const Info = [
|
||||
<div class={bem('name')}>
|
||||
{`${address.name} ${address.tel}`}
|
||||
{renderTag()}
|
||||
</div>,
|
||||
<div class={bem('address')}>{address.address}</div>,
|
||||
];
|
||||
|
||||
if (switchable && !disabled) {
|
||||
return (
|
||||
<Radio name={address.id} iconSize={18}>
|
||||
{Info}
|
||||
</Radio>
|
||||
);
|
||||
}
|
||||
|
||||
return Info;
|
||||
};
|
||||
|
||||
return () => {
|
||||
const { disabled } = props;
|
||||
|
||||
return (
|
||||
<div class={bem({ disabled })} onClick={onClick}>
|
||||
<Cell
|
||||
v-slots={{
|
||||
value: renderContent,
|
||||
'right-icon': renderRightIcon,
|
||||
}}
|
||||
border={false}
|
||||
valueClass={bem('value')}
|
||||
/>
|
||||
{slots.bottom?.(extend({}, props.address, { disabled }))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,152 @@
|
||||
# AddressList
|
||||
|
||||
### Intro
|
||||
|
||||
Display a list of receiving addresses.
|
||||
|
||||
### 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 { AddressList } from 'vant';
|
||||
|
||||
const app = createApp();
|
||||
app.use(AddressList);
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```html
|
||||
<van-address-list
|
||||
v-model="chosenAddressId"
|
||||
:list="list"
|
||||
:disabled-list="disabledList"
|
||||
disabled-text="The following address is out of range"
|
||||
default-tag-text="Default"
|
||||
@add="onAdd"
|
||||
@edit="onEdit"
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { Toast } from 'vant';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const chosenAddressId = ref('1');
|
||||
const list = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'John Snow',
|
||||
tel: '13000000000',
|
||||
address: 'Somewhere',
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Ned Stark',
|
||||
tel: '1310000000',
|
||||
address: 'Somewhere',
|
||||
},
|
||||
];
|
||||
const disabledList = [
|
||||
{
|
||||
id: '3',
|
||||
name: 'Tywin',
|
||||
tel: '1320000000',
|
||||
address: 'Somewhere',
|
||||
},
|
||||
];
|
||||
|
||||
const onAdd = () => Toast('Add');
|
||||
const onEdit = (item, index) => Toast('Edit:' + index);
|
||||
|
||||
return {
|
||||
list,
|
||||
onAdd,
|
||||
onEdit,
|
||||
disabledList,
|
||||
chosenAddressId,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| v-model | Id of chosen address | _string_ | - |
|
||||
| list | Address list | _Address[]_ | `[]` |
|
||||
| disabled-list | Disabled address list | _Address[]_ | `[]` |
|
||||
| disabled-text | Disabled text | _string_ | - |
|
||||
| switchable | Whether to allow switch address | _boolean_ | `true` |
|
||||
| add-button-text | Add button text | _string_ | `Add new address` |
|
||||
| default-tag-text | Default tag text | _string_ | - |
|
||||
|
||||
### Events
|
||||
|
||||
| Event | Description | Arguments |
|
||||
| --- | --- | --- |
|
||||
| add | Emitted when the add button is clicked | - |
|
||||
| edit | Emitted when the edit icon of address is clicked | _item: Address, index: number_ |
|
||||
| select | Emitted when an address is selected | _item: Address, index: number_ |
|
||||
| edit-disabled | Emitted when the edit icon of disabled address is clicked | _item: Address, index: number_ |
|
||||
| select-disabled | Emitted when a disabled address is selected | _item: Address, index: number_ |
|
||||
| click-item | Emitted when an address item is clicked | _item: Address, index: number_ |
|
||||
|
||||
### Data Structure of Address
|
||||
|
||||
| Key | Description | Type |
|
||||
| --------- | ------------------ | ------------------ |
|
||||
| id | Id | _number \| string_ |
|
||||
| name | Name | _string_ |
|
||||
| tel | Phone | _number \| string_ |
|
||||
| address | Address | _string_ |
|
||||
| isDefault | Is default address | _boolean_ |
|
||||
|
||||
### Slots
|
||||
|
||||
| Name | Description | SlotProps |
|
||||
| ------------ | ------------------------------ | --------------- |
|
||||
| default | Custom content after list | - |
|
||||
| top | Custom content before list | - |
|
||||
| item-bottom | Custom content after list item | _item: Address_ |
|
||||
| tag `v3.0.9` | Custom tag of list item | _item: Address_ |
|
||||
|
||||
### Types
|
||||
|
||||
The component exports the following type definitions:
|
||||
|
||||
```ts
|
||||
import type { AddressListAddress } from 'vant';
|
||||
```
|
||||
|
||||
## Theming
|
||||
|
||||
### CSS Variables
|
||||
|
||||
The component provides the following CSS variables, which can be used to customize styles. Please refer to [ConfigProvider component](#/en-US/config-provider).
|
||||
|
||||
| Name | Default Value | Description |
|
||||
| --- | --- | --- |
|
||||
| --van-address-list-padding | _var(--van-padding-sm) var(--van-padding-sm) 80px_ | - |
|
||||
| --van-address-list-disabled-text-color | _var(--van-gray-6)_ | - |
|
||||
| --van-address-list-disabled-text-padding | _var(--van-padding-base) \* 5 0 var(--van-padding-md)_ | - |
|
||||
| --van-address-list-disabled-text-font-size | _var(--van-font-size-md)_ | - |
|
||||
| --van-address-list-disabled-text-line-height | _var(--van-line-height-md)_ | - |
|
||||
| --van-address-list-add-button-z-index | _999_ | - |
|
||||
| --van-address-list-item-padding | _var(--van-padding-sm)_ | - |
|
||||
| --van-address-list-item-text-color | _var(--van-text-color)_ | - |
|
||||
| --van-address-list-item-disabled-text-color | _var(--van-gray-5)_ | - |
|
||||
| --van-address-list-item-font-size | _13px_ | - |
|
||||
| --van-address-list-item-line-height | _var(--van-line-height-sm)_ | - |
|
||||
| --van-address-list-item-radio-icon-color | _var(--van-danger-color)_ | - |
|
||||
| --van-address-list-edit-icon-size | _20px_ | - |
|
||||
@@ -0,0 +1,152 @@
|
||||
# AddressList 地址列表
|
||||
|
||||
### 介绍
|
||||
|
||||
展示地址信息列表。
|
||||
|
||||
### 引入
|
||||
|
||||
通过以下方式来全局注册组件,更多注册方式请参考[组件注册](#/zh-CN/advanced-usage#zu-jian-zhu-ce)。
|
||||
|
||||
```js
|
||||
import { createApp } from 'vue';
|
||||
import { AddressList } from 'vant';
|
||||
|
||||
const app = createApp();
|
||||
app.use(AddressList);
|
||||
```
|
||||
|
||||
## 代码演示
|
||||
|
||||
### 基础用法
|
||||
|
||||
```html
|
||||
<van-address-list
|
||||
v-model="chosenAddressId"
|
||||
:list="list"
|
||||
:disabled-list="disabledList"
|
||||
disabled-text="以下地址超出配送范围"
|
||||
default-tag-text="默认"
|
||||
@add="onAdd"
|
||||
@edit="onEdit"
|
||||
/>
|
||||
```
|
||||
|
||||
```js
|
||||
import { ref } from 'vue';
|
||||
import { Toast } from 'vant';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const chosenAddressId = ref('1');
|
||||
const list = [
|
||||
{
|
||||
id: '1',
|
||||
name: '张三',
|
||||
tel: '13000000000',
|
||||
address: '浙江省杭州市西湖区文三路 138 号东方通信大厦 7 楼 501 室',
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: '李四',
|
||||
tel: '1310000000',
|
||||
address: '浙江省杭州市拱墅区莫干山路 50 号',
|
||||
},
|
||||
];
|
||||
const disabledList = [
|
||||
{
|
||||
id: '3',
|
||||
name: '王五',
|
||||
tel: '1320000000',
|
||||
address: '浙江省杭州市滨江区江南大道 15 号',
|
||||
},
|
||||
];
|
||||
|
||||
const onAdd = () => Toast('新增地址');
|
||||
const onEdit = (item, index) => Toast('编辑地址:' + index);
|
||||
|
||||
return {
|
||||
list,
|
||||
onAdd,
|
||||
onEdit,
|
||||
disabledList,
|
||||
chosenAddressId,
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| ---------------- | ----------------- | ---------------------- | ---------- |
|
||||
| v-model | 当前选中地址的 id | _string_ | - |
|
||||
| list | 地址列表 | _AddressListAddress[]_ | `[]` |
|
||||
| disabled-list | 不可配送地址列表 | _AddressListAddress[]_ | `[]` |
|
||||
| disabled-text | 不可配送提示文案 | _string_ | - |
|
||||
| switchable | 是否允许切换地址 | _boolean_ | `true` |
|
||||
| add-button-text | 底部按钮文字 | _string_ | `新增地址` |
|
||||
| default-tag-text | 默认地址标签文字 | _string_ | - |
|
||||
|
||||
### Events
|
||||
|
||||
| 事件名 | 说明 | 回调参数 |
|
||||
| --- | --- | --- |
|
||||
| add | 点击新增按钮时触发 | - |
|
||||
| edit | 点击编辑按钮时触发 | _item: AddressListAddress, index: number_ |
|
||||
| select | 切换选中的地址时触发 | _item: AddressListAddress, index: number_ |
|
||||
| edit-disabled | 编辑不可配送的地址时触发 | _item: AddressListAddress, index: number_ |
|
||||
| select-disabled | 选中不可配送的地址时触发 | _item: AddressListAddress, index: number_ |
|
||||
| click-item | 点击任意地址时触发 | _item: AddressListAddress, index: number_ |
|
||||
|
||||
### AddressListAddress 数据结构
|
||||
|
||||
| 键名 | 说明 | 类型 |
|
||||
| --------- | ------------------ | ------------------ |
|
||||
| id | 每条地址的唯一标识 | _number \| string_ |
|
||||
| name | 姓名 | _string_ |
|
||||
| tel | 手机号 | _number \| string_ |
|
||||
| address | 详细地址 | _string_ |
|
||||
| isDefault | 是否为默认地址 | _boolean_ |
|
||||
|
||||
### Slots
|
||||
|
||||
| 名称 | 说明 | 参数 |
|
||||
| ------------ | -------------------- | -------------------------- |
|
||||
| default | 在列表下方插入内容 | - |
|
||||
| top | 在顶部插入内容 | - |
|
||||
| item-bottom | 在列表项底部插入内容 | _item: AddressListAddress_ |
|
||||
| tag `v3.0.9` | 自定义列表项标签内容 | _item: AddressListAddress_ |
|
||||
|
||||
### 类型定义
|
||||
|
||||
组件导出以下类型定义:
|
||||
|
||||
```ts
|
||||
import type { AddressListAddress } from 'vant';
|
||||
```
|
||||
|
||||
## 主题定制
|
||||
|
||||
### 样式变量
|
||||
|
||||
组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 [ConfigProvider 组件](#/zh-CN/config-provider)。
|
||||
|
||||
| 名称 | 默认值 | 描述 |
|
||||
| --- | --- | --- |
|
||||
| --van-address-list-padding | _var(--van-padding-sm) var(--van-padding-sm) 80px_ | - |
|
||||
| --van-address-list-disabled-text-color | _var(--van-gray-6)_ | - |
|
||||
| --van-address-list-disabled-text-padding | _var(--van-padding-base) \* 5 0 var(--van-padding-md)_ | - |
|
||||
| --van-address-list-disabled-text-font-size | _var(--van-font-size-md)_ | - |
|
||||
| --van-address-list-disabled-text-line-height | _var(--van-line-height-md)_ | - |
|
||||
| --van-address-list-add-button-z-index | _999_ | - |
|
||||
| --van-address-list-item-padding | _var(--van-padding-sm)_ | - |
|
||||
| --van-address-list-item-text-color | _var(--van-text-color)_ | - |
|
||||
| --van-address-list-item-disabled-text-color | _var(--van-gray-5)_ | - |
|
||||
| --van-address-list-item-font-size | _13px_ | - |
|
||||
| --van-address-list-item-line-height | _var(--van-line-height-sm)_ | - |
|
||||
| --van-address-list-item-radio-icon-color | _var(--van-danger-color)_ | - |
|
||||
| --van-address-list-edit-icon-size | _20px_ | - |
|
||||
@@ -0,0 +1,96 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useTranslate } from '@demo/use-translate';
|
||||
import { Toast } from '../../toast';
|
||||
|
||||
const t = useTranslate({
|
||||
'zh-CN': {
|
||||
list: [
|
||||
{
|
||||
id: '1',
|
||||
name: '张三',
|
||||
tel: '13000000000',
|
||||
address: '浙江省杭州市西湖区文三路 138 号东方通信大厦 7 楼 501 室',
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: '李四',
|
||||
tel: '1310000000',
|
||||
address: '浙江省杭州市拱墅区莫干山路 50 号',
|
||||
},
|
||||
],
|
||||
disabledList: [
|
||||
{
|
||||
id: '3',
|
||||
name: '王五',
|
||||
tel: '1320000000',
|
||||
address: '浙江省杭州市滨江区江南大道 15 号',
|
||||
},
|
||||
],
|
||||
add: '新增地址',
|
||||
edit: '编辑地址',
|
||||
disabledText: '以下地址超出配送范围',
|
||||
defaultTagText: '默认',
|
||||
},
|
||||
'en-US': {
|
||||
list: [
|
||||
{
|
||||
id: '1',
|
||||
name: 'John Snow',
|
||||
tel: '13000000000',
|
||||
address: 'Somewhere',
|
||||
isDefault: true,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Ned Stark',
|
||||
tel: '1310000000',
|
||||
address: 'Somewhere',
|
||||
},
|
||||
],
|
||||
disabledList: [
|
||||
{
|
||||
id: '3',
|
||||
name: 'Tywin',
|
||||
tel: '1320000000',
|
||||
address: 'Somewhere',
|
||||
},
|
||||
],
|
||||
add: 'Add',
|
||||
edit: 'Edit',
|
||||
disabledText: 'The following address is out of range',
|
||||
defaultTagText: 'Default',
|
||||
},
|
||||
});
|
||||
|
||||
const chosenAddressId = ref('1');
|
||||
const onAdd = () => {
|
||||
Toast(t('add'));
|
||||
};
|
||||
const onEdit = (item: unknown, index: number) => {
|
||||
Toast(`${t('edit')}:${index}`);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<demo-block :title="t('basicUsage')">
|
||||
<van-address-list
|
||||
v-model="chosenAddressId"
|
||||
:list="t('list')"
|
||||
:disabled-list="t('disabledList')"
|
||||
:disabled-text="t('disabledText')"
|
||||
:default-tag-text="t('defaultTagText')"
|
||||
@add="onAdd"
|
||||
@edit="onEdit"
|
||||
/>
|
||||
</demo-block>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.demo-address-list {
|
||||
.van-doc-demo-block__title {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,112 @@
|
||||
@import './var.less';
|
||||
|
||||
:root {
|
||||
--van-address-list-padding: @address-list-padding;
|
||||
--van-address-list-disabled-text-color: @address-list-disabled-text-color;
|
||||
--van-address-list-disabled-text-padding: @address-list-disabled-text-padding;
|
||||
--van-address-list-disabled-text-font-size: @address-list-disabled-text-font-size;
|
||||
--van-address-list-disabled-text-line-height: @address-list-disabled-text-line-height;
|
||||
--van-address-list-add-button-z-index: @address-list-add-button-z-index;
|
||||
--van-address-list-item-padding: @address-list-item-padding;
|
||||
--van-address-list-item-text-color: @address-list-item-text-color;
|
||||
--van-address-list-item-disabled-text-color: @address-list-item-disabled-text-color;
|
||||
--van-address-list-item-font-size: @address-list-item-font-size;
|
||||
--van-address-list-item-line-height: @address-list-item-line-height;
|
||||
--van-address-list-item-radio-icon-color: @address-list-item-radio-icon-color;
|
||||
--van-address-list-edit-icon-size: @address-list-edit-icon-size;
|
||||
}
|
||||
|
||||
.van-address-list {
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
padding: var(--van-address-list-padding);
|
||||
|
||||
&__bottom {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: var(--van-address-list-add-button-z-index);
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding-left: var(--van-padding-md);
|
||||
padding-right: var(--van-padding-md);
|
||||
background-color: var(--van-white);
|
||||
}
|
||||
|
||||
&__add {
|
||||
height: 40px;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
&__disabled-text {
|
||||
padding: var(--van-address-list-disabled-text-padding);
|
||||
color: var(--van-address-list-disabled-text-color);
|
||||
font-size: var(--van-address-list-disabled-text-font-size);
|
||||
line-height: var(--van-address-list-disabled-text-line-height);
|
||||
}
|
||||
}
|
||||
|
||||
.van-address-item {
|
||||
padding: var(--van-address-list-item-padding);
|
||||
background-color: var(--van-white);
|
||||
border-radius: var(--van-border-radius-lg);
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: var(--van-padding-sm);
|
||||
}
|
||||
|
||||
&__value {
|
||||
padding-right: 44px;
|
||||
}
|
||||
|
||||
&__name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: var(--van-padding-xs);
|
||||
font-size: var(--van-font-size-lg);
|
||||
line-height: var(--van-line-height-lg);
|
||||
}
|
||||
|
||||
&__tag {
|
||||
flex: none;
|
||||
margin-left: var(--van-padding-xs);
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
&__address {
|
||||
color: var(--van-address-list-item-text-color);
|
||||
font-size: var(--van-address-list-item-font-size);
|
||||
line-height: var(--van-address-list-item-line-height);
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
.van-address-item__name,
|
||||
.van-address-item__address {
|
||||
color: var(--van-address-list-item-disabled-text-color);
|
||||
}
|
||||
}
|
||||
|
||||
&__edit {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: var(--van-padding-md);
|
||||
color: var(--van-gray-6);
|
||||
font-size: var(--van-address-list-edit-icon-size);
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
|
||||
.van-cell {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.van-radio__label {
|
||||
margin-left: var(--van-padding-sm);
|
||||
}
|
||||
|
||||
.van-radio__icon--checked .van-icon {
|
||||
background-color: var(--van-address-list-item-radio-icon-color);
|
||||
border-color: var(--van-address-list-item-radio-icon-color);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user