Merge branch 'dev' into next

This commit is contained in:
chenjiahan 2022-05-02 11:03:12 +08:00
commit b65396ef06
46 changed files with 3037 additions and 308 deletions

View File

@ -18,7 +18,6 @@
"build-site": "vant-cli build-site && gh-pages -d site-dist"
},
"author": "",
"license": "MIT",
"husky": {
"hooks": {
"pre-commit": "lint-staged",

View File

@ -22,7 +22,6 @@
"test:coverage": "open test/coverage/index.html"
},
"author": "",
"license": "MIT",
"lint-staged": {
"*.md": "prettier --write",
"*.{ts,tsx,js,vue,less,scss}": "prettier --write",

View File

@ -1,10 +1,13 @@
{
"name": "@vant/area-data",
"version": "1.2.3",
"version": "1.2.4",
"description": "Vant 省市区数据",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"clean": "rimraf ./dist",
"dev": "node ./build.js -w",

View File

@ -1,36 +1,40 @@
# Vant CLI
Vant CLI 是一个 Vue 组件库构建工具,通过 Vant CLI 可以快速搭建一套功能完备的 Vue 组件库。
Vant CLI is a tool for building vue component library. You can quickly build a full-featured Vue component library with vant-cli.
### 特性
🇨🇳 <a href="./README.zh-CN.md">查看中文版介绍</a>
- 提供丰富的命令,涵盖从开发测试到构建发布的完整流程
- 基于约定的目录结构,自动生成优雅的文档站点和组件示例
- 内置 ESLint、Stylelint 校验规则,提交代码时自动执行校验
- 构建后的组件库默认支持按需引入、主题定制、Tree Shaking
---
### 快速上手
### Features
执行以下命令可以快速创建一个基于 Vant CLI 的项目:
- Provides rich commands covering the complete process from development to deploy
- Based on conventional directory structure. Generate elegant document website and component examples automatically.
- ESlint Stylelint built-in.
- Support Tree Shaking/Theme Customization/Import on Demand
### Quickstart
To create a Vant CLI project, run:
```bash
yarn create vant-cli-app
```
### 手动安装
### Install Manually
```shell
# 通过 npm
# via npm
npm i @vant/cli -D
# 通过 yarn
# via yarn
yarn add @vant/cli -D
# 通过 pnpm
# via pnpm
pnpm add @vant/cli -D
```
安装完成后,请将以下配置添加到 package.json 文件中
Please add the followed config to `package.json` file.
```json
{
@ -63,9 +67,9 @@ pnpm add @vant/cli -D
}
```
## 详细文档
## More Details
- [命令](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/commands.md)
- [配置指南](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/config.md)
- [目录结构](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/directory.md)
- [更新日志](https://github.com/youzan/vant/tree/dev/packages/vant-cli/changelog.md)
- [cli](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/commands.md)
- [config](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/config.md)
- [directory structure](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/directory.md)
- [CHANGELOG](https://github.com/youzan/vant/tree/dev/packages/vant-cli/changelog.md)

View File

@ -0,0 +1,71 @@
# Vant CLI
Vant CLI 是一个 Vue 组件库构建工具,通过 Vant CLI 可以快速搭建一套功能完备的 Vue 组件库。
### 特性
- 提供丰富的命令,涵盖从开发测试到构建发布的完整流程
- 基于约定的目录结构,自动生成优雅的文档站点和组件示例
- 内置 ESLint、Stylelint 校验规则,提交代码时自动执行校验
- 构建后的组件库默认支持按需引入、主题定制、Tree Shaking
### 快速上手
执行以下命令可以快速创建一个基于 Vant CLI 的项目:
```bash
yarn create vant-cli-app
```
### 手动安装
```shell
# 通过 npm
npm i @vant/cli -D
# 通过 yarn
yarn add @vant/cli -D
# 通过 pnpm
pnpm add @vant/cli -D
```
安装完成后,请将以下配置添加到 package.json 文件中
```json
{
"scripts": {
"dev": "vant-cli dev",
"test": "vant-cli test",
"lint": "vant-cli lint",
"build": "vant-cli build",
"prepare": "husky install",
"release": "vant-cli release",
"build-site": "vant-cli build-site"
},
"lint-staged": {
"*.md": "prettier --write",
"*.{ts,tsx,js,vue,less,scss}": "prettier --write",
"*.{ts,tsx,js,vue}": "eslint --fix",
"*.{vue,css,less,scss}": "stylelint --fix"
},
"eslintConfig": {
"root": true,
"extends": ["@vant"]
},
"stylelint": {
"extends": ["@vant/stylelint-config"]
},
"prettier": {
"singleQuote": true
},
"browserslist": ["Chrome >= 51", "iOS >= 10"]
}
```
## 详细文档
- [命令](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/commands.zh-CN.md)
- [配置指南](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/config.zh-CN.md)
- [目录结构](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/directory.zh-CN.md)
- [更新日志](https://github.com/youzan/vant/tree/dev/packages/vant-cli/changelog.md)

View File

@ -1,6 +1,6 @@
# 命令
# Commands
Vant CLI 中内置了一系列的命令,可以将命令添加到 npm scripts 中进行使用。
You can add built-in commands to `npm scripts` to use it.
```json
// package.json
@ -15,7 +15,7 @@ Vant CLI 中内置了一系列的命令,可以将命令添加到 npm scripts
}
```
也可以通过 npm 自带的 [npx](https://github.com/npm/npx) 直接执行某个命令:
Additionally, [npx](https://github.com/npm/npx) can used to be run those commands.
```bash
npx vant-cli dev
@ -23,17 +23,15 @@ npx vant-cli dev
### dev
运行本地开发环境。
运行 dev 命令时Vant CLI 会通过启动一个本地服务器,用于在开发过程中对文档和示例进行预览。
Start local dev server for browsering components and demo.
### build
构建组件库。
Build Vue component library.
运行 build 命令会在 `es``lib` 目录下生成可用于生产环境的组件代码,详见 [目录结构](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/directory.md)
Files will be output to `es` and `lib` directory. More details [directory structure](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/directory.md)
发布 npm 时,请将以下配置加入到 `package.json` 中,使 npm 包能被正确识别:
Please add the followed config to `package.json` when publish to npm.
```json
// package.json
@ -46,19 +44,19 @@ npx vant-cli dev
### build-site
构建文档站点,在 `site` 目录生成可用于生产环境的文档站点代码。
Build documentation website. Files will be output to `site` directory.
### release
发布组件库,发布前会自动执行 build 和 changelog 命令,并通过 [release-it](https://github.com/release-it/release-it) 发布 npm 包。
Publish to npm. `build` and `changelog` will be automatically execute when run `release`.
## changelog
### changelog
基于 commit 记录生成更新日志,基于 [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog) 实现。
Generate changelog based on commit records.
## commit-lint
### commit-lint
校验 commit message 的格式是否符合规范,需要配合 `husky` 在提交 commit 时触发。
Validate the format of commit message. Need `husky` to do this.
```bash
npx husky add .husky/commit-msg 'npx --no-install vant-cli commit-lint $1'

View File

@ -0,0 +1,65 @@
# 命令
Vant CLI 中内置了一系列的命令,可以将命令添加到 npm scripts 中进行使用。
```json
// package.json
{
"scripts": {
"dev": "vant-cli dev",
"test": "vant-cli test",
"lint": "vant-cli lint",
"release": "vant-cli release",
"build-site": "vant-cli build-site"
}
}
```
也可以通过 npm 自带的 [npx](https://github.com/npm/npx) 直接执行某个命令:
```bash
npx vant-cli dev
```
### dev
运行本地开发环境。
运行 dev 命令时Vant CLI 会通过启动一个本地服务器,用于在开发过程中对文档和示例进行预览。
### build
构建组件库。
运行 build 命令会在 `es``lib` 目录下生成可用于生产环境的组件代码,详见 [目录结构](https://github.com/youzan/vant/tree/dev/packages/vant-cli/docs/directory.zh-CN.md)。
发布 npm 时,请将以下配置加入到 `package.json` 中,使 npm 包能被正确识别:
```json
// package.json
{
"main": "lib/index.js",
"module": "es/index.js",
"files": ["es", "lib"]
}
```
### build-site
构建文档站点,在 `site` 目录生成可用于生产环境的文档站点代码。
### release
发布组件库,发布前会自动执行 build 和 changelog 命令,并通过 [release-it](https://github.com/release-it/release-it) 发布 npm 包。
### changelog
基于 commit 记录生成更新日志,基于 [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog) 实现。
### commit-lint
校验 commit message 的格式是否符合规范,需要配合 `husky` 在提交 commit 时触发。
```bash
npx husky add .husky/commit-msg 'npx --no-install vant-cli commit-lint $1'
```

View File

@ -1,6 +1,6 @@
# 配置指南
# Config
- [配置指南](#----)
- [Config](#----)
- [vant.config.mjs](#vantconfigmjs)
- [name](#name)
- [build.css.base](#buildcssbase)
@ -22,48 +22,48 @@
- [site.htmlMeta](#sitehtmlmeta)
- [site.enableVConsole](#siteenablevconsole)
- [PostCSS](#postcss)
- [默认配置](#-----1)
- [Default Config](#-----1)
- [browserslist](#browserslist)
## vant.config.mjs
`vant.config.mjs` 中包含了 `vant-cli` 的打包配置和文档站点配置,请创建此文件并置于项目根目录下。下面是一份基本配置的示例:
`vant.config.mjs` includes bundle and documentation site config. Please create this file and place it in your project root directory. Here is a basic example:
```js
export default {
// 组件库名称
// component library name
name: 'demo-ui',
// 构建配置
// bundle config
build: {
site: {
publicPath: '/demo-ui/',
},
},
// 文档站点配置
// documentation site config
site: {
// 标题
// title
title: 'Demo UI',
// 图标
// logo
logo: 'https://cdn.jsdelivr.net/npm/@vant/assets/logo.png',
// 描述
// description
description: '示例组件库',
// 左侧导航
// left nav
nav: [
{
title: '开发指南',
title: 'example',
items: [
{
path: 'home',
title: '介绍',
title: 'home',
},
],
},
{
title: '基础组件',
title: 'basic components',
items: [
{
path: 'my-button',
title: 'MyButton 按钮',
title: 'MyButton',
},
],
},
@ -77,16 +77,16 @@ export default {
- Type: `string`
- Default: `''`
组件库名称,建议使用中划线分割,如 `demo-ui`
Component library name. kebab-case recommended.
### build.css.base
- Type: `string`
- Default: `'style/base.less'`
全局样式文件的路径,可以为相对路径或绝对路径。
Global style file path. Support absolute path and relative path both.
相对路径基于 `src` 目录计算。
Note: relative path is calculated based on `src`.
```js
module.exports = {
@ -103,7 +103,7 @@ module.exports = {
- Type: `string`
- Default: `'less'`
CSS 预处理器配置,目前支持 `less``sass` 两种预处理器,默认使用 `less`
CSS preprocess Config, support `less` and `sass`. Use `less` by default.
```js
module.exports = {
@ -120,9 +120,9 @@ module.exports = {
- Type: `string`
- Default: `/`
等价于 vite 的 `build.outDir` 配置。
Equivalent to vite `build.outDir`.
一般来说,我们的文档网站会部署在一个域名的子路径上,如 `https://my.github.io/demo-ui/`,这时候 `publicPath` 需要跟子路径保持一致,即 `/demo-ui/`
Generally, documentation site will be deployed to subpath of domain. For example: `https://my.github.io/demo-ui/`, `publicPath` should be `/demo-ui/`.
```js
module.exports = {
@ -152,24 +152,24 @@ module.exports = {
- Type: `boolean`
- Default: `false`
是否通过 Named Export 对组件进行导出。
Should export components by Named Export.
未开启此选项时,会通过 `export default from 'xxx'` 导出组件内部的默认模块。
When set to `false`, `export default from 'xxx'` will be used to export module.
开启此选项后,会通过 `export * from 'xxx'` 导出组件内部的所有模块、类型定义。
When set to `true`, `export * from 'xxx'` will be used to export all modules and type definition.
### build.configureVite
- Type: `(config: InlineConfig): InlineConfig`
- Default: `undefined`
vant-cli 使用 vite 来构建组件库和文档站点,通过 `configureVite` 选项可以自定义 vite 配置(从 4.0.0 版本开始支持)。
Custom vite config(`@vant/cli>= 4.0.0`)
```js
module.exports = {
build: {
configureVite(config) {
// 添加一个自定义插件
// add vite plugin
config.plugins.push(vitePluginXXX);
return config;
},
@ -177,8 +177,6 @@ module.exports = {
};
```
在自定义配置时,可以通过 `process.env.BUILD_TARGET` 对构建目标进行区分:
```js
module.exports = {
build: {
@ -186,11 +184,11 @@ module.exports = {
const { BUILD_TARGET } = process.env;
if (BUILD_TARGET === 'package') {
// 修改组件库构建配置
// component library bundle config
}
if (BUILD_TARGET === 'site') {
// 修改文档站点构建配置
// documentation site bundle config
}
return config;
@ -204,51 +202,51 @@ module.exports = {
- Type: `'npm' | 'yarn' | 'pnpm'`
- Default: `undefined`
指定使用的包管理器。
`npm` package manager.
### site.title
- Type: `string`
- Default: `''`
文档站点的标题。
Documentation site title.
### site.logo
- Type: `string`
- Default: `''`
文档站点的 Logo。
Documentation site logo.
### site.description
- Type: `string`
- Default: `''`
标题下方的描述文案。
Documentation site description.
### site.nav
- Type: `object[]`
- Default: `undefined`
文档站点的左侧导航,数组中的每个对象表示一个导航分组。
Documentation site left nav. Each item of `nav` means a navigation group.
```js
module.exports = {
site: {
nav: [
{
// 分组标题
title: '开发指南',
// 导航项
// group title
title: 'Development Guide',
// nav items
items: [
{
// 导航项路由
// nav router
path: 'home',
// 导航项文案
title: '介绍',
// 是否隐藏当前页右侧的手机模拟器(默认不隐藏)
// nav title
title: 'title',
// should hide phone emulator(false by default)
hideSimulator: true,
},
],
@ -263,7 +261,7 @@ module.exports = {
- Type: `object[]`
- Default: `undefined`
文档站点多版本配置,当组件库存在多个版本的文档时,可以通过`site.versions`在顶部导航配置一个版本切换按钮。
Documentation site muti-version config.
```js
module.exports = {
@ -281,17 +279,17 @@ module.exports = {
### site.baiduAnalytics
- Type: `object`
- Default: `undefied`
- Default: `undefined`
文档网站的百度统计配置,添加这项配置后,会自动在构建文档网站时加载百度统计的脚本。
Documentation site baidu analysis config. The script of Baidu Statistic will be automatically loaded when build documentation website.
```js
module.exports = {
site: {
baiduAnalytics: {
// 打开百度统计 ->『管理』->『代码获取』
// 找到下面这串 URL: "https://hm.baidu.com/hm.js?xxxxx"
// `xxxxx` 填写在 seed 中即可
// find the followed URL: "https://hm.baidu.com/hm.js?xxxxx"
// add `xxxxx` in the seed
seed: 'xxxxx',
},
},
@ -303,45 +301,43 @@ module.exports = {
- Type: `object`
- Default: `undefined`
文档网站的搜索配置,基于 algolia 提供的 docsearch 服务实现。
配置内容参见 [docsearch](https://docsearch.algolia.com/docs/behavior)。
Documentation site search config. Based on [docsearch](https://docsearch.algolia.com/docs/behavior) of algolia.
### site.hideSimulator
- Type: `boolean`
- Default: `false`
是否隐藏所有页面右侧的手机模拟器,默认不隐藏
Should hide phone emulator, `false` by default.
### site.simulator.url
- Type: `string`
- Default: -
自定义手机模拟器的 iframe URL 地址。
Customize iframe URL.
### site.htmlMeta
- Type: `Record<string, string>`
- Default: `undefined`
配置 HTML 中的 meta 标签,对象的 key 为 namevalue 为 content。
Customize HTML meta tag, key means name, value means content.
### site.enableVConsole
- Type: `boolean`
- Default: `false`
是否在 dev 时开启 [vConsole](https://github.com/Tencent/vConsole) 调试,用于移动端 debug。
Should use [vConsole](https://github.com/Tencent/vConsole) to debug when dev. For mobile.
## PostCSS
通过根目录下的`postcss.config.js`文件可以对 PostCSS 进行配置。
PostCSS can be configured through the `postcss.config.js` file in the root directory.
### 默认配置
### Default Config
`vant-cli` 中默认的 PostCSS 配置如下:
PostCSS default config:
```js
module.exports = {
@ -353,9 +349,9 @@ module.exports = {
## browserslist
推荐在 `package.json` 文件里添加 browserslist 字段,这个值会被 `autoprefixer` 用来确定目标浏览器的版本,保证编译后代码的兼容性。
Add browserslist field to `package.json` file is recommended. It's used by `autoprefixer` to determine the version of target browser, ensuring compatibility of compiled code.
在移动端浏览器中使用,可以添加如下配置:
You can add the following config for mobile:
```json
{

View File

@ -0,0 +1,364 @@
# 配置指南
- [配置指南](#----)
- [vant.config.mjs](#vantconfigmjs)
- [name](#name)
- [build.css.base](#buildcssbase)
- [build.css.preprocessor](#buildcsspreprocessor)
- [build.site.publicPath](#buildsitepublicpath)
- [build.srcDir](#buildsrcdir)
- [build.namedExport](#buildnamedexport)
- [build.configureVite](#buildconfigurevite)
- [build.packageManager](#buildpackagemanager)
- [site.title](#sitetitle)
- [site.logo](#sitelogo)
- [site.description](#sitedescription)
- [site.nav](#sitenav)
- [site.versions](#siteversions)
- [site.baiduAnalytics](#sitebaiduanalytics)
- [site.searchConfig](#sitesearchconfig)
- [site.hideSimulator](#sitehidesimulator)
- [site.simulator.url](#sitesimulatorurl)
- [site.htmlMeta](#sitehtmlmeta)
- [site.enableVConsole](#siteenablevconsole)
- [PostCSS](#postcss)
- [默认配置](#-----1)
- [browserslist](#browserslist)
## vant.config.mjs
`vant.config.mjs` 中包含了 `vant-cli` 的打包配置和文档站点配置,请创建此文件并置于项目根目录下。下面是一份基本配置的示例:
```js
export default {
// 组件库名称
name: 'demo-ui',
// 构建配置
build: {
site: {
publicPath: '/demo-ui/',
},
},
// 文档站点配置
site: {
// 标题
title: 'Demo UI',
// 图标
logo: 'https://cdn.jsdelivr.net/npm/@vant/assets/logo.png',
// 描述
description: '示例组件库',
// 左侧导航
nav: [
{
title: '开发指南',
items: [
{
path: 'home',
title: '介绍',
},
],
},
{
title: '基础组件',
items: [
{
path: 'my-button',
title: 'MyButton 按钮',
},
],
},
],
},
};
```
### name
- Type: `string`
- Default: `''`
组件库名称,建议使用中划线分割,如 `demo-ui`
### build.css.base
- Type: `string`
- Default: `'style/base.less'`
全局样式文件的路径,可以为相对路径或绝对路径。
相对路径基于 `src` 目录计算。
```js
module.exports = {
build: {
css: {
base: 'style/global.scss',
},
},
};
```
### build.css.preprocessor
- Type: `string`
- Default: `'less'`
CSS 预处理器配置,目前支持 `less``sass` 两种预处理器,默认使用 `less`
```js
module.exports = {
build: {
css: {
preprocessor: 'sass',
},
},
};
```
### build.site.publicPath
- Type: `string`
- Default: `/`
等价于 vite 的 `build.outDir` 配置。
一般来说,我们的文档网站会部署在一个域名的子路径上,如 `https://my.github.io/demo-ui/`,这时候 `publicPath` 需要跟子路径保持一致,即 `/demo-ui/`
```js
module.exports = {
build: {
site: {
publicPath: '/demo-ui/',
},
},
};
```
### build.srcDir
- Type: `string`
- Default: `src`
```js
module.exports = {
build: {
srcDir: 'myDir',
},
};
```
### build.namedExport
- Type: `boolean`
- Default: `false`
是否通过 Named Export 对组件进行导出。
未开启此选项时,会通过 `export default from 'xxx'` 导出组件内部的默认模块。
开启此选项后,会通过 `export * from 'xxx'` 导出组件内部的所有模块、类型定义。
### build.configureVite
- Type: `(config: InlineConfig): InlineConfig`
- Default: `undefined`
vant-cli 使用 vite 来构建组件库和文档站点,通过 `configureVite` 选项可以自定义 vite 配置(从 4.0.0 版本开始支持)。
```js
module.exports = {
build: {
configureVite(config) {
// 添加一个自定义插件
config.plugins.push(vitePluginXXX);
return config;
},
},
};
```
在自定义配置时,可以通过 `process.env.BUILD_TARGET` 对构建目标进行区分:
```js
module.exports = {
build: {
configureVite(config) {
const { BUILD_TARGET } = process.env;
if (BUILD_TARGET === 'package') {
// 修改组件库构建配置
}
if (BUILD_TARGET === 'site') {
// 修改文档站点构建配置
}
return config;
},
},
};
```
### build.packageManager
- Type: `'npm' | 'yarn' | 'pnpm'`
- Default: `undefined`
指定使用的包管理器。
### site.title
- Type: `string`
- Default: `''`
文档站点的标题。
### site.logo
- Type: `string`
- Default: `''`
文档站点的 Logo。
### site.description
- Type: `string`
- Default: `''`
标题下方的描述文案。
### site.nav
- Type: `object[]`
- Default: `undefined`
文档站点的左侧导航,数组中的每个对象表示一个导航分组。
```js
module.exports = {
site: {
nav: [
{
// 分组标题
title: '开发指南',
// 导航项
items: [
{
// 导航项路由
path: 'home',
// 导航项文案
title: '介绍',
// 是否隐藏当前页右侧的手机模拟器(默认不隐藏)
hideSimulator: true,
},
],
},
],
},
};
```
### site.versions
- Type: `object[]`
- Default: `undefined`
文档站点多版本配置,当组件库存在多个版本的文档时,可以通过`site.versions`在顶部导航配置一个版本切换按钮。
```js
module.exports = {
site: {
versions: [
{
label: 'v1',
link: 'https://youzan.github.io/vant/v1/',
},
],
},
};
```
### site.baiduAnalytics
- Type: `object`
- Default: `undefied`
文档网站的百度统计配置,添加这项配置后,会自动在构建文档网站时加载百度统计的脚本。
```js
module.exports = {
site: {
baiduAnalytics: {
// 打开百度统计 ->『管理』->『代码获取』
// 找到下面这串 URL: "https://hm.baidu.com/hm.js?xxxxx"
// 将 `xxxxx` 填写在 seed 中即可
seed: 'xxxxx',
},
},
};
```
### site.searchConfig
- Type: `object`
- Default: `undefined`
文档网站的搜索配置,基于 algolia 提供的 docsearch 服务实现。
配置内容参见 [docsearch](https://docsearch.algolia.com/docs/behavior)。
### site.hideSimulator
- Type: `boolean`
- Default: `false`
是否隐藏所有页面右侧的手机模拟器,默认不隐藏
### site.simulator.url
- Type: `string`
- Default: -
自定义手机模拟器的 iframe URL 地址。
### site.htmlMeta
- Type: `Record<string, string>`
- Default: `undefined`
配置 HTML 中的 meta 标签,对象的 key 为 namevalue 为 content。
### site.enableVConsole
- Type: `boolean`
- Default: `false`
是否在 dev 时开启 [vConsole](https://github.com/Tencent/vConsole) 调试,用于移动端 debug。
## PostCSS
通过根目录下的`postcss.config.js`文件可以对 PostCSS 进行配置。
### 默认配置
`vant-cli` 中默认的 PostCSS 配置如下:
```js
module.exports = {
plugins: {
autoprefixer: {},
},
};
```
## browserslist
推荐在 `package.json` 文件里添加 browserslist 字段,这个值会被 `autoprefixer` 用来确定目标浏览器的版本,保证编译后代码的兼容性。
在移动端浏览器中使用,可以添加如下配置:
```json
{
"browserslist": ["Chrome >= 51", "iOS >= 10"]
}
```

View File

@ -1,91 +1,91 @@
# 目录结构
# Directory Structure
## 源代码目录
## Source Code Directory
基于 Vant CLI 搭建的组件库的基本目录结构如下所示:
The basic directory structure of the component library based on Vant CLI is as follows:
```
project
├─ src # 组件源代码
│ ├─ button # button 组件源代码
│ └─ dialog # dialog 组件源代码
├─ src # component library source code
│ ├─ button # button source code
│ └─ dialog # dialog source code
├─ docs # 静态文档目录
│ ├─ home.md # 文档首页
│ └─ changelog.md # 更新日志
├─ docs # static doc directory
│ ├─ home.md # documentation site home
│ └─ changelog.md # changelog
├─ vant.config.mjs # Vant CLI 配置文件
├─ vant.config.mjs # Vant CLI config file
├─ package.json
└─ README.md
```
单个组件的目录如下:
The directories for individual components are as follows:
```
button
├─ demo # 示例目录
│ └─ index.vue # 组件示例
├─ index.vue # 组件源码
└─ README.md # 组件文档
├─ demo # component demo directory
│ └─ index.vue # component demo
├─ index.vue # component source code
└─ README.md # component doc
```
使用 .vue 文件编写组件时,编译后会生成对应的 JS 和 CSS 文件,且 JS 文件中会自动引入 CSS 文件。
When writing SFC, the corresponding JS and CSS files will be generated after bundle process, and the CSS file will be automatically imported into the JS file.
如果需要将 JS 和 CSS 解耦,实现主题定制等功能,在编写代码时就要使用独立的 JS 和 CSS 文件,如下所示:
If you need to separate JS and CSS to implement functions such as theme customization, you need to use separate JS and CSS files when writing code, as shown below:
```
button
├─ demo # 组件示例
│ └─ index.vue # 组件示例入口
├─ index.js # 组件入口
├─ index.less # 组件样式,可以为 less 或 scss
└─ README.md # 组件文档
├─ demo # component demo directory
│ └─ index.vue # component demo entry
├─ index.js # component entry
├─ index.less # component stylesupport scss and less
└─ README.md # component doc
```
采用这种目录结构时,组件的使用者需要分别引入 JS 和 CSS 文件,也可以通过 babel-plugin-import 自动引入样式。
When using this directory structure, the developer of the component library needs to import the JS and CSS files respectively, and the styles can also be imported automatically through babel-plugin-import.
通过引入样式源文件less 或 scss并修改样式变量可以实现主题定制功能。
Theme customization can be achieved by importing style source files (less or scss) and modifying style variables.
## 构建结果目录
## Output Directory
运行 build 命令会在 `es``lib` 目录下生成可用于生产环境的组件代码,结构如下:
Running the `build` command will generate production code in the `es` and `lib` directories with the following structure:
```
project
├─ es # es 目录下的代码遵循 esmodule 规范
│ ├─ button # button 组件编译后的代码目录
│ ├─ dialog # dialog 组件编译后的代码目录
│ └─ index.js # 引入所有组件的入口 (ESModule)
├─ es # ESM Directory
│ ├─ button # button component directory
│ ├─ dialog # dialog component directory
│ └─ index.js # All component files entry (ESModule)
└─ lib # lib 目录下的代码遵循 commonjs 规范
├─ button # button 组件编译后的代码目录
├─ dialog # dialog 组件编译后的代码目录
├─ index.js # 引入所有组件的入口
├─ index.less # 所有组件未编译的样式入口
├─ index.css # 打包后的组件样式,用于 CDN 引入
├─ [name].js # 打包后的组件脚本UMD 格式
├─ [name].es.js # 打包后的组件脚本ESModule 格式
├─ [name].min.js # 打包和压缩后的组件脚本UMD 格式
└─ [name].es.min.js # 打包和压缩后的组件脚本ESModule 格式
└─ lib # Commonjs directory
├─ button # button component library
├─ dialog # dialog component library
├─ index.js # All component files entry (Commonjs)
├─ index.less # All component styles entry(Uncompiled)
├─ index.css # Bundle component styles for CDN
├─ [name].js # Bundle script for UMD
├─ [name].es.js # Bundle script for ESM
├─ [name].min.js # Bundle and minified script for UMD
└─ [name].es.min.js # Bundle and minified script for ESM
```
单个组件编译后的目录如下:
The compiled directory of a single component is as follows:
```
button
├─ index.js # 组件编译后的 JS 文件
├─ index.css # 组件编译后的 CSS 文件
├─ index.less # 组件编译前的 CSS 文件,可以为 less 或 scss
└─ style # 按需引入样式的入口
├─ index.js # 按需引入编译后的样式
└─ less.js # 按需引入未编译的样式,可用于主题定制
├─ index.js # Bundle script file
├─ index.css # Bundle CSS file
├─ index.less # Uncompiled CSS file, less or scss
└─ style # Style entry on demand directory
├─ index.js # Compiled styles on demand
└─ less.js # Uncompiled styles on demand, for theme customization
```
### 生成类型声明
### Generate type definition
当组件库使用 TS 编写,且根目录下存在 `tsconfig.declaration.json` 文件Vant CLI 会自动生成 `.d.ts` 类型声明文件。
When the component library is written in TS and the `tsconfig.declaration.json` file exists in the root directory, Vant CLI will automatically generate the `.d.ts` type declaration file.
`tsconfig.declaration.json` 的参考格式如下:
The format of `tsconfig.declaration.json` is as follows:
```json
{
@ -100,7 +100,7 @@ button
}
```
成功生成类型声明后,请在 `package.json` 中添加类型入口声明:
Please add the `typings` field in `package.json` after generate type declaration:
```json
{

View File

@ -0,0 +1,109 @@
# 目录结构
## 源代码目录
基于 Vant CLI 搭建的组件库的基本目录结构如下所示:
```
project
├─ src # 组件源代码
│ ├─ button # button 组件源代码
│ └─ dialog # dialog 组件源代码
├─ docs # 静态文档目录
│ ├─ home.md # 文档首页
│ └─ changelog.md # 更新日志
├─ vant.config.mjs # Vant CLI 配置文件
├─ package.json
└─ README.md
```
单个组件的目录如下:
```
button
├─ demo # 示例目录
│ └─ index.vue # 组件示例
├─ index.vue # 组件源码
└─ README.md # 组件文档
```
使用 .vue 文件编写组件时,编译后会生成对应的 JS 和 CSS 文件,且 JS 文件中会自动引入 CSS 文件。
如果需要将 JS 和 CSS 解耦,实现主题定制等功能,在编写代码时就要使用独立的 JS 和 CSS 文件,如下所示:
```
button
├─ demo # 组件示例
│ └─ index.vue # 组件示例入口
├─ index.js # 组件入口
├─ index.less # 组件样式,可以为 less 或 scss
└─ README.md # 组件文档
```
采用这种目录结构时,组件的使用者需要分别引入 JS 和 CSS 文件,也可以通过 babel-plugin-import 自动引入样式。
通过引入样式源文件less 或 scss并修改样式变量可以实现主题定制功能。
## 构建结果目录
运行 build 命令会在 `es``lib` 目录下生成可用于生产环境的组件代码,结构如下:
```
project
├─ es # es 目录下的代码遵循 esmodule 规范
│ ├─ button # button 组件编译后的代码目录
│ ├─ dialog # dialog 组件编译后的代码目录
│ └─ index.js # 引入所有组件的入口 (ESModule)
└─ lib # lib 目录下的代码遵循 commonjs 规范
├─ button # button 组件编译后的代码目录
├─ dialog # dialog 组件编译后的代码目录
├─ index.js # 引入所有组件的入口
├─ index.less # 所有组件未编译的样式入口
├─ index.css # 打包后的组件样式,用于 CDN 引入
├─ [name].js # 打包后的组件脚本UMD 格式
├─ [name].es.js # 打包后的组件脚本ESModule 格式
├─ [name].min.js # 打包和压缩后的组件脚本UMD 格式
└─ [name].es.min.js # 打包和压缩后的组件脚本ESModule 格式
```
单个组件编译后的目录如下:
```
button
├─ index.js # 组件编译后的 JS 文件
├─ index.css # 组件编译后的 CSS 文件
├─ index.less # 组件编译前的 CSS 文件,可以为 less 或 scss
└─ style # 按需引入样式的入口
├─ index.js # 按需引入编译后的样式
└─ less.js # 按需引入未编译的样式,可用于主题定制
```
### 生成类型声明
当组件库使用 TS 编写,且根目录下存在 `tsconfig.declaration.json` 文件Vant CLI 会自动生成 `.d.ts` 类型声明文件。
`tsconfig.declaration.json` 的参考格式如下:
```json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"declaration": true,
"declarationDir": ".",
"emitDeclarationOnly": true
},
"include": ["es/**/*", "lib/**/*"],
"exclude": ["node_modules", "**/test/**/*", "**/demo/**/*"]
}
```
成功生成类型声明后,请在 `package.json` 中添加类型入口声明:
```json
{
"typings": "lib/index.d.ts"
}
```

View File

@ -0,0 +1,40 @@
# usePageVisibility
### Intro
Get the visible state of the page.
## Usage
### Basic Usage
```js
import { watch } from 'vue';
import { usePageVisibility } from '@vant/use';
export default {
setup() {
const pageVisibility = usePageVisibility();
watch(pageVisibility, (value) => {
console.log('visibility: ', value);
});
},
};
```
## API
### Type Declarations
```ts
type VisibilityState = 'visible' | 'hidden';
function usePageVisibility(): Ref<VisibilityState>;
```
### Return Value
| Name | Description | Type |
| --- | --- | --- |
| visibilityState | The current visible state of the page, could be `visible` or `hidden` | _Ref\<VisibilityState>_ |

View File

@ -0,0 +1,52 @@
# useRect
### Intro
Get the size of an element and its position relative to the viewport, equivalent to [Element.getBoundingClientRect](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect).
## Usage
### Basic Usage
```html
<div ref="root" />
```
```js
import { ref, onMounted } from 'vue';
import { useRect } from '@vant/use';
export default {
setup() {
const root = ref();
onMounted(() => {
const rect = useRect(root);
console.log(rect); // -> the size of an element and its position relative to the viewport
});
return { root };
},
};
```
## API
### Type Declarations
```ts
function useRect(
element: Element | Window | Ref<Element | Window | undefined>
): DOMRect;
```
### Return Value
| Name | Description | Type |
| --- | --- | --- |
| width | Width of the element | _number_ |
| height | Height of the element | _number_ |
| top | The distance from the top to the top-left of the viewport | _number_ |
| left | The distance from the left to the top-left of the viewport | _number_ |
| right | The distance from the right to the top-left of the viewport | _number_ |
| bottom | The distance from the bottom to the top-left of the viewport | _number_ |

View File

@ -0,0 +1,80 @@
# useRelation
### Intro
Establish the association relationship between parent and child components, perform data communication and method invocation, based on `provide` and `inject` implementation.
## Usage
### Basic Usage
Use `useChildren` in parent to associate child components:
```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++;
};
// provide data and methods to children
linkChildren({ add, count });
},
};
```
Use `useParent` in child component to get the data and methods provided by parent.
```js
import { useParent } from '@vant/use';
export default {
setup() {
const { parent } = useParent(RELATION_KEY);
// use data and methods provided by parent
if (parent) {
parent.add();
console.log(parent.count.value); // -> 1
}
},
};
```
## API
### Type Declarations
```ts
function useParent<T>(key: string | symbol): {
parent?: T;
index?: Ref<number>;
};
function useChildren(key: string | symbol): {
children: ComponentPublicInstance[];
linkChildren: (value: any) => void;
};
```
### Return Value of useParent
| Name | Description | Type |
| --- | --- | --- |
| parent | Data and methods provided by parent | _any_ |
| index | Index position of the current component in all child of the parent component | _Ref\<number>_ |
### Return Value of useChildren
| Name | Description | Type |
| --- | --- | --- |
| children | Component list of children | _ComponentPublicInstance[]_ |
| linkChildren | Function to provide values to child | _(value: any) => void_ |

View File

@ -0,0 +1,57 @@
# useScrollParent
### Intro
Get the closest parent element that is scrollable.
## Usage
### Basic Usage
```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
### Type Declarations
```ts
function useScrollParent(
element: Ref<Element | undefined>
): Ref<Element | Window | undefined>;
```
### Params
| Name | Description | Type | Default Value |
| ------- | ------------------- | --------------- | ------------- |
| element | The current element | _Ref\<Element>_ | - |
### Return Value
| Name | Description | Type |
| --- | --- | --- |
| scrollParent | The closest parent element that is scrollable | _Ref\<Element>_ |

View File

@ -0,0 +1,45 @@
# useWindowSize
### Intro
Get the viewport width and height of the browser window, and update it automatically when the window size changes.
## Usage
### Basic Usage
```js
import { watch } from 'vue';
import { useWindowSize } from '@vant/use';
export default {
setup() {
const { width, height } = useWindowSize();
console.log(width.value); // -> width of browser window
console.log(height.value); // -> height of browser window
watch([width, height], () => {
console.log('window resized');
});
},
};
```
## API
### Type Declarations
```ts
function useWindowSize(): {
width: Ref<number>;
height: Ref<number>;
};
```
### Return Value
| Name | Description | Type |
| ------ | ---------------------------- | -------------- |
| width | The width of browser window | _Ref\<number>_ |
| height | The height of browser window | _Ref\<number>_ |

View File

@ -36,4 +36,11 @@ console.log(height.value); // -> window height
| --- | --- |
| [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 |
| [useCustomFieldValue](#/en-US/use-custom-field-value) | Used to custom Field value |
| [useEventListener](#/en-US/use-event-listener) | Used to attach event |
| [usePageVisibility](#/en-US/use-page-visibility) | Get the visible state of the page |
| [useRect](#/en-US/use-rect) | Get the size of an element and its position relative to the viewport |
| [useRelation](#/en-US/use-relation) | Establish the association relationship between parent and child components |
| [useScrollParent](#/en-US/use-scroll-parent) | Get the closest parent element that is scrollable |
| [useToggle](#/en-US/use-toggle) | Used to switch between `true` and `false` |
| [useWindowSize](#/en-US/use-window-size) | Get the viewport width and height of the browser window |

View File

@ -40,6 +40,7 @@ console.log(height.value); // -> 窗口高度
| --- | --- |
| [useClickAway](#/zh-CN/use-click-away) | 监听点击元素外部的事件 |
| [useCountDown](#/zh-CN/use-count-down) | 提供倒计时管理能力 |
| [useCustomFieldValue](#/zh-CN/use-custom-field-value) | 自定义表单组件中的表单项 |
| [useEventListener](#/zh-CN/use-event-listener) | 方便地进行事件绑定 |
| [usePageVisibility](#/zh-CN/use-page-visibility) | 获取页面的可见状态 |
| [useRect](#/zh-CN/use-rect) | 获取元素的大小及其相对于视口的位置 |

View File

@ -117,7 +117,10 @@ exports[`should render demo and match snapshot 1`] = `
class="van-button van-button--primary van-button--normal van-button--loading"
>
<div class="van-button__content">
<div class="van-loading van-loading--circular van-button__loading">
<div class="van-loading van-loading--circular van-button__loading"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular">
<svg class="van-loading__circular"
viewbox="25 25 50 50"
@ -137,7 +140,10 @@ exports[`should render demo and match snapshot 1`] = `
class="van-button van-button--primary van-button--normal van-button--loading"
>
<div class="van-button__content">
<div class="van-loading van-loading--spinner van-button__loading">
<div class="van-loading van-loading--spinner van-button__loading"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--spinner">
<i class="van-loading__line van-loading__line--1">
</i>
@ -171,7 +177,10 @@ exports[`should render demo and match snapshot 1`] = `
class="van-button van-button--success van-button--normal van-button--loading"
>
<div class="van-button__content">
<div class="van-loading van-loading--circular van-button__loading">
<div class="van-loading van-loading--circular van-button__loading"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular">
<svg class="van-loading__circular"
viewbox="25 25 50 50"

View File

@ -364,7 +364,169 @@ exports[`should have two "van-coupon-list__empty" classes when render coupon lis
>
<div class="van-empty">
<div class="van-empty__image">
<img src="https://img.yzcdn.cn/vant/empty-image-default.png">
<svg viewbox="0 0 160 160">
<defs>
<linearGradient x1="50%"
x2="50%"
y2="100%"
id="van-empty-5"
>
<stop stop-color="#F2F3F5"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient x1="95%"
y1="48%"
x2="5.5%"
y2="51%"
id="van-empty-6"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient y1="45%"
x2="100%"
y2="54%"
id="van-empty-7"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<defs>
<linearGradient id="van-empty-a"
x1="64%"
y1="100%"
x2="64%"
>
<stop stop-color="#FFF"
offset="0%"
stop-opacity="0.5"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M36 131V53H16v20H2v58h34z"
fill="url(#van-empty-a)"
>
</path>
<path d="M123 15h22v14h9v77h-31V15z"
fill="url(#van-empty-a)"
>
</path>
</g>
<defs>
<linearGradient id="van-empty-b"
x1="64%"
y1="97%"
x2="64%"
y2="0%"
>
<stop stop-color="#F2F3F5"
offset="0%"
stop-opacity="0.3"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M87 6c3 0 7 3 8 6a8 8 0 1 1-1 16H80a7 7 0 0 1-8-6c0-4 3-7 6-7 0-5 4-9 9-9Z"
fill="url(#van-empty-b)"
>
</path>
<path d="M19 23c2 0 3 1 4 3 2 0 4 2 4 4a4 4 0 0 1-4 3v1h-7v-1l-1 1c-2 0-3-2-3-4 0-1 1-3 3-3 0-2 2-4 4-4Z"
fill="url(#van-empty-b)"
>
</path>
</g>
<g transform="translate(36 50)"
fill="none"
>
<g transform="translate(8)">
<rect fill="#EBEDF0"
opacity=".6"
x="38"
y="13"
width="36"
height="53"
rx="2"
>
</rect>
<rect fill="url(#van-empty-5)"
width="64"
height="66"
rx="2"
>
</rect>
<rect fill="#FFF"
x="6"
y="6"
width="52"
height="55"
rx="1"
>
</rect>
<g transform="translate(15 17)"
fill="url(#van-empty-6)"
>
<rect width="34"
height="6"
rx="1"
>
</rect>
<path d="M0 14h34v6H0z">
</path>
<rect y="28"
width="34"
height="6"
rx="1"
>
</rect>
</g>
</g>
<rect fill="url(#van-empty-7)"
y="61"
width="88"
height="28"
rx="1"
>
</rect>
<rect fill="#F7F8FA"
x="29"
y="72"
width="30"
height="6"
rx="1"
>
</rect>
</g>
</svg>
</div>
<div class="van-empty__bottom">
<p class="van-coupon-list__empty-tip">
@ -386,7 +548,169 @@ exports[`should have two "van-coupon-list__empty" classes when render coupon lis
>
<div class="van-empty">
<div class="van-empty__image">
<img src="https://img.yzcdn.cn/vant/empty-image-default.png">
<svg viewbox="0 0 160 160">
<defs>
<linearGradient x1="50%"
x2="50%"
y2="100%"
id="van-empty-5"
>
<stop stop-color="#F2F3F5"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient x1="95%"
y1="48%"
x2="5.5%"
y2="51%"
id="van-empty-6"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient y1="45%"
x2="100%"
y2="54%"
id="van-empty-7"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<defs>
<linearGradient id="van-empty-a"
x1="64%"
y1="100%"
x2="64%"
>
<stop stop-color="#FFF"
offset="0%"
stop-opacity="0.5"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M36 131V53H16v20H2v58h34z"
fill="url(#van-empty-a)"
>
</path>
<path d="M123 15h22v14h9v77h-31V15z"
fill="url(#van-empty-a)"
>
</path>
</g>
<defs>
<linearGradient id="van-empty-b"
x1="64%"
y1="97%"
x2="64%"
y2="0%"
>
<stop stop-color="#F2F3F5"
offset="0%"
stop-opacity="0.3"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M87 6c3 0 7 3 8 6a8 8 0 1 1-1 16H80a7 7 0 0 1-8-6c0-4 3-7 6-7 0-5 4-9 9-9Z"
fill="url(#van-empty-b)"
>
</path>
<path d="M19 23c2 0 3 1 4 3 2 0 4 2 4 4a4 4 0 0 1-4 3v1h-7v-1l-1 1c-2 0-3-2-3-4 0-1 1-3 3-3 0-2 2-4 4-4Z"
fill="url(#van-empty-b)"
>
</path>
</g>
<g transform="translate(36 50)"
fill="none"
>
<g transform="translate(8)">
<rect fill="#EBEDF0"
opacity=".6"
x="38"
y="13"
width="36"
height="53"
rx="2"
>
</rect>
<rect fill="url(#van-empty-5)"
width="64"
height="66"
rx="2"
>
</rect>
<rect fill="#FFF"
x="6"
y="6"
width="52"
height="55"
rx="1"
>
</rect>
<g transform="translate(15 17)"
fill="url(#van-empty-6)"
>
<rect width="34"
height="6"
rx="1"
>
</rect>
<path d="M0 14h34v6H0z">
</path>
<rect y="28"
width="34"
height="6"
rx="1"
>
</rect>
</g>
</g>
<rect fill="url(#van-empty-7)"
y="61"
width="88"
height="28"
rx="1"
>
</rect>
<rect fill="#F7F8FA"
x="29"
y="72"
width="30"
height="6"
rx="1"
>
</rect>
</g>
</svg>
</div>
<div class="van-empty__bottom">
<p class="van-coupon-list__empty-tip">
@ -484,7 +808,169 @@ exports[`should render list-footer slot correctly 1`] = `
>
<div class="van-empty">
<div class="van-empty__image">
<img src="https://img.yzcdn.cn/vant/empty-image-default.png">
<svg viewbox="0 0 160 160">
<defs>
<linearGradient x1="50%"
x2="50%"
y2="100%"
id="van-empty-5"
>
<stop stop-color="#F2F3F5"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient x1="95%"
y1="48%"
x2="5.5%"
y2="51%"
id="van-empty-6"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient y1="45%"
x2="100%"
y2="54%"
id="van-empty-7"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<defs>
<linearGradient id="van-empty-a"
x1="64%"
y1="100%"
x2="64%"
>
<stop stop-color="#FFF"
offset="0%"
stop-opacity="0.5"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M36 131V53H16v20H2v58h34z"
fill="url(#van-empty-a)"
>
</path>
<path d="M123 15h22v14h9v77h-31V15z"
fill="url(#van-empty-a)"
>
</path>
</g>
<defs>
<linearGradient id="van-empty-b"
x1="64%"
y1="97%"
x2="64%"
y2="0%"
>
<stop stop-color="#F2F3F5"
offset="0%"
stop-opacity="0.3"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M87 6c3 0 7 3 8 6a8 8 0 1 1-1 16H80a7 7 0 0 1-8-6c0-4 3-7 6-7 0-5 4-9 9-9Z"
fill="url(#van-empty-b)"
>
</path>
<path d="M19 23c2 0 3 1 4 3 2 0 4 2 4 4a4 4 0 0 1-4 3v1h-7v-1l-1 1c-2 0-3-2-3-4 0-1 1-3 3-3 0-2 2-4 4-4Z"
fill="url(#van-empty-b)"
>
</path>
</g>
<g transform="translate(36 50)"
fill="none"
>
<g transform="translate(8)">
<rect fill="#EBEDF0"
opacity=".6"
x="38"
y="13"
width="36"
height="53"
rx="2"
>
</rect>
<rect fill="url(#van-empty-5)"
width="64"
height="66"
rx="2"
>
</rect>
<rect fill="#FFF"
x="6"
y="6"
width="52"
height="55"
rx="1"
>
</rect>
<g transform="translate(15 17)"
fill="url(#van-empty-6)"
>
<rect width="34"
height="6"
rx="1"
>
</rect>
<path d="M0 14h34v6H0z">
</path>
<rect y="28"
width="34"
height="6"
rx="1"
>
</rect>
</g>
</g>
<rect fill="url(#van-empty-7)"
y="61"
width="88"
height="28"
rx="1"
>
</rect>
<rect fill="#F7F8FA"
x="29"
y="72"
width="30"
height="6"
rx="1"
>
</rect>
</g>
</svg>
</div>
<div class="van-empty__bottom">
<p class="van-coupon-list__empty-tip">
@ -507,7 +993,169 @@ exports[`should render list-footer slot correctly 1`] = `
>
<div class="van-empty">
<div class="van-empty__image">
<img src="https://img.yzcdn.cn/vant/empty-image-default.png">
<svg viewbox="0 0 160 160">
<defs>
<linearGradient x1="50%"
x2="50%"
y2="100%"
id="van-empty-5"
>
<stop stop-color="#F2F3F5"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient x1="95%"
y1="48%"
x2="5.5%"
y2="51%"
id="van-empty-6"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient y1="45%"
x2="100%"
y2="54%"
id="van-empty-7"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<defs>
<linearGradient id="van-empty-a"
x1="64%"
y1="100%"
x2="64%"
>
<stop stop-color="#FFF"
offset="0%"
stop-opacity="0.5"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M36 131V53H16v20H2v58h34z"
fill="url(#van-empty-a)"
>
</path>
<path d="M123 15h22v14h9v77h-31V15z"
fill="url(#van-empty-a)"
>
</path>
</g>
<defs>
<linearGradient id="van-empty-b"
x1="64%"
y1="97%"
x2="64%"
y2="0%"
>
<stop stop-color="#F2F3F5"
offset="0%"
stop-opacity="0.3"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M87 6c3 0 7 3 8 6a8 8 0 1 1-1 16H80a7 7 0 0 1-8-6c0-4 3-7 6-7 0-5 4-9 9-9Z"
fill="url(#van-empty-b)"
>
</path>
<path d="M19 23c2 0 3 1 4 3 2 0 4 2 4 4a4 4 0 0 1-4 3v1h-7v-1l-1 1c-2 0-3-2-3-4 0-1 1-3 3-3 0-2 2-4 4-4Z"
fill="url(#van-empty-b)"
>
</path>
</g>
<g transform="translate(36 50)"
fill="none"
>
<g transform="translate(8)">
<rect fill="#EBEDF0"
opacity=".6"
x="38"
y="13"
width="36"
height="53"
rx="2"
>
</rect>
<rect fill="url(#van-empty-5)"
width="64"
height="66"
rx="2"
>
</rect>
<rect fill="#FFF"
x="6"
y="6"
width="52"
height="55"
rx="1"
>
</rect>
<g transform="translate(15 17)"
fill="url(#van-empty-6)"
>
<rect width="34"
height="6"
rx="1"
>
</rect>
<path d="M0 14h34v6H0z">
</path>
<rect y="28"
width="34"
height="6"
rx="1"
>
</rect>
</g>
</g>
<rect fill="url(#van-empty-7)"
y="61"
width="88"
height="28"
rx="1"
>
</rect>
<rect fill="#F7F8FA"
x="29"
y="72"
width="30"
height="6"
rx="1"
>
</rect>
</g>
</svg>
</div>
<div class="van-empty__bottom">
<p class="van-coupon-list__empty-tip">

View File

@ -5,11 +5,21 @@ import {
makeStringProp,
createNamespace,
} from '../utils';
import { Network } from './Network';
import {
renderError,
renderSearch,
renderNetwork,
renderMaterial,
} from './Images';
const [name, bem] = createNamespace('empty');
const PRESET_IMAGES = ['error', 'search', 'default'];
const PRESET_IMAGES: Record<string, () => JSX.Element> = {
error: renderError,
search: renderSearch,
network: renderNetwork,
default: renderMaterial,
};
const emptyProps = {
image: makeStringProp('default'),
@ -29,18 +39,7 @@ export default defineComponent({
if (slots.image) {
return slots.image();
}
let { image } = props;
if (image === 'network') {
return Network;
}
if (PRESET_IMAGES.includes(image)) {
image = `https://img.yzcdn.cn/vant/empty-image-${image}.png`;
}
return <img src={image} />;
return PRESET_IMAGES[props.image]?.() || <img src={props.image} />;
};
const renderDescription = () => {

View File

@ -0,0 +1,203 @@
const getId = (num: number | string) => `van-empty-${num}`;
const useId = (num: number | string) => `url(#${getId(num)})`;
const renderStop = (color: string, offset: number, opacity?: number) => (
<stop stop-color={color} offset={`${offset}%`} stop-opacity={opacity} />
);
const renderStops = (fromColor: string, toColor: string) => [
renderStop(fromColor, 0),
renderStop(toColor, 100),
];
const renderShadow = (id: string) => [
<defs>
<radialGradient
id={getId(id)}
cx="50%"
cy="54%"
fx="50%"
fy="54%"
r="297%"
gradientTransform="matrix(-.16 0 0 -.33 .58 .72)"
>
{renderStop('#EBEDF0', 0)}
{renderStop('#F2F3F5', 100, 0.3)}
</radialGradient>
</defs>,
<ellipse fill={useId(id)} opacity=".8" cx="80" cy="140" rx="46" ry="8" />,
];
const renderBuilding = () => [
<defs>
<linearGradient id={getId('a')} x1="64%" y1="100%" x2="64%">
{renderStop('#FFF', 0, 0.5)}
{renderStop('#F2F3F5', 100)}
</linearGradient>
</defs>,
<g opacity=".8">
<path d="M36 131V53H16v20H2v58h34z" fill={useId('a')} />
<path d="M123 15h22v14h9v77h-31V15z" fill={useId('a')} />
</g>,
];
const renderCloud = () => [
<defs>
<linearGradient id={getId('b')} x1="64%" y1="97%" x2="64%" y2="0%">
{renderStop('#F2F3F5', 0, 0.3)}
{renderStop('#F2F3F5', 100)}
</linearGradient>
</defs>,
<g opacity=".8">
<path
d="M87 6c3 0 7 3 8 6a8 8 0 1 1-1 16H80a7 7 0 0 1-8-6c0-4 3-7 6-7 0-5 4-9 9-9Z"
fill={useId('b')}
/>
<path
d="M19 23c2 0 3 1 4 3 2 0 4 2 4 4a4 4 0 0 1-4 3v1h-7v-1l-1 1c-2 0-3-2-3-4 0-1 1-3 3-3 0-2 2-4 4-4Z"
fill={useId('b')}
/>
</g>,
];
export const renderNetwork = () => (
<svg viewBox="0 0 160 160">
<defs>
<linearGradient id={getId(1)} x1="64%" y1="100%" x2="64%">
{renderStop('#FFF', 0, 0.5)}
{renderStop('#F2F3F5', 100)}
</linearGradient>
<linearGradient id={getId(2)} x1="50%" x2="50%" y2="84%">
{renderStop('#EBEDF0', 0)}
{renderStop('#DCDEE0', 100, 0)}
</linearGradient>
<linearGradient id={getId(3)} x1="100%" x2="100%" y2="100%">
{renderStops('#EAEDF0', '#DCDEE0')}
</linearGradient>
<radialGradient
id={getId(4)}
cx="50%"
cy="0%"
fx="50%"
fy="0%"
r="100%"
gradientTransform="matrix(0 1 -.54 0 .5 -.5)"
>
{renderStop('#EBEDF0', 0)}
{renderStop('#FFF', 100, 0)}
</radialGradient>
</defs>
<g fill="none">
{renderBuilding()}
<path fill={useId(4)} d="M0 139h160v21H0z" />
<path
d="M80 54a7 7 0 0 1 3 13v27l-2 2h-2a2 2 0 0 1-2-2V67a7 7 0 0 1 3-13z"
fill={useId(2)}
/>
<g opacity=".6" stroke-linecap="round" stroke-width="7">
<path d="M64 47a19 19 0 0 0-5 13c0 5 2 10 5 13" stroke={useId(3)} />
<path d="M53 36a34 34 0 0 0 0 48" stroke={useId(3)} />
<path d="M95 73a19 19 0 0 0 6-13c0-5-2-9-6-13" stroke={useId(3)} />
<path d="M106 84a34 34 0 0 0 0-48" stroke={useId(3)} />
</g>
<g transform="translate(31 105)">
<rect fill="#EBEDF0" width="98" height="34" rx="2" />
<rect fill="#FFF" x="9" y="8" width="80" height="18" rx="1.1" />
<rect fill="#EBEDF0" x="15" y="12" width="18" height="6" rx="1.1" />
</g>
</g>
</svg>
);
export const renderMaterial = () => (
<svg viewBox="0 0 160 160">
<defs>
<linearGradient x1="50%" x2="50%" y2="100%" id={getId(5)}>
{renderStops('#F2F3F5', '#DCDEE0')}
</linearGradient>
<linearGradient x1="95%" y1="48%" x2="5.5%" y2="51%" id={getId(6)}>
{renderStops('#EAEDF1', '#DCDEE0')}
</linearGradient>
<linearGradient y1="45%" x2="100%" y2="54%" id={getId(7)}>
{renderStops('#EAEDF1', '#DCDEE0')}
</linearGradient>
</defs>
{renderBuilding()}
{renderCloud()}
<g transform="translate(36 50)" fill="none">
<g transform="translate(8)">
<rect
fill="#EBEDF0"
opacity=".6"
x="38"
y="13"
width="36"
height="53"
rx="2"
/>
<rect fill={useId(5)} width="64" height="66" rx="2" />
<rect fill="#FFF" x="6" y="6" width="52" height="55" rx="1" />
<g transform="translate(15 17)" fill={useId(6)}>
<rect width="34" height="6" rx="1" />
<path d="M0 14h34v6H0z" />
<rect y="28" width="34" height="6" rx="1" />
</g>
</g>
<rect fill={useId(7)} y="61" width="88" height="28" rx="1" />
<rect fill="#F7F8FA" x="29" y="72" width="30" height="6" rx="1" />
</g>
</svg>
);
export const renderError = () => (
<svg viewBox="0 0 160 160">
<defs>
<linearGradient x1="50%" x2="50%" y2="100%" id={getId(8)}>
{renderStops('#EAEDF1', '#DCDEE0')}
</linearGradient>
</defs>
{renderBuilding()}
{renderCloud()}
{renderShadow('c')}
<path
d="m59 60 21 21 21-21h3l9 9v3L92 93l21 21v3l-9 9h-3l-21-21-21 21h-3l-9-9v-3l21-21-21-21v-3l9-9h3Z"
fill={useId(8)}
/>
</svg>
);
export const renderSearch = () => (
<svg viewBox="0 0 160 160">
<defs>
<linearGradient x1="50%" y1="100%" x2="50%" id={getId(9)}>
{renderStops('#EEE', '#D8D8D8')}
</linearGradient>
<linearGradient x1="100%" y1="50%" y2="50%" id={getId(10)}>
{renderStops('#F2F3F5', '#DCDEE0')}
</linearGradient>
<linearGradient x1="50%" x2="50%" y2="100%" id={getId(11)}>
{renderStops('#F2F3F5', '#DCDEE0')}
</linearGradient>
<linearGradient x1="50%" x2="50%" y2="100%" id={getId(12)}>
{renderStops('#FFF', '#F7F8FA')}
</linearGradient>
</defs>
{renderBuilding()}
{renderCloud()}
{renderShadow('d')}
<g transform="rotate(-45 113 -4)" fill="none">
<rect fill={useId(9)} x="24" y="52.8" width="5.8" height="19" rx="1" />
<rect fill={useId(10)} x="22.1" y="67.3" width="9.9" height="28" rx="1" />
<circle stroke={useId(11)} stroke-width="8" cx="27" cy="27" r="27" />
<circle fill={useId(12)} cx="27" cy="27" r="16" />
<path
d="M37 7c-8 0-15 5-16 12"
stroke={useId(11)}
stroke-width="3"
opacity=".5"
stroke-linecap="round"
transform="rotate(45 29 13)"
/>
</g>
</svg>
);

View File

@ -1,63 +0,0 @@
const prefix = 'van-empty-network-';
const renderStop = (color: string, offset: number, opacity?: number) => (
<stop stop-color={color} offset={`${offset}%`} stop-opacity={opacity} />
);
export const Network = (
<svg viewBox="0 0 160 160">
<defs>
<linearGradient id={`${prefix}1`} x1="64%" y1="100%" x2="64%">
{renderStop('#FFF', 0, 0.5)}
{renderStop('#F2F3F5', 100)}
</linearGradient>
<linearGradient id={`${prefix}2`} x1="50%" x2="50%" y2="84%">
{renderStop('#EBEDF0', 0)}
{renderStop('#DCDEE0', 100, 0)}
</linearGradient>
<linearGradient id={`${prefix}3`} x1="100%" x2="100%" y2="100%">
{renderStop('#EAEDF0', 0)}
{renderStop('#DCDEE0', 100)}
</linearGradient>
<radialGradient
id={`${prefix}4`}
cx="50%"
cy="0%"
fx="50%"
fy="0%"
r="100%"
gradientTransform="matrix(0 1 -.54 0 .5 -.5)"
>
{renderStop('#EBEDF0', 0)}
{renderStop('#FFF', 100, 0)}
</radialGradient>
</defs>
<g fill="none">
<g opacity=".8">
<path d="M36 131V53H16v20H2v58h34z" fill={`url(#${prefix}1)`} />
<path d="M123 15h22v14h9v77h-31V15z" fill={`url(#${prefix}1)`} />
</g>
<path fill={`url(#${prefix}4)`} d="M0 139h160v21H0z" />
<path
d="M80 54a7 7 0 0 1 3 13v27l-2 2h-2a2 2 0 0 1-2-2V67a7 7 0 0 1 3-13z"
fill={`url(#${prefix}2)`}
/>
<g opacity=".6" stroke-linecap="round" stroke-width="7">
<path
d="M64 47a19 19 0 0 0-5 13c0 5 2 10 5 13"
stroke={`url(#${prefix}3)`}
/>
<path d="M53 36a34 34 0 0 0 0 48" stroke={`url(#${prefix}3)`} />
<path
d="M95 73a19 19 0 0 0 6-13c0-5-2-9-6-13"
stroke={`url(#${prefix}3)`}
/>
<path d="M106 84a34 34 0 0 0 0-48" stroke={`url(#${prefix}3)`} />
</g>
<g transform="translate(31 105)">
<rect fill="#EBEDF0" width="98" height="34" rx="2" />
<rect fill="#FFF" x="9" y="8" width="80" height="18" rx="1.1" />
<rect fill="#EBEDF0" x="15" y="12" width="18" height="6" rx="1.1" />
</g>
</g>
</svg>
);

View File

@ -4,7 +4,169 @@ exports[`should render demo and match snapshot 1`] = `
<div>
<div class="van-empty">
<div class="van-empty__image">
<img src="https://img.yzcdn.cn/vant/empty-image-default.png">
<svg viewbox="0 0 160 160">
<defs>
<linearGradient x1="50%"
x2="50%"
y2="100%"
id="van-empty-5"
>
<stop stop-color="#F2F3F5"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient x1="95%"
y1="48%"
x2="5.5%"
y2="51%"
id="van-empty-6"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient y1="45%"
x2="100%"
y2="54%"
id="van-empty-7"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<defs>
<linearGradient id="van-empty-a"
x1="64%"
y1="100%"
x2="64%"
>
<stop stop-color="#FFF"
offset="0%"
stop-opacity="0.5"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M36 131V53H16v20H2v58h34z"
fill="url(#van-empty-a)"
>
</path>
<path d="M123 15h22v14h9v77h-31V15z"
fill="url(#van-empty-a)"
>
</path>
</g>
<defs>
<linearGradient id="van-empty-b"
x1="64%"
y1="97%"
x2="64%"
y2="0%"
>
<stop stop-color="#F2F3F5"
offset="0%"
stop-opacity="0.3"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M87 6c3 0 7 3 8 6a8 8 0 1 1-1 16H80a7 7 0 0 1-8-6c0-4 3-7 6-7 0-5 4-9 9-9Z"
fill="url(#van-empty-b)"
>
</path>
<path d="M19 23c2 0 3 1 4 3 2 0 4 2 4 4a4 4 0 0 1-4 3v1h-7v-1l-1 1c-2 0-3-2-3-4 0-1 1-3 3-3 0-2 2-4 4-4Z"
fill="url(#van-empty-b)"
>
</path>
</g>
<g transform="translate(36 50)"
fill="none"
>
<g transform="translate(8)">
<rect fill="#EBEDF0"
opacity=".6"
x="38"
y="13"
width="36"
height="53"
rx="2"
>
</rect>
<rect fill="url(#van-empty-5)"
width="64"
height="66"
rx="2"
>
</rect>
<rect fill="#FFF"
x="6"
y="6"
width="52"
height="55"
rx="1"
>
</rect>
<g transform="translate(15 17)"
fill="url(#van-empty-6)"
>
<rect width="34"
height="6"
rx="1"
>
</rect>
<path d="M0 14h34v6H0z">
</path>
<rect y="28"
width="34"
height="6"
rx="1"
>
</rect>
</g>
</g>
<rect fill="url(#van-empty-7)"
y="61"
width="88"
height="28"
rx="1"
>
</rect>
<rect fill="#F7F8FA"
x="29"
y="72"
width="30"
height="6"
rx="1"
>
</rect>
</g>
</svg>
</div>
<p class="van-empty__description">
Description
@ -67,7 +229,111 @@ exports[`should render demo and match snapshot 1`] = `
>
<div class="van-empty">
<div class="van-empty__image">
<img src="https://img.yzcdn.cn/vant/empty-image-error.png">
<svg viewbox="0 0 160 160">
<defs>
<linearGradient x1="50%"
x2="50%"
y2="100%"
id="van-empty-8"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<defs>
<linearGradient id="van-empty-a"
x1="64%"
y1="100%"
x2="64%"
>
<stop stop-color="#FFF"
offset="0%"
stop-opacity="0.5"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M36 131V53H16v20H2v58h34z"
fill="url(#van-empty-a)"
>
</path>
<path d="M123 15h22v14h9v77h-31V15z"
fill="url(#van-empty-a)"
>
</path>
</g>
<defs>
<linearGradient id="van-empty-b"
x1="64%"
y1="97%"
x2="64%"
y2="0%"
>
<stop stop-color="#F2F3F5"
offset="0%"
stop-opacity="0.3"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M87 6c3 0 7 3 8 6a8 8 0 1 1-1 16H80a7 7 0 0 1-8-6c0-4 3-7 6-7 0-5 4-9 9-9Z"
fill="url(#van-empty-b)"
>
</path>
<path d="M19 23c2 0 3 1 4 3 2 0 4 2 4 4a4 4 0 0 1-4 3v1h-7v-1l-1 1c-2 0-3-2-3-4 0-1 1-3 3-3 0-2 2-4 4-4Z"
fill="url(#van-empty-b)"
>
</path>
</g>
<defs>
<radialGradient id="van-empty-c"
cx="50%"
cy="54%"
fx="50%"
fy="54%"
r="297%"
gradienttransform="matrix(-.16 0 0 -.33 .58 .72)"
>
<stop stop-color="#EBEDF0"
offset="0%"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
stop-opacity="0.3"
>
</stop>
</radialGradient>
</defs>
<ellipse fill="url(#van-empty-c)"
opacity=".8"
cx="80"
cy="140"
rx="46"
ry="8"
>
</ellipse>
<path d="m59 60 21 21 21-21h3l9 9v3L92 93l21 21v3l-9 9h-3l-21-21-21 21h-3l-9-9v-3l21-21-21-21v-3l9-9h3Z"
fill="url(#van-empty-8)"
>
</path>
</svg>
</div>
<p class="van-empty__description">
Description
@ -98,7 +364,169 @@ exports[`should render demo and match snapshot 1`] = `
<div class="van-empty__image"
style="width: 100px; height: 100px;"
>
<img src="https://img.yzcdn.cn/vant/empty-image-default.png">
<svg viewbox="0 0 160 160">
<defs>
<linearGradient x1="50%"
x2="50%"
y2="100%"
id="van-empty-5"
>
<stop stop-color="#F2F3F5"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient x1="95%"
y1="48%"
x2="5.5%"
y2="51%"
id="van-empty-6"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient y1="45%"
x2="100%"
y2="54%"
id="van-empty-7"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<defs>
<linearGradient id="van-empty-a"
x1="64%"
y1="100%"
x2="64%"
>
<stop stop-color="#FFF"
offset="0%"
stop-opacity="0.5"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M36 131V53H16v20H2v58h34z"
fill="url(#van-empty-a)"
>
</path>
<path d="M123 15h22v14h9v77h-31V15z"
fill="url(#van-empty-a)"
>
</path>
</g>
<defs>
<linearGradient id="van-empty-b"
x1="64%"
y1="97%"
x2="64%"
y2="0%"
>
<stop stop-color="#F2F3F5"
offset="0%"
stop-opacity="0.3"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M87 6c3 0 7 3 8 6a8 8 0 1 1-1 16H80a7 7 0 0 1-8-6c0-4 3-7 6-7 0-5 4-9 9-9Z"
fill="url(#van-empty-b)"
>
</path>
<path d="M19 23c2 0 3 1 4 3 2 0 4 2 4 4a4 4 0 0 1-4 3v1h-7v-1l-1 1c-2 0-3-2-3-4 0-1 1-3 3-3 0-2 2-4 4-4Z"
fill="url(#van-empty-b)"
>
</path>
</g>
<g transform="translate(36 50)"
fill="none"
>
<g transform="translate(8)">
<rect fill="#EBEDF0"
opacity=".6"
x="38"
y="13"
width="36"
height="53"
rx="2"
>
</rect>
<rect fill="url(#van-empty-5)"
width="64"
height="66"
rx="2"
>
</rect>
<rect fill="#FFF"
x="6"
y="6"
width="52"
height="55"
rx="1"
>
</rect>
<g transform="translate(15 17)"
fill="url(#van-empty-6)"
>
<rect width="34"
height="6"
rx="1"
>
</rect>
<path d="M0 14h34v6H0z">
</path>
<rect y="28"
width="34"
height="6"
rx="1"
>
</rect>
</g>
</g>
<rect fill="url(#van-empty-7)"
y="61"
width="88"
height="28"
rx="1"
>
</rect>
<rect fill="#F7F8FA"
x="29"
y="72"
width="30"
height="6"
rx="1"
>
</rect>
</g>
</svg>
</div>
<p class="van-empty__description">
Description
@ -120,7 +548,169 @@ exports[`should render demo and match snapshot 1`] = `
<div>
<div class="van-empty">
<div class="van-empty__image">
<img src="https://img.yzcdn.cn/vant/empty-image-default.png">
<svg viewbox="0 0 160 160">
<defs>
<linearGradient x1="50%"
x2="50%"
y2="100%"
id="van-empty-5"
>
<stop stop-color="#F2F3F5"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient x1="95%"
y1="48%"
x2="5.5%"
y2="51%"
id="van-empty-6"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient y1="45%"
x2="100%"
y2="54%"
id="van-empty-7"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<defs>
<linearGradient id="van-empty-a"
x1="64%"
y1="100%"
x2="64%"
>
<stop stop-color="#FFF"
offset="0%"
stop-opacity="0.5"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M36 131V53H16v20H2v58h34z"
fill="url(#van-empty-a)"
>
</path>
<path d="M123 15h22v14h9v77h-31V15z"
fill="url(#van-empty-a)"
>
</path>
</g>
<defs>
<linearGradient id="van-empty-b"
x1="64%"
y1="97%"
x2="64%"
y2="0%"
>
<stop stop-color="#F2F3F5"
offset="0%"
stop-opacity="0.3"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M87 6c3 0 7 3 8 6a8 8 0 1 1-1 16H80a7 7 0 0 1-8-6c0-4 3-7 6-7 0-5 4-9 9-9Z"
fill="url(#van-empty-b)"
>
</path>
<path d="M19 23c2 0 3 1 4 3 2 0 4 2 4 4a4 4 0 0 1-4 3v1h-7v-1l-1 1c-2 0-3-2-3-4 0-1 1-3 3-3 0-2 2-4 4-4Z"
fill="url(#van-empty-b)"
>
</path>
</g>
<g transform="translate(36 50)"
fill="none"
>
<g transform="translate(8)">
<rect fill="#EBEDF0"
opacity=".6"
x="38"
y="13"
width="36"
height="53"
rx="2"
>
</rect>
<rect fill="url(#van-empty-5)"
width="64"
height="66"
rx="2"
>
</rect>
<rect fill="#FFF"
x="6"
y="6"
width="52"
height="55"
rx="1"
>
</rect>
<g transform="translate(15 17)"
fill="url(#van-empty-6)"
>
<rect width="34"
height="6"
rx="1"
>
</rect>
<path d="M0 14h34v6H0z">
</path>
<rect y="28"
width="34"
height="6"
rx="1"
>
</rect>
</g>
</g>
<rect fill="url(#van-empty-7)"
y="61"
width="88"
height="28"
rx="1"
>
</rect>
<rect fill="#F7F8FA"
x="29"
y="72"
width="30"
height="6"
rx="1"
>
</rect>
</g>
</svg>
</div>
<p class="van-empty__description">
Description

View File

@ -3,7 +3,169 @@
exports[`should render bottom slot correctly 1`] = `
<div class="van-empty">
<div class="van-empty__image">
<img src="https://img.yzcdn.cn/vant/empty-image-default.png">
<svg viewbox="0 0 160 160">
<defs>
<linearGradient x1="50%"
x2="50%"
y2="100%"
id="van-empty-5"
>
<stop stop-color="#F2F3F5"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient x1="95%"
y1="48%"
x2="5.5%"
y2="51%"
id="van-empty-6"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient y1="45%"
x2="100%"
y2="54%"
id="van-empty-7"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<defs>
<linearGradient id="van-empty-a"
x1="64%"
y1="100%"
x2="64%"
>
<stop stop-color="#FFF"
offset="0%"
stop-opacity="0.5"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M36 131V53H16v20H2v58h34z"
fill="url(#van-empty-a)"
>
</path>
<path d="M123 15h22v14h9v77h-31V15z"
fill="url(#van-empty-a)"
>
</path>
</g>
<defs>
<linearGradient id="van-empty-b"
x1="64%"
y1="97%"
x2="64%"
y2="0%"
>
<stop stop-color="#F2F3F5"
offset="0%"
stop-opacity="0.3"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M87 6c3 0 7 3 8 6a8 8 0 1 1-1 16H80a7 7 0 0 1-8-6c0-4 3-7 6-7 0-5 4-9 9-9Z"
fill="url(#van-empty-b)"
>
</path>
<path d="M19 23c2 0 3 1 4 3 2 0 4 2 4 4a4 4 0 0 1-4 3v1h-7v-1l-1 1c-2 0-3-2-3-4 0-1 1-3 3-3 0-2 2-4 4-4Z"
fill="url(#van-empty-b)"
>
</path>
</g>
<g transform="translate(36 50)"
fill="none"
>
<g transform="translate(8)">
<rect fill="#EBEDF0"
opacity=".6"
x="38"
y="13"
width="36"
height="53"
rx="2"
>
</rect>
<rect fill="url(#van-empty-5)"
width="64"
height="66"
rx="2"
>
</rect>
<rect fill="#FFF"
x="6"
y="6"
width="52"
height="55"
rx="1"
>
</rect>
<g transform="translate(15 17)"
fill="url(#van-empty-6)"
>
<rect width="34"
height="6"
rx="1"
>
</rect>
<path d="M0 14h34v6H0z">
</path>
<rect y="28"
width="34"
height="6"
rx="1"
>
</rect>
</g>
</g>
<rect fill="url(#van-empty-7)"
y="61"
width="88"
height="28"
rx="1"
>
</rect>
<rect fill="#F7F8FA"
x="29"
y="72"
width="30"
height="6"
rx="1"
>
</rect>
</g>
</svg>
</div>
<div class="van-empty__bottom">
Custom bottom
@ -14,7 +176,169 @@ exports[`should render bottom slot correctly 1`] = `
exports[`should render description slot correctly 1`] = `
<div class="van-empty">
<div class="van-empty__image">
<img src="https://img.yzcdn.cn/vant/empty-image-default.png">
<svg viewbox="0 0 160 160">
<defs>
<linearGradient x1="50%"
x2="50%"
y2="100%"
id="van-empty-5"
>
<stop stop-color="#F2F3F5"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient x1="95%"
y1="48%"
x2="5.5%"
y2="51%"
id="van-empty-6"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
<linearGradient y1="45%"
x2="100%"
y2="54%"
id="van-empty-7"
>
<stop stop-color="#EAEDF1"
offset="0%"
>
</stop>
<stop stop-color="#DCDEE0"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<defs>
<linearGradient id="van-empty-a"
x1="64%"
y1="100%"
x2="64%"
>
<stop stop-color="#FFF"
offset="0%"
stop-opacity="0.5"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M36 131V53H16v20H2v58h34z"
fill="url(#van-empty-a)"
>
</path>
<path d="M123 15h22v14h9v77h-31V15z"
fill="url(#van-empty-a)"
>
</path>
</g>
<defs>
<linearGradient id="van-empty-b"
x1="64%"
y1="97%"
x2="64%"
y2="0%"
>
<stop stop-color="#F2F3F5"
offset="0%"
stop-opacity="0.3"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M87 6c3 0 7 3 8 6a8 8 0 1 1-1 16H80a7 7 0 0 1-8-6c0-4 3-7 6-7 0-5 4-9 9-9Z"
fill="url(#van-empty-b)"
>
</path>
<path d="M19 23c2 0 3 1 4 3 2 0 4 2 4 4a4 4 0 0 1-4 3v1h-7v-1l-1 1c-2 0-3-2-3-4 0-1 1-3 3-3 0-2 2-4 4-4Z"
fill="url(#van-empty-b)"
>
</path>
</g>
<g transform="translate(36 50)"
fill="none"
>
<g transform="translate(8)">
<rect fill="#EBEDF0"
opacity=".6"
x="38"
y="13"
width="36"
height="53"
rx="2"
>
</rect>
<rect fill="url(#van-empty-5)"
width="64"
height="66"
rx="2"
>
</rect>
<rect fill="#FFF"
x="6"
y="6"
width="52"
height="55"
rx="1"
>
</rect>
<g transform="translate(15 17)"
fill="url(#van-empty-6)"
>
<rect width="34"
height="6"
rx="1"
>
</rect>
<path d="M0 14h34v6H0z">
</path>
<rect y="28"
width="34"
height="6"
rx="1"
>
</rect>
</g>
</g>
<rect fill="url(#van-empty-7)"
y="61"
width="88"
height="28"
rx="1"
>
</rect>
<rect fill="#F7F8FA"
x="29"
y="72"
width="30"
height="6"
rx="1"
>
</rect>
</g>
</svg>
</div>
<p class="van-empty__description">
Custom description
@ -35,7 +359,7 @@ exports[`should render svg when image is network 1`] = `
<div class="van-empty__image">
<svg viewbox="0 0 160 160">
<defs>
<linearGradient id="van-empty-network-1"
<linearGradient id="van-empty-1"
x1="64%"
y1="100%"
x2="64%"
@ -50,7 +374,7 @@ exports[`should render svg when image is network 1`] = `
>
</stop>
</linearGradient>
<linearGradient id="van-empty-network-2"
<linearGradient id="van-empty-2"
x1="50%"
x2="50%"
y2="84%"
@ -65,7 +389,7 @@ exports[`should render svg when image is network 1`] = `
>
</stop>
</linearGradient>
<linearGradient id="van-empty-network-3"
<linearGradient id="van-empty-3"
x1="100%"
x2="100%"
y2="100%"
@ -79,7 +403,7 @@ exports[`should render svg when image is network 1`] = `
>
</stop>
</linearGradient>
<radialGradient id="van-empty-network-4"
<radialGradient id="van-empty-4"
cx="50%"
cy="0%"
fx="50%"
@ -99,22 +423,39 @@ exports[`should render svg when image is network 1`] = `
</radialGradient>
</defs>
<g fill="none">
<defs>
<linearGradient id="van-empty-a"
x1="64%"
y1="100%"
x2="64%"
>
<stop stop-color="#FFF"
offset="0%"
stop-opacity="0.5"
>
</stop>
<stop stop-color="#F2F3F5"
offset="100%"
>
</stop>
</linearGradient>
</defs>
<g opacity=".8">
<path d="M36 131V53H16v20H2v58h34z"
fill="url(#van-empty-network-1)"
fill="url(#van-empty-a)"
>
</path>
<path d="M123 15h22v14h9v77h-31V15z"
fill="url(#van-empty-network-1)"
fill="url(#van-empty-a)"
>
</path>
</g>
<path fill="url(#van-empty-network-4)"
<path fill="url(#van-empty-4)"
d="M0 139h160v21H0z"
>
</path>
<path d="M80 54a7 7 0 0 1 3 13v27l-2 2h-2a2 2 0 0 1-2-2V67a7 7 0 0 1 3-13z"
fill="url(#van-empty-network-2)"
fill="url(#van-empty-2)"
>
</path>
<g opacity=".6"
@ -122,19 +463,19 @@ exports[`should render svg when image is network 1`] = `
stroke-width="7"
>
<path d="M64 47a19 19 0 0 0-5 13c0 5 2 10 5 13"
stroke="url(#van-empty-network-3)"
stroke="url(#van-empty-3)"
>
</path>
<path d="M53 36a34 34 0 0 0 0 48"
stroke="url(#van-empty-network-3)"
stroke="url(#van-empty-3)"
>
</path>
<path d="M95 73a19 19 0 0 0 6-13c0-5-2-9-6-13"
stroke="url(#van-empty-network-3)"
stroke="url(#van-empty-3)"
>
</path>
<path d="M106 84a34 34 0 0 0 0-48"
stroke="url(#van-empty-network-3)"
stroke="url(#van-empty-3)"
>
</path>
</g>

View File

@ -16,6 +16,7 @@ import {
isDef,
extend,
addUnit,
toArray,
FORM_KEY,
numericProp,
unknownProp,
@ -239,12 +240,12 @@ export default defineComponent({
const validateWithTrigger = (trigger: FieldValidateTrigger) => {
if (form && props.rules) {
const defaultTrigger = form.props.validateTrigger === trigger;
const { validateTrigger } = form.props;
const defaultTrigger = toArray(validateTrigger).includes(trigger);
const rules = props.rules.filter((rule) => {
if (rule.trigger) {
return rule.trigger === trigger;
return toArray(rule.trigger).includes(trigger);
}
return defaultTrigger;
});

View File

@ -59,7 +59,7 @@ export type FiledRuleFormatter = (value: any, rule: FieldRule) => string;
export type FieldRule = {
pattern?: RegExp;
trigger?: FieldValidateTrigger;
trigger?: FieldValidateTrigger | FieldValidateTrigger[];
message?: FieldRuleMessage;
required?: boolean;
validator?: FieldRuleValidator;

View File

@ -6,7 +6,6 @@ import {
truthProp,
numericProp,
preventDefault,
makeStringProp,
createNamespace,
} from '../utils';
@ -35,9 +34,14 @@ const formProps = {
scrollToError: Boolean,
validateFirst: Boolean,
submitOnEnter: truthProp,
validateTrigger: makeStringProp<FieldValidateTrigger>('onBlur'),
showErrorMessage: truthProp,
errorMessageAlign: String as PropType<FieldTextAlign>,
validateTrigger: {
type: [String, Array] as PropType<
FieldValidateTrigger | FieldValidateTrigger[]
>,
default: 'onBlur',
},
};
export type FormProps = ExtractPropTypes<typeof formProps>;

View File

@ -115,7 +115,7 @@ export default {
setup() {
const value1 = ref('');
const value2 = ref('');
const value3 = ref('');
const value3 = ref('abc');
const value4 = ref('');
const pattern = /\d{6}/;
@ -129,7 +129,7 @@ export default {
setTimeout(() => {
Toast.clear();
resolve(/\d{6}/.test(val));
resolve(val === '1234');
}, 1000);
});
@ -495,7 +495,7 @@ export default {
| label-align | Field label align, can be set to `center` `right` | _string_ | `left` |
| input-align | Field input align, can be set to `center` `right` | _string_ | `left` |
| error-message-align | Error message align, can be set to `center` `right` | _string_ | `left` |
| validate-trigger | When to validate the form, can be set to `onChange``onSubmit` | _string_ | `onBlur` |
| validate-trigger | When to validate the form, can be set to `onChange``onSubmit`, supports using array to set multiple values | _string \| string[]_ | `onBlur` |
| colon | Whether to display colon after label | _boolean_ | `false` |
| disabled | Whether to disable form | _boolean_ | `false` |
| readonly | Whether to be readonly | _boolean_ | `false` |

View File

@ -123,7 +123,7 @@ export default {
setup() {
const value1 = ref('');
const value2 = ref('');
const value3 = ref('');
const value3 = ref('abc');
const value4 = ref('');
const pattern = /\d{6}/;
@ -140,7 +140,7 @@ export default {
setTimeout(() => {
Toast.clear();
resolve(/\d{6}/.test(val));
resolve(val === '1234');
}, 1000);
});
@ -527,7 +527,7 @@ export default {
| label-align | 表单项 label 对齐方式,可选值为 `center` `right` | _string_ | `left` |
| input-align | 输入框对齐方式,可选值为 `center` `right` | _string_ | `left` |
| error-message-align | 错误提示文案对齐方式,可选值为 `center` `right` | _string_ | `left` |
| validate-trigger | 表单校验触发时机,可选值为 `onChange``onSubmit`详见下表 | _string_ | `onBlur` |
| validate-trigger | 表单校验触发时机,可选值为 `onChange``onSubmit`支持通过数组同时设置多个值,具体用法见下方表格 | _string \| string[]_ | `onBlur` |
| colon | 是否在 label 后面添加冒号 | _boolean_ | `false` |
| disabled | 是否禁用表单中的所有输入框 | _boolean_ | `false` |
| readonly | 是否将表单中的所有输入框设置为只读状态 | _boolean_ | `false` |

View File

@ -293,6 +293,43 @@ test('should trigger validate after inputting when validate-trigger prop is onCh
expect(wrapper.find('.van-field__error-message').exists).toBeTruthy();
});
test('should trigger validate correctly when validate-trigger prop is array', async () => {
const wrapper = mount({
data() {
return {
...getSimpleRules(),
value: '',
};
},
render() {
return (
<Form ref="form" validateTrigger={['onBlur', 'onChange']}>
<Field
v-model={this.value}
name="A"
rules={this.rulesA}
modelValue=""
/>
</Form>
);
},
});
const input = wrapper.find('input');
await input.trigger('input');
expect(wrapper.find('.van-field__error-message').exists()).toBeFalsy();
await input.trigger('blur');
expect(wrapper.find('.van-field__error-message').exists()).toBeTruthy();
await wrapper.setData({ value: '1' });
expect(wrapper.find('.van-field__error-message').exists()).toBeFalsy();
await wrapper.setData({ value: '' });
expect(wrapper.find('.van-field__error-message').exists).toBeTruthy();
});
test('should allow to custom trigger in rules', async () => {
const rulesA = [
{

View File

@ -84,7 +84,10 @@ exports[`zoom in and drag image to move 1`] = `
style="object-fit: contain;"
>
<div class="van-image__loading">
<div class="van-loading van-loading--spinner">
<div class="van-loading van-loading--spinner"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--spinner">
<i class="van-loading__line van-loading__line--1">
</i>
@ -125,7 +128,10 @@ exports[`zoom in and drag image to move 2`] = `
style="object-fit: contain;"
>
<div class="van-image__loading">
<div class="van-loading van-loading--spinner">
<div class="van-loading van-loading--spinner"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--spinner">
<i class="van-loading__line van-loading__line--1">
</i>

View File

@ -374,7 +374,10 @@ exports[`should render demo and match snapshot 1`] = `
style="width: 100%; height: 27vw;"
>
<div class="van-image__loading">
<div class="van-loading van-loading--spinner">
<div class="van-loading van-loading--spinner"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--spinner"
style="width: 20px; height: 20px;"
>

View File

@ -59,7 +59,10 @@ exports[`should render demo and match snapshot 1`] = `
aria-busy="true"
>
<div class="van-list__loading">
<div class="van-loading van-loading--circular van-list__loading-icon">
<div class="van-loading van-loading--circular van-list__loading-icon"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular">
<svg class="van-loading__circular"
viewbox="25 25 50 50"

View File

@ -62,7 +62,11 @@ export default defineComponent({
return () => {
const { type, vertical } = props;
return (
<div class={bem([type, { vertical }])}>
<div
class={bem([type, { vertical }])}
aria-live="polite"
aria-busy={true}
>
<span class={bem('spinner', type)} style={spinnerStyle.value}>
{type === 'spinner' ? SpinIcon : CircularIcon}
</span>

View File

@ -2,7 +2,10 @@
exports[`should render demo and match snapshot 1`] = `
<div>
<div class="van-loading van-loading--circular">
<div class="van-loading van-loading--circular"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular">
<svg class="van-loading__circular"
viewbox="25 25 50 50"
@ -16,7 +19,10 @@ exports[`should render demo and match snapshot 1`] = `
</svg>
</span>
</div>
<div class="van-loading van-loading--spinner">
<div class="van-loading van-loading--spinner"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--spinner">
<i class="van-loading__line van-loading__line--1">
</i>
@ -46,7 +52,10 @@ exports[`should render demo and match snapshot 1`] = `
</div>
</div>
<div>
<div class="van-loading van-loading--circular">
<div class="van-loading van-loading--circular"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular"
style="color: rgb(25, 137, 250);"
>
@ -62,7 +71,10 @@ exports[`should render demo and match snapshot 1`] = `
</svg>
</span>
</div>
<div class="van-loading van-loading--spinner">
<div class="van-loading van-loading--spinner"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--spinner"
style="color: rgb(25, 137, 250);"
>
@ -94,7 +106,10 @@ exports[`should render demo and match snapshot 1`] = `
</div>
</div>
<div>
<div class="van-loading van-loading--circular">
<div class="van-loading van-loading--circular"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular"
style="width: 24px; height: 24px;"
>
@ -110,7 +125,10 @@ exports[`should render demo and match snapshot 1`] = `
</svg>
</span>
</div>
<div class="van-loading van-loading--spinner">
<div class="van-loading van-loading--spinner"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--spinner"
style="width: 24px; height: 24px;"
>
@ -142,7 +160,10 @@ exports[`should render demo and match snapshot 1`] = `
</div>
</div>
<div>
<div class="van-loading van-loading--circular">
<div class="van-loading van-loading--circular"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular"
style="width: 24px; height: 24px;"
>
@ -163,7 +184,10 @@ exports[`should render demo and match snapshot 1`] = `
</div>
</div>
<div>
<div class="van-loading van-loading--circular van-loading--vertical">
<div class="van-loading van-loading--circular van-loading--vertical"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular"
style="width: 24px; height: 24px;"
>
@ -184,7 +208,10 @@ exports[`should render demo and match snapshot 1`] = `
</div>
</div>
<div>
<div class="van-loading van-loading--circular van-loading--vertical">
<div class="van-loading van-loading--circular van-loading--vertical"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular"
style="color: rgb(0, 148, 255); width: 24px; height: 24px;"
>
@ -205,7 +232,10 @@ exports[`should render demo and match snapshot 1`] = `
Loading...
</span>
</div>
<div class="van-loading van-loading--circular van-loading--vertical">
<div class="van-loading van-loading--circular van-loading--vertical"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular"
style="width: 24px; height: 24px;"
>

View File

@ -495,7 +495,10 @@ exports[`should render demo and match snapshot 1`] = `
Confirm
</button>
</div>
<div class="van-loading van-loading--circular van-picker__loading">
<div class="van-loading van-loading--circular van-picker__loading"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular">
<svg class="van-loading__circular"
viewbox="25 25 50 50"

View File

@ -48,7 +48,10 @@ exports[`should render different head content in different pulling status 3`] =
style="transition-duration: 300ms; transform: translate3d(0,50px, 0);"
>
<div class="van-pull-refresh__head">
<div class="van-loading van-loading--circular van-pull-refresh__loading">
<div class="van-loading van-loading--circular van-pull-refresh__loading"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular">
<svg class="van-loading__circular"
viewbox="25 25 50 50"
@ -76,7 +79,10 @@ exports[`should render different head content in different pulling status 4`] =
style="transition-duration: 300ms; transform: translate3d(0,50px, 0);"
>
<div class="van-pull-refresh__head">
<div class="van-loading van-loading--circular van-pull-refresh__loading">
<div class="van-loading van-loading--circular van-pull-refresh__loading"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular">
<svg class="van-loading__circular"
viewbox="25 25 50 50"

View File

@ -82,7 +82,10 @@ exports[`should render demo and match snapshot 1`] = `
class="van-button van-button--danger van-button--normal van-button--round van-button--loading van-submit-bar__button van-submit-bar__button--danger"
>
<div class="van-button__content">
<div class="van-loading van-loading--circular van-button__loading">
<div class="van-loading van-loading--circular van-button__loading"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular">
<svg class="van-loading__circular"
viewbox="25 25 50 50"

View File

@ -27,7 +27,10 @@ exports[`should render demo and match snapshot 1`] = `
aria-checked="true"
>
<div class="van-switch__node">
<div class="van-loading van-loading--circular van-switch__loading">
<div class="van-loading van-loading--circular van-switch__loading"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular">
<svg class="van-loading__circular"
viewbox="25 25 50 50"

View File

@ -1,7 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should apply active color to loading icon 1`] = `
<div class="van-loading van-loading--circular van-switch__loading">
<div class="van-loading van-loading--circular van-switch__loading"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular"
style="color: red;"
>
@ -20,7 +23,10 @@ exports[`should apply active color to loading icon 1`] = `
`;
exports[`should apply inactive color to loading icon 1`] = `
<div class="van-loading van-loading--circular van-switch__loading">
<div class="van-loading van-loading--circular van-switch__loading"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular"
style="color: black;"
>

View File

@ -11,6 +11,7 @@ import {
import {
pick,
extend,
toArray,
isPromise,
truthProp,
Interceptor,
@ -24,7 +25,6 @@ import {
import {
bem,
name,
toArray,
isOversize,
filterFiles,
isImageFile,

View File

@ -85,7 +85,10 @@ exports[`should render demo and match snapshot 1`] = `
</div>
</div>
<div class="van-uploader__mask">
<div class="van-loading van-loading--circular van-uploader__loading">
<div class="van-loading van-loading--circular van-uploader__loading"
aria-live="polite"
aria-busy="true"
>
<span class="van-loading__spinner van-loading__spinner--circular">
<svg class="van-loading__circular"
viewbox="25 25 50 50"

View File

@ -1,4 +1,4 @@
import { createNamespace, isFunction } from '../utils';
import { toArray, createNamespace, isFunction } from '../utils';
import type {
UploaderMaxSize,
UploaderResultType,
@ -9,9 +9,6 @@ const [name, bem, t] = createNamespace('uploader');
export { name, bem, t };
export const toArray = <T>(item: T | T[]): T[] =>
Array.isArray(item) ? item : [item];
export function readFileContent(file: File, resultType: UploaderResultType) {
return new Promise<string | void>((resolve) => {
if (resultType === 'file') {

View File

@ -39,3 +39,6 @@ export function pick<T, U extends keyof T>(
export const isSameValue = (newValue: unknown, oldValue: unknown) =>
JSON.stringify(newValue) === JSON.stringify(oldValue);
export const toArray = <T>(item: T | T[]): T[] =>
Array.isArray(item) ? item : [item];

View File

@ -858,30 +858,30 @@ export default {
path: 'use-event-listener',
title: 'useEventListener',
},
// {
// path: 'use-page-visibility',
// title: 'usePageVisibility',
// },
// {
// path: 'use-rect',
// title: 'useRect',
// },
// {
// path: 'use-relation',
// title: 'useRelation',
// },
// {
// path: 'use-scroll-parent',
// title: 'useScrollParent',
// },
{
path: 'use-page-visibility',
title: 'usePageVisibility',
},
{
path: 'use-rect',
title: 'useRect',
},
{
path: 'use-relation',
title: 'useRelation',
},
{
path: 'use-scroll-parent',
title: 'useScrollParent',
},
{
path: 'use-toggle',
title: 'useToggle',
},
// {
// path: 'use-window-size',
// title: 'useWindowSize',
// },
{
path: 'use-window-size',
title: 'useWindowSize',
},
],
},
],