手把手教你系列- 卡片拖拽手势删除效果
背景介绍
手势效果是终端开发的常见需求,这篇文章手把手教你如何快速实现一个手势功能。最终效果
项目初始化
新建一个项目 demo-gesture
cml init project
进入项目
cd demo-gesture
设计数据结构
我们要做一个列表,所以先设计一个数据结构如下:
data = {
list: [
{
// 用作样式名称
className: 'inner-first',
// 用作元素位置偏移
transform: {
y: 0,
x: 0
} ,
}
]
}
写进/src/pages/index/index.cml
文件里面逻辑层JS代码里面
<script>
class Index {
data = {
list: [
{
className: 'inner-first',
transform: {
y: 0,
x: 0
}
},
{
className: 'inner-second',
transform: {
y: 0,
x: 0
}
},
{
className: 'inner-third',
transform: {
y: 0,
x: 0
}
},
{
className: 'inner-fouth',
transform: {
y: 0,
x: 0
}
}
],
}
methods = {
}
}
export default new Index();
</script>
书写CML使用数据
我们查看CML文档使用列表渲染,
写进/src/pages/index/index.cml
文件里面CML代码
<template>
<view class="wrapper">
<view c-for="{{list}}" c-for-index="idx" c-for-item="itemName" data-index="{{idx}}" class="box {{itemName.className}}" style="transform: translate({{itemName.transform.x}}, 0);" >
<text class="txt">{{idx}}</text>
<view class="remove-btn" data-index="{{idx}}">
<text class="rm">删</text>
</view>
</view>
</view>
</template>
书写CMSS
查看CMSS文档,CMSS针对多端情况只能使用 flex 给页面布局,
.wrapper{
flex-direction: col;
justify-content: space-around;
height: 1200cpx;
}
.inner-first{
background: red;
}
.inner-second{
background: yellow;
}
.inner-third{
background: blue;
}
.inner-fouth{
background: green;
}
.box{
height: 200cpx;
}
.txt{
text-align: center;
line-height: 50cpx;
height: 50cpx;
}
.remove-btn{
height: 50cpx;
width: 50cpx;
border: 1px solid hotpink;
font-size: 10cpx;
border-radius: 50cpx;
transform: translate(780cpx, 0)
}
.rm{
text-align: center;
line-height: 50cpx;
color: hotpink;
}
目前三端效果展现如下
添加手势
我们查看事件绑定文档
给box元素添加事件绑定:
c-bind:touchstart="eventhandler"
c-bind:touchmove="eventhandler"
c-bind:touchend="eventhandler"
添加事件回调函数
methods = {
eventHandler(event){
// 获取当前手指位置
let myPreX = event.changedTouches[0].pageX;
// 获取当前手指所触摸的Item元素
let index = event.currentTarget.dataset.index;
// 获取当前手指所触摸的Item元素的偏移值
let transform = this.list[index].transform;
if(index >= this.list.length) {
return;
}
console.log(index);
// 手指触摸开始时将上一个X方向偏移设为null
if(event.type == 'touchstart'){
preX = null;
}else if( event.type == 'touchmove'){
if(preX !== null){
let x = parseInt(transform.x) + myPreX - preX ;
//x < 0 当手指往右滑动时不允许移动滑块
// > 100 当手指往左滑动超过100时不允许滑动滑块
if(Math.abs(x) < 100 && x < 0){
//数据驱动视图更改
transform.x = x + 'cpx';
}
}
// 保存最后的位置
preX = myPreX;
}else if(event.type == 'touchend'){
if(Math.abs(parseInt(transform.x)) < 90){
transform.x = 0;
}
}
}
}
添加删除按钮事件回调函数
给remove-btn元素添加事件绑定:
c-bind:click="onRemove"
methods = {
onRemove(e){
let index = e.currentTarget.dataset.index;
this.list.splice(index, 1);
}
}
/src/pages/index/index.cml
最终全部代码如下:
<template>
<view class="wrapper">
<view c-for="{{list}}" c-for-index="idx" c-for-item="itemName" data-index="{{idx}}" class="box {{itemName.className}}" style="transform: translate({{itemName.transform.x}}, 0);"
c-bind:touchstart="eventHandler"
c-bind:touchmove="eventHandler"
c-bind:touchend="eventHandler"
>
<text class="txt">{{idx}}</text>
<view class="remove-btn" c-bind:click="onRemove" data-index="{{idx}}" >
<text class="rm" >删</text>
</view>
</view>
</view>
</template>
<script>
let preX = null;
class Index {
data = {
list: [
{
className: 'inner-first',
transform: {
y: 0,
x: 0
}
},
{
className: 'inner-second',
transform: {
y: 0,
x: 0
}
},
{
className: 'inner-third',
transform: {
y: 0,
x: 0
}
},
{
className: 'inner-fouth',
transform: {
y: 0,
x: 0
}
}
],
}
methods = {
eventHandler(event){
// 获取当前手指位置
let myPreX = event.changedTouches[0].pageX;
// 获取当前手指所触摸的Item元素
let index = event.currentTarget.dataset.index;
// 获取当前手指所触摸的Item元素的偏移值
if(index >= this.list.length) {
return;
}
console.log(index);
let transform = this.list[index].transform;
// 手指触摸开始时将上一个X方向偏移设为null
if(event.type == 'touchstart'){
preX = null;
}else if( event.type == 'touchmove'){
if(preX !== null){
let x = parseInt(transform.x) + myPreX - preX ;
//x < 0 当手指往右滑动时不允许移动滑块
// > 100 当手指往左滑动超过100时不允许滑动滑块
if(Math.abs(x) < 100 && x < 0){
//数据驱动视图更改
transform.x = x + 'cpx';
}
}
// 保存最后的位置
preX = myPreX;
}else if(event.type == 'touchend'){
if(Math.abs(parseInt(transform.x)) < 90){
transform.x = 0;
}
}
},
onRemove(e){
let index = e.currentTarget.dataset.index;
this.list.splice(index, 1);
}
}
}
export default new Index();
</script>
<style scoped>
.wrapper{
flex-direction: col;
justify-content: space-around;
height: 1200cpx;
}
.inner-first{
background: red;
}
.inner-second{
background: yellow;
}
.inner-third{
background: blue;
}
.inner-fouth{
background: green;
}
.box{
height: 200cpx;
}
.txt{
text-align: center;
line-height: 50cpx;
height: 50cpx;
}
.remove-btn{
height: 50cpx;
width: 50cpx;
border: 1px solid hotpink;
font-size: 10cpx;
border-radius: 50cpx;
transform: translate(780cpx, 0)
}
.rm{
text-align: center;
line-height: 50cpx;
color: hotpink;
}
</style>
<script cml-type="json">
{
}
</script>
最终不到150行代码实现三端拖拽效果: