Android仿探探卡片拖拽,[转]仿探探拖拽卡片效果Vue3实现

f164c1ca9afbc632d36d31dab8b52f11.png

原文来自:juejin.cn/post/6908404553431908365,作者 羊村长

基于 vite + vue3 + composition api 做的卡片拖拽,代码相对简洁

大帅刚做了一版类似探探的飞卡效果组件,十分炫酷!

只可惜不是vue3版本,下面带大家看看如何正确搬运到vue3中。

绝对抄袭,如有不同,纯属巧合😁

96ede958723c89aca603d92ffea8f401.gif

视频版

飞卡原理

核心点有三:卡片堆叠布局、拖动卡片和飞卡

布局主要利用z-index和absolute定位;

拖动主要利用几个touch事件:touchstart,touchmove,touchcancel,touchend;

飞卡主要利用勾股定理😁

详情参见原文,不再赘述。

组件化

这里抽取组件是核心,先看看FlyCard组件template中的结构:

@touchstart="touchStart"

@touchmove="touchMove"

@touchcancel="touchCancel"

@touchend="touchCancel">

复制代码

注意这里省略了所有样式,替换所有view为div,每张卡片预留了具名插槽方便外界传入内容进来。

只有卡片1需要监听事件,最后预留一张空卡等待“上位”😁

那么,使用FlyCard组件时,需要使用v-slot指令分发内容,来看看demo-tantan.vue

复制代码

这里的分发内容进去,完整写法应该是

注意这里使用vite,图片src是动态设置的,需要做特殊处理,否则不能正常显示:

import img1 from "../assets/1.jpg";

复制代码cards: [{img: img1}]

复制代码

逻辑代码拆分

目前FlyCard接近400行,不太容易维护了,我们可以用Composition API拆分它们。

观察一下不难发现,拖动逻辑只有卡片1需要,所以这一部分的数据和逻辑控制是独立的,完全可拆分出来。

e05c5940af74377209f48fe325ad7f9c.png

bd09badac9e3615f0a0df611109acff9.png

因此创建use/touch.js,抽取这部分逻辑代码,思路是:

抽取useTouch函数,接收卡片属性和回调函数等

响应数据就是上面的left,top这些

控制它们的逻辑是touchStart这些

组织在一起并导出供外界使用,日后还能复用在其他项目

抽取useTouch,接口如下:

function useTouch(props, {

onDragStart,

onDragMove,

onDragStop,

onThrowStart,

onThrowDone,

onThrowFail,

}) {}

复制代码

传入卡片属性后面计算逻辑要用到,还要留出事件回调,这样外界可以做一些额外事情:

响应式数据创建

const cardOneState = reactive({

left: 0,

top: 0,

startLeft: 0,

startTop: 0,

isDrag: false,

isThrow: false,

needBack: false,

isAnimating: false,

})

复制代码

控制逻辑:替换大量this.xxx,类似下面这样:

function touchStart(e) {

if (cardOneState.isAnimating) return;

cardOneState.isDrag = true;

cardOneState.needBack = false;

cardOneState.isThrow = false;

// ......

}

复制代码

这里有一个例外是getDistance方法,这是一个工具方法,外界不需要它,完全可以放到utils中去。

下面是飞卡逻辑和卡片回弹逻辑,它们需要处理另外几张卡的状态

const otherCardsState = reactive({

left2: 0,

top2: 0,

width2: 0,

height2: 0,

// ...

});

function resetAllCardDown() {/*...*/}

function resetAllCard() {/*...*/}

function makeCardThrow() {/*...*/}

function makeCardBack() {/*...*/}

复制代码

生命周期钩子处理

import { onMounted } from "vue";

function useTouch() {

// ...

onMounted(() => {

resetAllCard()

})

}

复制代码

最后导出接口:

return {

...toRefs(cardOneState),

...toRefs(otherCardsState),

touchStart,

touchMove,

touchCancel,

};

复制代码

重构完成,useTouch()长这样

a246c56c24da40d119bb56fc34b415ba.png

d3b805df60d836e9f86e1b5fbd6cd198.png

组件内使用

下面在FlyCard里面使用useTouch,额外暴露一下emits选项,组件输入输出更明确。

import useTouch from "../use/touch";

export default {

props: {},

emits: [

"onDragStart",

"onDragMove",

"onDragStop",

"onThrowFail",

"onThrowStart",

"onThrowDone",

],

setup(props, { emit }) {

const touchState = useTouch(props, {

onDragStart: () => emit("onDragStart"),

onDragMove: (obj) => emit("onDragMove", obj),

onDragStop: (obj) => emit("onDragStop", obj),

onThrowFail: () => emit("onThrowFail"),

onThrowStart: () => emit("onThrowStart"),

onThrowDone: () => emit("onThrowDone"),

});

return { ...touchState };

},

};

复制代码

可以看到FlyCard组件简洁多了,组件由接近400行缩减至200行

敲黑板

重构完成了,这是我们使用vue3 composition api的一次小实践,好处显而易见:

我们的组件更简洁、易维护了

我们的业务逻辑可复用了

我们的代码完全消除了this,更有利于支持ts

重构过程我们加强了对业务的理解,这些代码都不是我写的,但是我很快就搞清楚了组件真正需要的接口有哪些,哪些方法只是touch内部需要并不需要暴露出去的。

思考

大家观察其他卡片的操作代码,不难发现,它们很有规律,应该很容易进一步抽象成更加通用、可复用的逻辑,比如我能不能动态指定卡片的数量,而不是像现在这样写死,这样大大限制了它的通用性。这个留给大家实现,可以给我的项目提pr。

2570ec9e283938471c2a3add0b23c494.png

代码仓库

视频版

作者:杨村长

链接:juejin.cn/post/6908404553431908365

来源:掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
无论你是一个程序猿还是一个程序媛,每天干的事除了coding还是coding,代码不能解决的问题(什么问题自己心里还没点abcd数嘛),探探能帮你解决。最近网上特流行一款交友软件叫探探(据说是yp软件)。作为探探曾经的一名从来只浏览图片但是没有yue过的资深玩家同时又是一位热爱前端的妹子,我决定要仿一下这个app。既然是寄几开发,那还不是寄几说了算,毫无疑问整款APP的主题风格被我改成我最爱的终极少女粉了hhh,下面让我们一起来感受下探探的魅力吧~项目整体效果项目部分功能点解析主页图片左滑右滑对应按钮变化首先我们来聊一下最让我头痛的地方,就是主页面的左右滑动事件并且对应按钮会相应变化,即我左滑一下图片下面的灰色按钮会有相应的动画效果,右滑则对应着图片下面的红色按钮。对于一个刚入小程序坑的妹子来说,没有大神指点不知道要在这里面的逻辑坑还要绕多久才能绕出来。得一高人指点,我才完美滴实现了这个功能。这里写了三个大的盒子放着图片和文字信息,再将他们放到swiper-item里面,用swiper组件实现整个盒子的左右滑动                                          K             ♂21             金牛座             文化/教育                哦盒子下面不是按钮,我是放了两张图片。             先给他们写个滑动的时候触发的动画效果.active {    animation: active 1s ease;//定义一个叫做active的动画} @keyframes active {//补充active动作脚本     0% {        transform: scale(0.8);     }     50% {        transform: scale(1.2);     }     100% {        transform: scale(1.0);     } }在page的data里面定义三个变量,将left,right变量绑定到对应图片中data: {        left: false ,       right: false,        activeIndex: 0 },在swiper绑定事件中具体判断左右滑动事件changeswiper: function(e) {         var index = e.detail.current;//当前所在页面的 index     if(index > this.data.activeIndex) {//左滑事件判断       this.setData({         left: true//若为左滑,left值为true,触发图片动画效果       })     } else if(index  {//每滑动一次,数据发生变化       this.setData({         activeIndex: index,         left:false,         right:false       })     }, 1000);   },从本地上传图片这个呀查一查小程序开发文档就好了,先在要上传图片的地方的src绑定个数据变量放入图片默认地址,就是上传图片之前的添加图片data: {     imgUrl: '../../images/addImg.png'   },通过绑定tap事件将上传的图片地址替换进去uploadImg: function(e) { var that = this; wx.chooseImage({   count: 1, //上传图片数量   sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有   sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有   success: function (res) {// 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片       var tempFilePaths = res.tempFilePaths;       that.setData({           imgUrl: tempFilePaths     })       wx.showToast({//显示上传成功           title: '上传成功',           icon: 'success',           duration: 2000     })   } }),配对成功列表据通过easy-mock获取后台数据block wx:for渲染一个包含多节点的结构块                                                                                                                         {{item.nickname}}                     {{item.message}}                                            获取后台数据wx.request({       url: 'https://www.easy-mock.com/mock/5a23dbf382614c0dc1bebf04/getFriendsList/getFriendsList',       success: (res) => {         // console.log(response);         this.setData({           friendsList: res.data.data.friendsList         })       }     })其它差不多就是切页面了,个人原因用不太习惯weui的官方样式,每个页面都是我自己呕心沥血码出来的,所以大家不喜轻点喷哈,还在努力学习当中~~~项目开发用到的一些工具微信开发者工具、VScode、GithubIconfont阿里巴巴矢量图标库:各种图片logo应有尽有,前端开发必备esay-mock:模拟数据请求,实现无后端编程W3Cschool微信小程序开发教程手册文档:开发小程序要多看看哦小结emmmm目前项目功能还是很简单呀,还有很多功能后面慢慢实现吧~比如利用将上传的图片放到storage中,页面刷新之后图片依然在,slider滑动到某一处在页面上保存当前值,模拟配对成功后弹出提醒页面等等......也希望遇到热爱学习的小伙伴一起交流学习,一起在前端坑里越陷越深hhh项目地址:https://github.com/beautifulg... 求鼓励~求star呀~我的邮箱:804316947@qq.com 这里可以找到我哦作者:略略略

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值