mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
feat: Overlay component
This commit is contained in:
parent
bad69d9f3f
commit
2a41dcf58e
79
src-next/overlay/README.md
Normal file
79
src-next/overlay/README.md
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
# Overlay
|
||||||
|
|
||||||
|
### Install
|
||||||
|
|
||||||
|
```js
|
||||||
|
import Vue from 'vue';
|
||||||
|
import { Overlay } from 'vant';
|
||||||
|
|
||||||
|
Vue.use(Overlay);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-button type="primary" text="Show Overlay" @click="show = true" />
|
||||||
|
<van-overlay :show="show" @click="show = false" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
### Embedded Content
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-overlay :show="show" @click="show = false">
|
||||||
|
<div class="wrapper" @click.stop>
|
||||||
|
<div class="block" />
|
||||||
|
</div>
|
||||||
|
</van-overlay>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### Props
|
||||||
|
|
||||||
|
| Attribute | Description | Type | Default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| show | Whether to show overlay | _boolean_ | `false` |
|
||||||
|
| z-index | z-index | _number \| string_ | `1` |
|
||||||
|
| duration | Animation duration | _number \| string_ | `0.3` |
|
||||||
|
| class-name | ClassName | _string_ | - |
|
||||||
|
| custom-class `v2.2.5` | Custom style | _object_ | - |
|
||||||
|
| lock-scroll `v2.6.2` | Whether to lock background scroll | _boolean_ | `true` |
|
||||||
|
|
||||||
|
### Events
|
||||||
|
|
||||||
|
| Event | Description | Arguments |
|
||||||
|
| ----- | ---------------------- | -------------- |
|
||||||
|
| click | Triggered when clicked | _event: Event_ |
|
||||||
|
|
||||||
|
### Slots
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
| ---------------- | ------------ |
|
||||||
|
| default `v2.2.5` | Default slot |
|
85
src-next/overlay/README.zh-CN.md
Normal file
85
src-next/overlay/README.zh-CN.md
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
# Overlay 遮罩层
|
||||||
|
|
||||||
|
### 介绍
|
||||||
|
|
||||||
|
创建一个遮罩层,用于强调特定的页面元素,并阻止用户进行其他操作
|
||||||
|
|
||||||
|
### 引入
|
||||||
|
|
||||||
|
```js
|
||||||
|
import Vue from 'vue';
|
||||||
|
import { Overlay } from 'vant';
|
||||||
|
|
||||||
|
Vue.use(Overlay);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 代码演示
|
||||||
|
|
||||||
|
### 基础用法
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-button type="primary" text="显示遮罩层" @click="show = true" />
|
||||||
|
<van-overlay :show="show" @click="show = false" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
### 嵌入内容
|
||||||
|
|
||||||
|
通过默认插槽可以在遮罩层上嵌入任意内容
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-overlay :show="show" @click="show = false">
|
||||||
|
<div class="wrapper" @click.stop>
|
||||||
|
<div class="block" />
|
||||||
|
</div>
|
||||||
|
</van-overlay>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### Props
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| show | 是否展示遮罩层 | _boolean_ | `false` |
|
||||||
|
| z-index | z-index 层级 | _number \| string_ | `1` |
|
||||||
|
| duration | 动画时长,单位秒 | _number \| string_ | `0.3` |
|
||||||
|
| class-name | 自定义类名 | _string_ | - |
|
||||||
|
| custom-style `v2.2.5` | 自定义样式 | _object_ | - |
|
||||||
|
| lock-scroll `v2.6.2` | 是否锁定背景滚动,锁定时蒙层里的内容也将无法滚动 | _boolean_ | `true` |
|
||||||
|
|
||||||
|
### Events
|
||||||
|
|
||||||
|
| 事件名 | 说明 | 回调参数 |
|
||||||
|
| ------ | ---------- | -------------- |
|
||||||
|
| click | 点击时触发 | _event: Event_ |
|
||||||
|
|
||||||
|
### Slots
|
||||||
|
|
||||||
|
| 名称 | 说明 |
|
||||||
|
| ---------------- | ---------------------------------- |
|
||||||
|
| default `v2.0.5` | 默认插槽,用于在遮罩层上方嵌入内容 |
|
72
src-next/overlay/demo/index.vue
Normal file
72
src-next/overlay/demo/index.vue
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<template>
|
||||||
|
<demo-section>
|
||||||
|
<demo-block :title="t('basicUsage')">
|
||||||
|
<van-button
|
||||||
|
type="primary"
|
||||||
|
:text="t('showOverlay')"
|
||||||
|
style="margin-left: 16px;"
|
||||||
|
@click="show = true"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<van-overlay :show="show" @click="show = false" />
|
||||||
|
</demo-block>
|
||||||
|
|
||||||
|
<demo-block :title="t('embeddedContent')">
|
||||||
|
<van-button
|
||||||
|
type="primary"
|
||||||
|
:text="t('embeddedContent')"
|
||||||
|
style="margin-left: 16px;"
|
||||||
|
@click="showEmbedded = true"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<van-overlay :show="showEmbedded" @click="showEmbedded = false">
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="block" />
|
||||||
|
</div>
|
||||||
|
</van-overlay>
|
||||||
|
</demo-block>
|
||||||
|
</demo-section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
i18n: {
|
||||||
|
'zh-CN': {
|
||||||
|
showOverlay: '显示遮罩层',
|
||||||
|
embeddedContent: '嵌入内容',
|
||||||
|
},
|
||||||
|
'en-US': {
|
||||||
|
showOverlay: 'Show Overlay',
|
||||||
|
embeddedContent: 'Embedded Content',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
show: false,
|
||||||
|
showEmbedded: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
@import '../../style/var';
|
||||||
|
|
||||||
|
.demo-overlay {
|
||||||
|
background: @white;
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
background-color: @white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
49
src-next/overlay/index.js
Normal file
49
src-next/overlay/index.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { Transition } from 'vue';
|
||||||
|
import { createNamespace, isDef, noop } from '../utils';
|
||||||
|
import { preventDefault } from '../utils/dom/event';
|
||||||
|
|
||||||
|
const [createComponent, bem] = createNamespace('overlay');
|
||||||
|
|
||||||
|
function preventTouchMove(event) {
|
||||||
|
preventDefault(event, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createComponent({
|
||||||
|
props: {
|
||||||
|
show: Boolean,
|
||||||
|
zIndex: [Number, String],
|
||||||
|
duration: [Number, String],
|
||||||
|
className: null,
|
||||||
|
customStyle: Object,
|
||||||
|
lockScroll: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
setup(props, { slots }) {
|
||||||
|
return function () {
|
||||||
|
const style = {
|
||||||
|
zIndex: props.zIndex,
|
||||||
|
...props.customStyle,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isDef(props.duration)) {
|
||||||
|
style.animationDuration = `${props.duration}s`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Transition name="van-fade">
|
||||||
|
<div
|
||||||
|
vShow={props.show}
|
||||||
|
style={style}
|
||||||
|
class={[bem(), props.className]}
|
||||||
|
onTouchmove={props.lockScroll ? preventTouchMove : noop}
|
||||||
|
>
|
||||||
|
{slots.default?.()}
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
11
src-next/overlay/index.less
Normal file
11
src-next/overlay/index.less
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
@import '../style/var';
|
||||||
|
|
||||||
|
.van-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: @overlay-z-index;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: @overlay-background-color;
|
||||||
|
}
|
4
src-next/overlay/test/demo.spec.js
Normal file
4
src-next/overlay/test/demo.spec.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import Demo from '../demo';
|
||||||
|
import { snapshotDemo } from '../../../test/demo';
|
||||||
|
|
||||||
|
snapshotDemo(Demo);
|
98
src-next/overlay/test/index.spec.js
Normal file
98
src-next/overlay/test/index.spec.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import { mount } from '../../../test';
|
||||||
|
import Overlay from '..';
|
||||||
|
|
||||||
|
test('z-index prop', () => {
|
||||||
|
const wrapper = mount(Overlay, {
|
||||||
|
propsData: {
|
||||||
|
show: true,
|
||||||
|
zIndex: 99,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('class-name prop', () => {
|
||||||
|
const wrapper = mount(Overlay, {
|
||||||
|
propsData: {
|
||||||
|
show: true,
|
||||||
|
className: 'my-overlay',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('custom style prop', () => {
|
||||||
|
const wrapper = mount(Overlay, {
|
||||||
|
propsData: {
|
||||||
|
show: true,
|
||||||
|
customStyle: {
|
||||||
|
backgroundColor: 'red',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('duration prop', () => {
|
||||||
|
const wrapper = mount(Overlay, {
|
||||||
|
propsData: {
|
||||||
|
show: true,
|
||||||
|
duration: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('click event', () => {
|
||||||
|
const onClick = jest.fn();
|
||||||
|
const wrapper = mount(Overlay, {
|
||||||
|
context: {
|
||||||
|
on: {
|
||||||
|
click: onClick,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper.trigger('click');
|
||||||
|
expect(onClick).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('default slot', () => {
|
||||||
|
const wrapper = mount(Overlay, {
|
||||||
|
scopedSlots: {
|
||||||
|
default: () => 'Custom Default',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('lock-scroll prop', () => {
|
||||||
|
const onTouchMove = jest.fn();
|
||||||
|
const wrapper = mount({
|
||||||
|
template: `
|
||||||
|
<div @touchmove="onTouchMove">
|
||||||
|
<van-overlay :lock-scroll="lockScroll" />
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
lockScroll: true,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onTouchMove,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper.find('.van-overlay').trigger('touchmove');
|
||||||
|
expect(onTouchMove).toHaveBeenCalledTimes(0);
|
||||||
|
|
||||||
|
wrapper.setData({ lockScroll: false });
|
||||||
|
wrapper.find('.van-overlay').trigger('touchmove');
|
||||||
|
expect(onTouchMove).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user