mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-24 02:16:12 +08:00
Merge branch 'dev' into next
This commit is contained in:
commit
f2c151c337
@ -4,24 +4,32 @@
|
|||||||
|
|
||||||
这里提供了 Vant 现有的设计资源,更多资源还在整理中。
|
这里提供了 Vant 现有的设计资源,更多资源还在整理中。
|
||||||
|
|
||||||
### 组件
|
### 组件设计稿(Sketch)
|
||||||
|
|
||||||
包含 Sketch 格式的组件设计规范、色彩规范。
|
包含 Sketch 格式的组件设计规范、色彩规范。
|
||||||
|
|
||||||
<img src="https://img.yzcdn.cn/vant/design-components-0321.png" style="width: 80%;">
|
<img src="https://img.yzcdn.cn/vant/design-components-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/docs/assets/design.sketch?raw=true">下载</a>
|
<a class="design-download" href="https://github.com/youzan/vant/blob/dev/docs/assets/design.sketch?raw=true">下载</a>
|
||||||
|
|
||||||
> 提示:目前 Sketch 中部分组件仍为旧版样式,我们正在梳理新版设计规范,尽请期待!
|
> 提示:目前 Sketch 中部分组件仍为旧版样式,我们正在梳理新版设计规范,尽请期待!
|
||||||
|
|
||||||
### 图标
|
### 图标设计稿(Sketch)
|
||||||
|
|
||||||
包含 Sketch 格式的图标库资源。
|
包含 Sketch 格式的图标库资源。
|
||||||
|
|
||||||
<img src="https://img.yzcdn.cn/vant/design-icons-0321.png" style="width: 80%;">
|
<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-icons/blob/master/assets/icons.sketch?raw=true">下载</a>
|
<a class="design-download" href="https://github.com/youzan/vant-icons/blob/master/assets/icons.sketch?raw=true">下载</a>
|
||||||
|
|
||||||
|
### Axure 元件库
|
||||||
|
|
||||||
|
Axure 元件库,由社区的 [@axure-tczy](https://github.com/axure-tczy) 同学贡献。
|
||||||
|
|
||||||
|
<img src="https://img.yzcdn.cn/vant/vant-axure-0901-2.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-20200901.zip">下载</a>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
a.design-download {
|
a.design-download {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@ -34,6 +42,7 @@ a.design-download {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a.design-download:hover {
|
a.design-download:hover {
|
||||||
|
color: #fff;
|
||||||
opacity: .9;
|
opacity: .9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,6 +161,7 @@ export default {
|
|||||||
| route | Whether to enable route mode | _boolean_ | `false` |
|
| route | Whether to enable route mode | _boolean_ | `false` |
|
||||||
| placeholder `v2.6.0` | Whether to generage a placeholder element when fixed | _boolean_ | `false` |
|
| placeholder `v2.6.0` | Whether to generage a placeholder element when fixed | _boolean_ | `false` |
|
||||||
| safe-area-inset-bottom | Whether to enable bottom safe area adaptation | _boolean_ | `false` |
|
| safe-area-inset-bottom | Whether to enable bottom safe area adaptation | _boolean_ | `false` |
|
||||||
|
| before-change `v2.10.4` | Callback function before changing tabs,return `false` to prevent change,support return Promise | _(name) => boolean \| Promise_ | - |
|
||||||
|
|
||||||
### Tabbar Events
|
### Tabbar Events
|
||||||
|
|
||||||
|
@ -169,6 +169,7 @@ export default {
|
|||||||
| route | 是否开启路由模式 | _boolean_ | `false` |
|
| route | 是否开启路由模式 | _boolean_ | `false` |
|
||||||
| placeholder `v2.6.0` | 固定在底部时,是否在标签位置生成一个等高的占位元素 | _boolean_ | `false` |
|
| placeholder `v2.6.0` | 固定在底部时,是否在标签位置生成一个等高的占位元素 | _boolean_ | `false` |
|
||||||
| safe-area-inset-bottom | 是否开启[底部安全区适配](#/zh-CN/quickstart#di-bu-an-quan-qu-gua-pei),设置 fixed 时默认开启 | _boolean_ | `false` |
|
| safe-area-inset-bottom | 是否开启[底部安全区适配](#/zh-CN/quickstart#di-bu-an-quan-qu-gua-pei),设置 fixed 时默认开启 | _boolean_ | `false` |
|
||||||
|
| before-change `v2.10.4` | 切换标签前的回调函数,返回 `false` 可阻止切换,支持返回 Promise | _(name) => boolean \| Promise_ | - |
|
||||||
|
|
||||||
### Tabbar Events
|
### Tabbar Events
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { ref, reactive, provide } from 'vue';
|
import { ref, reactive, provide } from 'vue';
|
||||||
import { createNamespace, isDef } from '../utils';
|
import { createNamespace, isDef } from '../utils';
|
||||||
import { BORDER_TOP_BOTTOM } from '../utils/constant';
|
import { BORDER_TOP_BOTTOM } from '../utils/constant';
|
||||||
|
import { callInterceptor } from '../utils/interceptor';
|
||||||
import { useHeight } from '../composition/use-rect';
|
import { useHeight } from '../composition/use-rect';
|
||||||
|
|
||||||
const [createComponent, bem] = createNamespace('tabbar');
|
const [createComponent, bem] = createNamespace('tabbar');
|
||||||
@ -13,6 +14,7 @@ export default createComponent({
|
|||||||
zIndex: [Number, String],
|
zIndex: [Number, String],
|
||||||
placeholder: Boolean,
|
placeholder: Boolean,
|
||||||
activeColor: String,
|
activeColor: String,
|
||||||
|
beforeChange: Function,
|
||||||
inactiveColor: String,
|
inactiveColor: String,
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
@ -63,8 +65,14 @@ export default createComponent({
|
|||||||
|
|
||||||
const setActive = (active) => {
|
const setActive = (active) => {
|
||||||
if (active !== props.modelValue) {
|
if (active !== props.modelValue) {
|
||||||
|
callInterceptor({
|
||||||
|
interceptor: props.beforeChange,
|
||||||
|
args: [active],
|
||||||
|
done() {
|
||||||
emit('update:modelValue', active);
|
emit('update:modelValue', active);
|
||||||
emit('change', active);
|
emit('change', active);
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
// Utils
|
// Utils
|
||||||
import { createNamespace, isDef, addUnit, isPromise } from '../utils';
|
import { createNamespace, isDef, addUnit } from '../utils';
|
||||||
import { scrollLeftTo, scrollTopTo } from './utils';
|
import { scrollLeftTo, scrollTopTo } from './utils';
|
||||||
import { route } from '../composition/use-route';
|
import { route } from '../composition/use-route';
|
||||||
import { isHidden } from '../utils/dom/style';
|
import { isHidden } from '../utils/dom/style';
|
||||||
import { on, off } from '../utils/dom/event';
|
import { on, off } from '../utils/dom/event';
|
||||||
import { BORDER_TOP_BOTTOM } from '../utils/constant';
|
import { BORDER_TOP_BOTTOM } from '../utils/constant';
|
||||||
|
import { callInterceptor } from '../utils/interceptor';
|
||||||
import {
|
import {
|
||||||
getScroller,
|
getScroller,
|
||||||
getVisibleTop,
|
getVisibleTop,
|
||||||
@ -263,34 +264,21 @@ export default createComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
callBeforeChange(name, done) {
|
|
||||||
if (this.beforeChange) {
|
|
||||||
const returnVal = this.beforeChange(name);
|
|
||||||
|
|
||||||
if (isPromise(returnVal)) {
|
|
||||||
returnVal.then((value) => {
|
|
||||||
if (value) {
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (returnVal) {
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// emit event when clicked
|
// emit event when clicked
|
||||||
onClick(item, index) {
|
onClick(item, index) {
|
||||||
const { title, disabled, computedName } = this.children[index];
|
const { title, disabled, computedName } = this.children[index];
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
this.$emit('disabled', computedName, title);
|
this.$emit('disabled', computedName, title);
|
||||||
} else {
|
} else {
|
||||||
this.callBeforeChange(computedName, () => {
|
callInterceptor({
|
||||||
|
interceptor: this.beforeChange,
|
||||||
|
args: [computedName],
|
||||||
|
done: () => {
|
||||||
this.setCurrentIndex(index);
|
this.setCurrentIndex(index);
|
||||||
this.scrollToCurrentContent();
|
this.scrollToCurrentContent();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$emit('click', computedName, title);
|
this.$emit('click', computedName, title);
|
||||||
route(item.$router, item);
|
route(item.$router, item);
|
||||||
}
|
}
|
||||||
|
27
src/utils/interceptor.ts
Normal file
27
src/utils/interceptor.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { isPromise, noop } from '.';
|
||||||
|
|
||||||
|
export function callInterceptor(options: {
|
||||||
|
interceptor?: (...args: any[]) => Promise<boolean> | boolean;
|
||||||
|
done: () => void;
|
||||||
|
args: any[];
|
||||||
|
}) {
|
||||||
|
const { interceptor, args, done } = options;
|
||||||
|
|
||||||
|
if (interceptor) {
|
||||||
|
const returnVal = interceptor(...args);
|
||||||
|
|
||||||
|
if (isPromise(returnVal)) {
|
||||||
|
returnVal
|
||||||
|
.then((value) => {
|
||||||
|
if (value) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(noop);
|
||||||
|
} else if (returnVal) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
50
src/utils/test/interceptor.spec.js
Normal file
50
src/utils/test/interceptor.spec.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { later } from '../../../test';
|
||||||
|
import { callInterceptor } from '../interceptor';
|
||||||
|
|
||||||
|
test('#callInterceptor', async () => {
|
||||||
|
const done = jest.fn();
|
||||||
|
callInterceptor({ done });
|
||||||
|
expect(done).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
callInterceptor({
|
||||||
|
interceptor: () => false,
|
||||||
|
done,
|
||||||
|
});
|
||||||
|
expect(done).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
|
callInterceptor({
|
||||||
|
interceptor: () => true,
|
||||||
|
done,
|
||||||
|
});
|
||||||
|
expect(done).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
|
callInterceptor({
|
||||||
|
interceptor: () => Promise.resolve(false),
|
||||||
|
done,
|
||||||
|
});
|
||||||
|
await later();
|
||||||
|
expect(done).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
|
callInterceptor({
|
||||||
|
interceptor: () => Promise.resolve(true),
|
||||||
|
done,
|
||||||
|
});
|
||||||
|
await later();
|
||||||
|
expect(done).toHaveBeenCalledTimes(3);
|
||||||
|
|
||||||
|
callInterceptor({
|
||||||
|
interceptor: () => Promise.reject(),
|
||||||
|
done,
|
||||||
|
});
|
||||||
|
await later();
|
||||||
|
expect(done).toHaveBeenCalledTimes(3);
|
||||||
|
|
||||||
|
callInterceptor({
|
||||||
|
interceptor: (...args) => {
|
||||||
|
expect(args).toEqual(['foo']);
|
||||||
|
},
|
||||||
|
args: ['foo'],
|
||||||
|
done,
|
||||||
|
});
|
||||||
|
expect(done).toHaveBeenCalledTimes(3);
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user