[breaking change] CellSwipe: rename to SwipeCell (#1652)
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<div>
|
||||
<demo-section>
|
||||
<van-notice-bar>{{ $t('tips') }}</van-notice-bar>
|
||||
<demo-block :title="$t('basicUsage')">
|
||||
<van-swipe-cell :right-width="65" :left-width="65">
|
||||
<span slot="left">{{ $t('button1') }}</span>
|
||||
<van-cell-group>
|
||||
<van-cell :title="$t('title')" :value="$t('content')" />
|
||||
</van-cell-group>
|
||||
<span slot="right">{{ $t('button2') }}</span>
|
||||
</van-swipe-cell>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="$t('title2')">
|
||||
<van-swipe-cell :right-width="65" :left-width="65" :on-close="onClose">
|
||||
<span slot="left">{{ $t('button1') }}</span>
|
||||
<van-cell-group>
|
||||
<van-cell :title="$t('title')" :value="$t('content')" />
|
||||
</van-cell-group>
|
||||
<span slot="right">{{ $t('button2') }}</span>
|
||||
</van-swipe-cell>
|
||||
</demo-block>
|
||||
</demo-section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
i18n: {
|
||||
'zh-CN': {
|
||||
button1: '选择',
|
||||
button2: '删除',
|
||||
title: '单元格',
|
||||
title2: '异步关闭',
|
||||
confirm: '确定删除吗?',
|
||||
tips: '建议在手机模式下浏览本示例'
|
||||
},
|
||||
'en-US': {
|
||||
button1: 'Select',
|
||||
button2: 'Delete',
|
||||
title: 'Cell',
|
||||
title2: 'Async close',
|
||||
confirm: 'Are you sure to delete?',
|
||||
tips: 'Please try this demo in mobile mode'
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClose(clickPosition, instance) {
|
||||
switch (clickPosition) {
|
||||
case 'left':
|
||||
case 'cell':
|
||||
case 'outside':
|
||||
instance.close();
|
||||
break;
|
||||
case 'right':
|
||||
this.$dialog.confirm({
|
||||
message: this.$t('confirm')
|
||||
}).then(() => {
|
||||
instance.close();
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="postcss">
|
||||
.demo-swipe-cell {
|
||||
user-select: none;
|
||||
|
||||
.van-swipe-cell {
|
||||
&__left,
|
||||
&__right {
|
||||
color: #FFFFFF;
|
||||
font-size: 15px;
|
||||
width: 65px;
|
||||
height: 44px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
line-height: 44px;
|
||||
background-color: #F44;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,89 @@
|
||||
## SwipeCell
|
||||
|
||||
### Install
|
||||
``` javascript
|
||||
import { SwipeCell } from 'vant';
|
||||
|
||||
Vue.use(SwipeCell);
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
#### Basic Usage
|
||||
|
||||
```html
|
||||
<van-swipe-cell :right-width="65" :left-width="65">
|
||||
<span slot="left">Select</span>
|
||||
<van-cell-group>
|
||||
<van-cell title="Cell" value="Cell Content" />
|
||||
</van-cell-group>
|
||||
<span slot="right">Delete</span>
|
||||
</van-swipe-cell>
|
||||
```
|
||||
|
||||
#### Async close
|
||||
|
||||
```html
|
||||
<van-swipe-cell :right-width="65" :left-width="65" :on-close="onClose">
|
||||
<span slot="left">Select</span>
|
||||
<van-cell-group>
|
||||
<van-cell title="Cell" value="Cell Content" />
|
||||
</van-cell-group>
|
||||
<span slot="right">Delete</span>
|
||||
</van-swipe-cell>
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
methods: {
|
||||
onClose(clickPosition, instance) {
|
||||
switch (clickPosition) {
|
||||
case 'left':
|
||||
case 'cell':
|
||||
case 'outside':
|
||||
instance.close();
|
||||
break;
|
||||
case 'right':
|
||||
Dialog.confirm({
|
||||
message: 'Are you sure to delete?'
|
||||
}).then(() => {
|
||||
instance.close();
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
|-----------|-----------|-----------|-------------|
|
||||
| left-width | Width of the left scrollable area | `Number` | `0` |
|
||||
| right-width | Width of the right scrollable area | `Number` | `0` |
|
||||
| on-close | Callback function before close | `Function` | - |
|
||||
|
||||
### Slot
|
||||
|
||||
| name | Description |
|
||||
|-----------|-----------|
|
||||
| - | custom content |
|
||||
| left | content of left scrollable area |
|
||||
| right | content of right scrollabe area |
|
||||
|
||||
### onClose Params
|
||||
|
||||
| Argument | Type | Description |
|
||||
|-----------|-----------|-----------|
|
||||
| clickPosition | `String` | Click positon (`left` `right` `cell` `outside`) |
|
||||
| instance | `Object` | SwipeCell instance |
|
||||
|
||||
### Methods
|
||||
|
||||
Use ref to get SwipeCell instance and call instance methods
|
||||
|
||||
| Name | Attribute | Return value | Description |
|
||||
|-----------|-----------|-----------|-------------|
|
||||
| open | position: 'left' \| 'right' | - | open SwipeCell |
|
||||
| close | - | - | close SwipeCell |
|
||||
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<div
|
||||
v-clickoutside:touchstart="onClick"
|
||||
:class="b()"
|
||||
@click="onClick('cell')"
|
||||
@touchstart="startDrag"
|
||||
@touchmove="onDrag"
|
||||
@touchend="endDrag"
|
||||
@touchcancel="endDrag"
|
||||
>
|
||||
<div
|
||||
:class="b('wrapper')"
|
||||
:style="wrapperStyle"
|
||||
@transitionend="swipe = false"
|
||||
>
|
||||
<div v-if="leftWidth" :class="b('left')" @click.stop="onClick('left')">
|
||||
<slot name="left" />
|
||||
</div>
|
||||
<slot />
|
||||
<div v-if="rightWidth" :class="b('right')" @click.stop="onClick('right')">
|
||||
<slot name="right" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import create from '../utils/create';
|
||||
import Clickoutside from '../utils/clickoutside';
|
||||
import Touch from '../mixins/touch';
|
||||
|
||||
const THRESHOLD = 0.15;
|
||||
|
||||
export default create({
|
||||
name: 'swipe-cell',
|
||||
|
||||
mixins: [Touch],
|
||||
|
||||
props: {
|
||||
onClose: Function,
|
||||
leftWidth: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
rightWidth: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
|
||||
directives: {
|
||||
Clickoutside
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
offset: 0,
|
||||
draging: false
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
wrapperStyle() {
|
||||
return {
|
||||
transform: `translate3d(${this.offset}px, 0, 0)`,
|
||||
transition: this.draging ? 'none' : '.6s cubic-bezier(0.18, 0.89, 0.32, 1)'
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
open(position) {
|
||||
const offset = position === 'left' ? this.leftWidth : -this.rightWidth;
|
||||
this.swipeMove(offset);
|
||||
this.resetSwipeStatus();
|
||||
},
|
||||
|
||||
close() {
|
||||
this.offset = 0;
|
||||
},
|
||||
|
||||
resetSwipeStatus() {
|
||||
this.swiping = false;
|
||||
this.opened = true;
|
||||
},
|
||||
|
||||
swipeMove(offset = 0) {
|
||||
this.offset = offset;
|
||||
offset && (this.swiping = true);
|
||||
!offset && (this.opened = false);
|
||||
},
|
||||
|
||||
swipeLeaveTransition(direction) {
|
||||
const { offset, leftWidth, rightWidth } = this;
|
||||
const threshold = this.opened ? (1 - THRESHOLD) : THRESHOLD;
|
||||
|
||||
// right
|
||||
if (direction > 0 && -offset > rightWidth * threshold && rightWidth > 0) {
|
||||
this.open('right');
|
||||
// left
|
||||
} else if (direction < 0 && offset > leftWidth * threshold && leftWidth > 0) {
|
||||
this.open('left');
|
||||
} else {
|
||||
this.swipeMove();
|
||||
}
|
||||
},
|
||||
|
||||
startDrag(event) {
|
||||
this.draging = true;
|
||||
this.touchStart(event);
|
||||
|
||||
if (this.opened) {
|
||||
this.startX -= this.offset;
|
||||
}
|
||||
},
|
||||
|
||||
onDrag(event) {
|
||||
this.touchMove(event);
|
||||
const { deltaX } = this;
|
||||
|
||||
if ((deltaX < 0 && (-deltaX > this.rightWidth || !this.rightWidth)) ||
|
||||
(deltaX > 0 && (deltaX > this.leftWidth || deltaX > 0 && !this.leftWidth))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.direction === 'horizontal') {
|
||||
event.preventDefault();
|
||||
this.swipeMove(deltaX);
|
||||
};
|
||||
},
|
||||
|
||||
endDrag() {
|
||||
this.draging = false;
|
||||
if (this.swiping) {
|
||||
this.swipeLeaveTransition(this.offset > 0 ? -1 : 1);
|
||||
};
|
||||
},
|
||||
|
||||
onClick(position = 'outside') {
|
||||
if (!this.offset) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.onClose) {
|
||||
this.onClose(position, this);
|
||||
} else {
|
||||
this.swipeMove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,51 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders demo correctly 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
<div class="van-notice-bar" style="color:undefined;background:undefined;">
|
||||
<!---->
|
||||
<div class="van-notice-bar__wrap">
|
||||
<div class="van-notice-bar__content" style="padding-left:0;animation-delay:1s;animation-duration:0s;">建议在手机模式下浏览本示例</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-swipe-cell">
|
||||
<div class="van-swipe-cell__wrapper" style="transform:translate3d(0px, 0, 0);transition:.6s cubic-bezier(0.18, 0.89, 0.32, 1);">
|
||||
<div class="van-swipe-cell__left"><span>选择</span></div>
|
||||
<div class="van-cell-group van-hairline--top-bottom">
|
||||
<div class="van-cell van-hairline">
|
||||
<!---->
|
||||
<div class="van-cell__title"><span>单元格</span>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="van-cell__value"><span>内容</span></div>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-swipe-cell__right"><span>删除</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-swipe-cell">
|
||||
<div class="van-swipe-cell__wrapper" style="transform:translate3d(0px, 0, 0);transition:.6s cubic-bezier(0.18, 0.89, 0.32, 1);">
|
||||
<div class="van-swipe-cell__left"><span>选择</span></div>
|
||||
<div class="van-cell-group van-hairline--top-bottom">
|
||||
<div class="van-cell van-hairline">
|
||||
<!---->
|
||||
<div class="van-cell__title"><span>单元格</span>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="van-cell__value"><span>内容</span></div>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-swipe-cell__right"><span>删除</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,46 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`drag and show left part 1`] = `
|
||||
<div class="van-swipe-cell">
|
||||
<div class="van-swipe-cell__wrapper">
|
||||
<div class="van-swipe-cell__left"></div>
|
||||
<div class="van-swipe-cell__right"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`drag and show left part 2`] = `
|
||||
<div class="van-swipe-cell">
|
||||
<div class="van-swipe-cell__wrapper">
|
||||
<div class="van-swipe-cell__left"></div>
|
||||
<div class="van-swipe-cell__right"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`drag and show left part 3`] = `
|
||||
<div class="van-swipe-cell">
|
||||
<div class="van-swipe-cell__wrapper">
|
||||
<div class="van-swipe-cell__left"></div>
|
||||
<div class="van-swipe-cell__right"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`drag and show left part 4`] = `
|
||||
<div class="van-swipe-cell">
|
||||
<div class="van-swipe-cell__wrapper">
|
||||
<div class="van-swipe-cell__left"></div>
|
||||
<div class="van-swipe-cell__right"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`drag and show left part 5`] = `
|
||||
<div class="van-swipe-cell">
|
||||
<div class="van-swipe-cell__wrapper">
|
||||
<div class="van-swipe-cell__left"></div>
|
||||
<div class="van-swipe-cell__right"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,4 @@
|
||||
import Demo from '../demo';
|
||||
import demoTest from '../../../test/demo-test';
|
||||
|
||||
demoTest(Demo);
|
||||
@@ -0,0 +1,66 @@
|
||||
import SwipeCell from '..';
|
||||
import { mount, triggerDrag } from '../../../test/utils';
|
||||
|
||||
const defaultProps = {
|
||||
propsData: {
|
||||
leftWidth: 100,
|
||||
rightWidth: 100
|
||||
}
|
||||
};
|
||||
|
||||
it('drag and show left part', () => {
|
||||
const wrapper = mount(SwipeCell, defaultProps);
|
||||
|
||||
triggerDrag(wrapper, 10, 0);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
||||
triggerDrag(wrapper, 50, 0);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
||||
triggerDrag(wrapper, 500, 0);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
||||
triggerDrag(wrapper, 0, 100);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('drag and show left part', () => {
|
||||
const wrapper = mount(SwipeCell, defaultProps);
|
||||
|
||||
triggerDrag(wrapper, -50, 0);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('on close prop', () => {
|
||||
let position;
|
||||
let instance;
|
||||
|
||||
const wrapper = mount(SwipeCell, {
|
||||
propsData: {
|
||||
...defaultProps.propsData,
|
||||
onClose(pos, ins) {
|
||||
position = pos;
|
||||
instance = ins;
|
||||
}
|
||||
}
|
||||
});
|
||||
wrapper.trigger('click');
|
||||
expect(position).toEqual(undefined);
|
||||
|
||||
wrapper.setData({ offset: 100 });
|
||||
wrapper.trigger('click');
|
||||
expect(position).toEqual('cell');
|
||||
|
||||
wrapper.find('.van-swipe-cell__left').trigger('click');
|
||||
expect(position).toEqual('left');
|
||||
|
||||
wrapper.find('.van-swipe-cell__right').trigger('click');
|
||||
expect(position).toEqual('right');
|
||||
|
||||
instance.close();
|
||||
expect(wrapper.vm.offset).toEqual(0);
|
||||
|
||||
wrapper.setData({ offset: 100, onClose: null });
|
||||
wrapper.trigger('click');
|
||||
expect(wrapper.vm.offset).toEqual(0);
|
||||
});
|
||||
@@ -0,0 +1,89 @@
|
||||
## SwipeCell 滑动单元格
|
||||
|
||||
### 使用指南
|
||||
``` javascript
|
||||
import { SwipeCell } from 'vant';
|
||||
|
||||
Vue.use(SwipeCell);
|
||||
```
|
||||
|
||||
### 代码演示
|
||||
|
||||
#### 基础用法
|
||||
|
||||
```html
|
||||
<van-swipe-cell :right-width="65" :left-width="65">
|
||||
<span slot="left">选择</span>
|
||||
<van-cell-group>
|
||||
<van-cell title="单元格" value="内容" />
|
||||
</van-cell-group>
|
||||
<span slot="right">删除</span>
|
||||
</van-swipe-cell>
|
||||
```
|
||||
|
||||
#### 异步关闭
|
||||
|
||||
```html
|
||||
<van-swipe-cell :right-width="65" :left-width="65" :on-close="onClose">
|
||||
<span slot="left">选择</span>
|
||||
<van-cell-group>
|
||||
<van-cell title="单元格" value="内容" />
|
||||
</van-cell-group>
|
||||
<span slot="right">删除</span>
|
||||
</van-swipe-cell>
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
methods: {
|
||||
onClose(clickPosition, instance) {
|
||||
switch (clickPosition) {
|
||||
case 'left':
|
||||
case 'cell':
|
||||
case 'outside':
|
||||
instance.close();
|
||||
break;
|
||||
case 'right':
|
||||
Dialog.confirm({
|
||||
message: '确定删除吗?'
|
||||
}).then(() => {
|
||||
instance.close();
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|-----------|-----------|-----------|-------------|
|
||||
| left-width | 左侧滑动区域宽度 | `Number` | `0` |
|
||||
| right-width | 右侧滑动区域宽度 | `Number` | `0` |
|
||||
| on-close | 关闭时的回调函数 | `Function` | - |
|
||||
|
||||
### Slot
|
||||
|
||||
| 名称 | 说明 |
|
||||
|-----------|-----------|
|
||||
| - | 自定义显示内容 |
|
||||
| left | 左侧滑动内容 |
|
||||
| right | 右侧滑动内容 |
|
||||
|
||||
### onClose 参数
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
|-----------|-----------|-----------|
|
||||
| clickPosition | `String` | 关闭时的点击位置 (`left` `right` `cell` `outside`) |
|
||||
| instance | `Object` | SwipeCell 实例 |
|
||||
|
||||
### 方法
|
||||
|
||||
通过 ref 可以获取到 SwipeCell 实例并调用实例方法
|
||||
|
||||
| 方法名 | 参数 | 返回值 | 介绍 |
|
||||
|-----------|-----------|-----------|-------------|
|
||||
| open | position: 'left' \| 'right' | - | 打开单元格侧边栏 |
|
||||
| close | - | - | 收起单元格侧边栏 |
|
||||
Reference in New Issue
Block a user