diff --git a/components.json b/components.json
index da3f772d4..dd4b25daa 100644
--- a/components.json
+++ b/components.json
@@ -6,6 +6,7 @@
   "cell": "./packages/cell/index.js",
   "icon": "./packages/icon/index.js",
   "cell-group": "./packages/cell-group/index.js",
+  "cell-swipe": "./packages/cell-swipe/index.js",
   "popup": "./packages/popup/index.js",
   "dialog": "./packages/dialog/index.js",
   "picker": "./packages/picker/index.js",
diff --git a/docs/examples-dist/cell-swipe.vue b/docs/examples-dist/cell-swipe.vue
new file mode 100644
index 000000000..cd91bd534
--- /dev/null
+++ b/docs/examples-dist/cell-swipe.vue
@@ -0,0 +1,39 @@
+<template><section class="demo-cell"><h1 class="demo-title">Cell Swipe 滑动单元格</h1><example-block title="基础用法">
+                <van-cell-swipe :right-width="65" :left-width="65">
+  <van-cell-group>
+    <van-cell title="单元格1" value="单元格1内容"></van-cell>
+  </van-cell-group>
+  
+  <span slot="right" class="swipe-delete-btn">
+      删除
+  </span>
+  <span slot="left" class="swipe-check-btn">
+      选择
+  </span>
+</van-cell-swipe>
+
+              </example-block></section></template>
+<style>
+.swipe-delete-btn {
+    background-color: #FF4444;
+    color: #FFFFFF;
+    font-size: 16px;
+    width: 65px;
+    height: 44px;
+    display: inline-block;
+    text-align: center;
+    line-height: 44px;
+}
+.swipe-check-btn {
+    background-color: #84c483;
+    color: #FFFFFF;
+    font-size: 16px;
+    width: 65px;
+    height: 44px;
+    display: inline-block;
+    text-align: center;
+    line-height: 44px;
+}
+</style>
+<script>
+import Vue from "vue";import ExampleBlock from "components/example-block";Vue.component("example-block", ExampleBlock);</script>
\ No newline at end of file
diff --git a/docs/examples-dist/search.vue b/docs/examples-dist/search.vue
index 24b981d97..0a05cfb6e 100644
--- a/docs/examples-dist/search.vue
+++ b/docs/examples-dist/search.vue
@@ -3,6 +3,9 @@
 
 
 
+              </example-block><example-block title="基础用法">
+                <van-search placeholder="搜索商品" type="showcase"></van-search>
+
               </example-block><example-block title="监听对应事件">
                 <van-search placeholder="商品名称" @search="goSearch" @change="handleChange" @cancel="handleCancel"></van-search>
 
diff --git a/docs/examples-docs/cell-swipe.md b/docs/examples-docs/cell-swipe.md
new file mode 100644
index 000000000..51659b0be
--- /dev/null
+++ b/docs/examples-docs/cell-swipe.md
@@ -0,0 +1,91 @@
+
+<style>
+.swipe-delete-btn {
+    background-color: #FF4444;
+    color: #FFFFFF;
+    font-size: 16px;
+    width: 65px;
+    height: 44px;
+    display: inline-block;
+    text-align: center;
+    line-height: 44px;
+}
+.swipe-check-btn {
+    background-color: #84c483;
+    color: #FFFFFF;
+    font-size: 16px;
+    width: 65px;
+    height: 44px;
+    display: inline-block;
+    text-align: center;
+    line-height: 44px;
+}
+</style>
+## 滑动单元格
+
+### 使用指南
+
+如果你已经按照快速上手中引入了整个`vant`,以下**组件注册**就可以忽略了,因为你已经全局注册了`vant`中的全部组件。
+
+#### 全局注册
+
+你可以在全局注册`Cell Swipe`组件,比如页面的主文件(`index.js`,`main.js`),这样页面任何地方都可以直接使用`Cell Swipe`组件了:
+
+```js
+import Vue from 'vue';
+import { CellSwipe } from 'vant';
+import 'vant/lib/vant-css/cell-swipe.css';
+
+Vue.component(CellSwipe.name, CellSwipe);
+```
+
+#### 局部注册
+
+如果你只是想在某个组件中使用,你可以在对应组件中注册`Cell Swipe`组件,这样只能在你注册的组件中使用`Cell Swipe`:
+
+```js
+import { CellSwipe } from 'vant';
+
+export default {
+  components: {
+    'van-cell-swipe': CellSwipe
+  }
+};
+```
+
+### 代码演示
+
+#### 基础用法
+
+:::demo 基础用法
+```html
+<van-cell-swipe :right-width="65" :left-width="65">
+  <van-cell-group>
+    <van-cell title="单元格1" value="单元格1内容"></van-cell>
+  </van-cell-group>
+  
+  <span slot="right" class="swipe-delete-btn">
+      删除
+  </span>
+  <span slot="left" class="swipe-check-btn">
+      选择
+  </span>
+</van-cell-swipe>
+```
+:::
+
+
+### API
+
+| 参数       | 说明      | 类型       | 默认值       | 可选值       |
+|-----------|-----------|-----------|-------------|-------------|
+| right-width | 右侧滑动按钮宽度 | `number`  |      0     |           |
+| left-width | 左侧滑动按钮宽度 | `number`  |       0    |           |
+
+### Slot
+
+| name       | 描述      |
+|-----------|-----------|
+| - | 自定义显示内容 |
+| right | 右侧滑动内容 |
+| left | 左侧滑动内容 |
diff --git a/docs/src/nav.config.js b/docs/src/nav.config.js
index b64adcc35..6f155b732 100644
--- a/docs/src/nav.config.js
+++ b/docs/src/nav.config.js
@@ -37,6 +37,10 @@ module.exports = {
               "path": "/cell",
               "title": "Cell 单元格"
             },
+            {
+              "path": "/cell-swipe",
+              "title": "Cell Swipe 滑动单元格"
+            },
             {
               "path": "/progress",
               "title": "Progress 进度条"
diff --git a/packages/cell-swipe/components/CellSwipe.vue b/packages/cell-swipe/components/CellSwipe.vue
new file mode 100644
index 000000000..777402261
--- /dev/null
+++ b/packages/cell-swipe/components/CellSwipe.vue
@@ -0,0 +1,142 @@
+<template>
+  <div
+    v-clickoutside:touchstart="swipeMove"
+    @click="swipeMove()"
+    @touchstart="startDrag"
+    @touchmove="onDrag"
+    @touchend="endDrag"
+    class="van-cell-swipe"
+    ref="cell">
+    <div class="van-cell-wrapper">
+      <slot>单元格内容</slot>
+    </div>
+    <div class="van-cell-left">
+      <div ref="left">
+        <slot name="left"></slot>
+      </div>
+    </div>
+    <div class="van-cell-right">
+      <div ref="right">
+        <slot name="right"></slot>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+  import {once} from 'src/utils/dom';
+  import Clickoutside from 'src/utils/clickoutside';
+  
+  export default {
+    name: 'van-cell-swipe',
+    props: {
+      'leftWidth': {type: Number, default: 0},
+      'rightWidth': {type: Number, default: 0}
+    },
+    directives: {Clickoutside},
+    data() {
+      return {
+        start: {x: 0, y: 0}
+      };
+    },
+    computed: {
+      leftDefaultTransform(){
+        return this.translate3d(-this.leftWidth - 1);
+      },
+      rightDefaultTransform(){
+        return this.translate3d(this.rightWidth);
+      }
+    },
+    mounted() {
+      this.wrap = this.$refs.cell.querySelector('.van-cell-wrapper');
+      this.leftElm = this.$refs.left;
+      this.leftWrapElm = this.leftElm.parentNode;
+      this.leftDefaultTransform = this.translate3d(-this.leftWidth - 1);
+      this.leftWrapElm.style.webkitTransform = this.leftDefaultTransform;
+
+      this.rightElm = this.$refs.right;
+      this.rightWrapElm = this.rightElm.parentNode;
+      this.rightDefaultTransform = this.translate3d(this.rightWidth);
+      this.rightWrapElm.style.webkitTransform = this.rightDefaultTransform;
+    },
+    methods: {
+      resetSwipeStatus() {
+        this.swiping = false; // 是否正在拖动
+        this.opened = true; // 记录是否滑动左右 或者 注册
+        this.offsetLeft = 0; // 记录单次拖动的拖动距离
+      },
+      translate3d(offset) {
+        return `translate3d(${offset}px, 0, 0)`;
+      },
+      swipeMove(offset = 0) {
+        this.wrap.style.webkitTransform = this.translate3d(offset);
+        this.rightWrapElm.style.webkitTransform = this.translate3d(this.rightWidth + offset);
+        this.leftWrapElm.style.webkitTransform = this.translate3d(-this.leftWidth + offset);
+        offset && (this.swiping = true);
+      },
+      swipeLeaveTransition(direction) {
+        setTimeout(() => {
+          this.swipeLeave = true;
+          // left
+          if (direction > 0 && -this.offsetLeft > this.rightWidth * 0.4 && this.rightWidth > 0) {
+            this.swipeMove(-this.rightWidth);
+            this.resetSwipeStatus();
+            return;
+            // right
+          } else if (direction < 0 && this.offsetLeft > this.leftWidth * 0.4 && this.leftWidth > 0) {
+            this.swipeMove(this.leftWidth);
+            this.resetSwipeStatus();
+            return;
+          } else {
+            this.swipeMove(0);
+            once(this.wrap, 'webkitTransitionEnd', _ => {
+              this.wrap.style.webkitTransform = '';
+              this.rightWrapElm.style.webkitTransform = this.rightDefaultTransform;
+              this.leftWrapElm.style.webkitTransform = this.leftDefaultTransform;
+              this.swipeLeave = false;
+              this.swiping = false;
+            });
+          }
+        }, 0);
+      },
+      startDrag(evt) {
+        console.log('startDrag')
+        evt = evt.changedTouches ? evt.changedTouches[0] : evt;
+        this.dragging = true;
+        this.start.x = evt.pageX;
+        this.start.y = evt.pageY;
+      },
+      onDrag(evt) {
+        console.log('onDrag')
+        if (this.opened) {
+          !this.swiping && this.swipeMove(0);
+          this.opened = false;
+          return;
+        }
+        if (!this.dragging) return;
+        let swiping;
+        const e = evt.changedTouches ? evt.changedTouches[0] : evt;
+        const offsetTop = e.pageY - this.start.y;
+        const offsetLeft = this.offsetLeft = e.pageX - this.start.x;
+        if ((offsetLeft < 0 && -offsetLeft > this.rightWidth) ||
+          (offsetLeft > 0 && offsetLeft > this.leftWidth) ||
+          (offsetLeft > 0 && !this.leftWidth) ||
+          (offsetLeft < 0 && !this.rightWidth)) {
+          return;
+        }
+        const y = Math.abs(offsetTop);
+        const x = Math.abs(offsetLeft);
+        swiping = !(x < 5 || (x >= 5 && y >= x * 1.73));
+        if (!swiping) return;
+        evt.preventDefault();
+        this.swipeMove(offsetLeft);
+      },
+      endDrag() {
+        console.log('endDrag')
+        if (!this.swiping) return;
+        this.swipeLeaveTransition(this.offsetLeft > 0 ? -1 : 1);
+      }
+    }
+  };
+</script>
+
diff --git a/packages/cell-swipe/index.js b/packages/cell-swipe/index.js
new file mode 100644
index 000000000..bb9559c21
--- /dev/null
+++ b/packages/cell-swipe/index.js
@@ -0,0 +1,2 @@
+import CellSwipe from './components/CellSwipe.vue'
+export default CellSwipe;
diff --git a/packages/vant-css/src/cell-swipe.css b/packages/vant-css/src/cell-swipe.css
new file mode 100644
index 000000000..637e93854
--- /dev/null
+++ b/packages/vant-css/src/cell-swipe.css
@@ -0,0 +1,27 @@
+
+.van-cell-swipe .van-cell-wrapper, .van-cell-swipe .van-cell-left, .van-cell-swipe .van-cell-right {
+    -webkit-transition: -webkit-transform 150ms ease-in-out;
+    transition: -webkit-transform 150ms ease-in-out;
+    transition: transform 150ms ease-in-out;
+    transition: transform 150ms ease-in-out, -webkit-transform 150ms ease-in-out;
+}
+
+.van-cell-swipe{
+    position: relative;
+    min-height: 48px;
+    overflow: hidden;
+}
+.van-cell-right{
+    position: absolute;
+    height: 100%;
+    right: 0;
+    top: 0;
+    transform: translate3d(100%,0,0);
+}
+.van-cell-left {
+    position: absolute;
+    height: 100%;
+    left: 0;
+    top: 0;
+    transform: translate3d(-100%,0,0);
+}
\ No newline at end of file
diff --git a/packages/vant-css/src/index.css b/packages/vant-css/src/index.css
index 85785cd78..d83ee1789 100644
--- a/packages/vant-css/src/index.css
+++ b/packages/vant-css/src/index.css
@@ -4,6 +4,7 @@
 @import './reset.css';
 @import './button.css';
 @import './cell.css';
+@import './cell-swipe.css';
 @import './card.css';
 @import './dialog.css';
 @import './field.css';
diff --git a/src/index.js b/src/index.js
index 9566cdfb8..37c200d8c 100644
--- a/src/index.js
+++ b/src/index.js
@@ -5,6 +5,7 @@ import Radio from '../packages/radio/index.js';
 import Cell from '../packages/cell/index.js';
 import Icon from '../packages/icon/index.js';
 import CellGroup from '../packages/cell-group/index.js';
+import CellSwipe from '../packages/cell-swipe/index.js';
 import Popup from '../packages/popup/index.js';
 import Dialog from '../packages/dialog/index.js';
 import Picker from '../packages/picker/index.js';
@@ -47,6 +48,7 @@ const install = function(Vue) {
   Vue.component(Cell.name, Cell);
   Vue.component(Icon.name, Icon);
   Vue.component(CellGroup.name, CellGroup);
+  Vue.component(CellSwipe.name, CellSwipe);
   Vue.component(Popup.name, Popup);
   Vue.component(Picker.name, Picker);
   Vue.component(RadioGroup.name, RadioGroup);
@@ -89,6 +91,7 @@ module.exports = {
   Cell,
   Icon,
   CellGroup,
+  CellSwipe,
   Popup,
   Dialog,
   Picker,
diff --git a/src/utils/dom.js b/src/utils/dom.js
index ede0951ec..b5c2550a6 100644
--- a/src/utils/dom.js
+++ b/src/utils/dom.js
@@ -55,3 +55,44 @@ export function removeClass(el, cls) {
     el.className = trim(curClass);
   }
 };
+export const once = function(el, event, fn) {
+  var listener = function() {
+    if (fn) {
+      fn.apply(this, arguments);
+    }
+    off(el, event, listener);
+  };
+  on(el, event, listener);
+};
+
+export const on = (function() {
+  if (document.addEventListener) {
+    return function(element, event, handler) {
+      if (element && event && handler) {
+        element.addEventListener(event, handler, false);
+      }
+    };
+  } else {
+    return function(element, event, handler) {
+      if (element && event && handler) {
+        element.attachEvent('on' + event, handler);
+      }
+    };
+  }
+})();
+
+export const off = (function() {
+  if (document.removeEventListener) {
+    return function(element, event, handler) {
+      if (element && event) {
+        element.removeEventListener(event, handler, false);
+      }
+    };
+  } else {
+    return function(element, event, handler) {
+      if (element && event) {
+        element.detachEvent('on' + event, handler);
+      }
+    };
+  }
+})();
diff --git a/test/unit/specs/cell-swipe.spec.js b/test/unit/specs/cell-swipe.spec.js
new file mode 100644
index 000000000..46325f291
--- /dev/null
+++ b/test/unit/specs/cell-swipe.spec.js
@@ -0,0 +1,141 @@
+import CellSwipe from 'packages/cell-swipe';
+import { mount } from 'avoriaz';
+
+describe('CellSwipe', () => {
+  let wrapper;
+  afterEach(() => {
+    wrapper && wrapper.destroy();
+  });
+
+  it('create a CellSwipe', () => {
+    wrapper = mount(CellSwipe, {
+      propsData: {
+        leftWidth: 2,
+        rightWidth: 2
+      }
+    });
+    wrapper.vm.startDrag({
+      pageX: 0,
+      pageY: 0
+    });
+    wrapper.vm.onDrag({
+      preventDefault() {},
+      pageY: 0,
+      pageX: 50
+    });
+    wrapper.vm.offsetLeft = -20;
+    wrapper.vm.rightWidth = 10;
+    wrapper.vm.swipeLeaveTransition(1);
+    wrapper.vm.endDrag();
+    expect(wrapper.hasClass('van-cell-swipe')).to.be.true;
+  });
+});
+
+
+describe('CellSwipe-left', () => {
+  let wrapper;
+  afterEach(() => {
+    wrapper && wrapper.destroy();
+  });
+
+  it('create a CellSwipe left', () => {
+    wrapper = mount(CellSwipe, {
+      propsData: {
+        leftWidth: 2,
+        rightWidth: 2
+      }
+    });
+    wrapper.vm.startDrag({
+      changedTouches: [{
+        pageX: 0,
+        pageY: 0
+      }
+      ]
+    });
+    wrapper.vm.onDrag({
+      preventDefault() {},
+      changedTouches: [{
+        pageX: 0,
+        pageY: -50
+      }
+      ]
+    });
+    wrapper.vm.offsetLeft = 20;
+    wrapper.vm.rightWidth = 10;
+    wrapper.vm.swipeLeaveTransition(-1);
+    wrapper.vm.endDrag();
+    expect(wrapper.hasClass('van-cell-swipe')).to.be.true;
+  });
+});
+
+describe('CellSwipe-0', () => {
+  let wrapper;
+  afterEach(() => {
+    wrapper && wrapper.destroy();
+  });
+
+  it('create a CellSwipe 0', () => {
+    wrapper = mount(CellSwipe, {
+      propsData: {
+        leftWidth: 0,
+        rightWidth: 2
+      }
+    });
+    wrapper.vm.startDrag({
+      pageX: 0,
+      pageY: 0
+    });
+    wrapper.vm.onDrag({
+      preventDefault() {},
+      pageY: 0,
+      pageX: -2
+    });
+    wrapper.vm.opened = true;
+    wrapper.vm.onDrag({
+      preventDefault() {},
+      pageY: 0,
+      pageX: -2
+    });
+    wrapper.vm.opened = false;
+    wrapper.vm.onDrag({
+      preventDefault() {},
+      pageY: 0,
+      pageX: 40
+    });
+    wrapper.vm.swipeLeaveTransition(0);
+    wrapper.vm.endDrag();
+    expect(wrapper.hasClass('van-cell-swipe')).to.be.true;
+  });
+});
+
+
+describe('CellSwipe-0', () => {
+  let wrapper;
+  afterEach(() => {
+    wrapper && wrapper.destroy();
+  });
+
+  it('create a CellSwipe 0', () => {
+    wrapper = mount(CellSwipe, {
+      propsData: {
+        leftWidth: 0,
+        rightWidth: 2
+      }
+    });
+    wrapper.vm.startDrag({
+      pageX: 0,
+      pageY: 0
+    });
+    wrapper.vm.onDrag({
+      preventDefault() {},
+      pageY: 1000,
+      pageX: 40
+    });
+    wrapper.vm.swipeMove();
+    wrapper.vm.swiping = false;
+    wrapper.vm.endDrag();
+    wrapper.vm.swiping = true;
+    wrapper.vm.endDrag();
+    expect(wrapper.hasClass('van-cell-swipe')).to.be.true;
+  });
+});