├── App.vue
├── README.md
├── components
└── cl-cardDel
│ └── cl-cardDel.js
├── main.js
├── manifest.json
├── pages.json
├── pages
├── index
│ └── index.vue
├── qzone
│ └── index.vue
└── tantan
│ ├── card-box.vue
│ └── index.vue
├── static
├── 1.jpg
├── 2.jpg
├── 3.jpg
├── 4.jpg
├── 5.jpg
└── logo.png
└── uni.scss
/App.vue:
--------------------------------------------------------------------------------
1 |
14 |
15 |
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cardDel
2 |
3 | 卡片删除效果(仿探探)
4 |
5 | # 说明
6 |
7 | 插件设计: 插件不仅仅可以实现仿探探的效果,还能通过参数实现卡片不同的动画效果的变化。
8 |
9 | 基本模板里提供了简单的动画效果。
10 |
11 |
12 | ## 使用方式
13 |
14 | **在index.js中**
15 |
16 | ~~~
17 | import clCardDel from "@/components/cl-cardDel/cl-cardDel";
18 | mixins:[clCardDel]
19 | ~~~
20 |
21 | ## OBJECT参数说明
22 |
23 | | 参数 | 类型 | 默认值 | 说明 |
24 | | --- | --- | --- | --- |
25 | | number | Number | 2 | 存在的卡片数量 |
26 | | moveRotate | Object | { x:0,y:0 } | 设置位移图片旋转角度距离 card中心点 - 指向坐标 |
27 | | delMoveD | Number | screenHeight*2 | 删除移动距离 |
28 | | touchMoveD | Number | 100 | card移动距离 card移动距离/touchMoveD = 其他card变化比率 |
29 | | rotate | Number | 0 | 第2张卡片旋转角度 |
30 | | scale | Object | { x:1,y:1 } | 第2张卡片缩放 |
31 | | skew | Object | { x:0,y:0 } | 第2张卡片倾斜 |
32 | | translate | Object | { x:0,y:0 } | 第2张卡片位移 |
33 | | opacity | Number | 1 | 第2张卡片透明度 |
34 |
35 | ## 事件
36 |
37 | | 事件名 | 说明 |
38 | | --- | --- |
39 | | init | 设置初始参数 |
40 | | getData | 获取数据 |
41 | | moveJudge(x,y,ratio) | 触摸中判断 |
42 | | endJudge(x,y) | 触摸结束判断 |
43 | | _back | 执行回退动画 |
44 | | _del | 执行删除动画 |
45 |
46 | ## 如果觉得插件不错,麻烦给个好评
47 |
--------------------------------------------------------------------------------
/components/cl-cardDel/cl-cardDel.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data(){
3 | return{
4 | number:2, //展示卡片数量,同时设置animationData对象
5 | moveRotate:{ x:0,y:0 }, //设置位移图片旋转角度距离 card中心点 - 指向坐标
6 | delMoveD: uni.getSystemInfoSync().screenHeight,//设置删除移动距离
7 | touchMoveD: 100,//设置card移动距离, card移动距离/touchMoveD = 其他card变化比率
8 | rotate:0, //旋转deg 设置第2张卡片transform opacity
9 | scale:{ x:1,y:1 }, //缩放
10 | skew:{ x:0,y:0 }, //倾斜px
11 | translate:{ x:0,y:0 }, //位移px
12 | opacity:1, //透明度,参数范围 0~1
13 | type:false, //是否拥有两套代码
14 |
15 |
16 | moveX:0, //记录移动值
17 | moveY:0, //
18 | oldTouces:{},
19 | oldMove:{},
20 | touchAnimation:null,
21 | animationData:{},
22 | dataList:[],
23 | delTime:150,
24 | cardId:0,
25 | x:0,
26 | y:0,
27 | sysHeight:0,
28 | sysWidth:0,
29 | delFlag:false, //app下禁止快速滑动150ms
30 | }
31 | },
32 | created() {
33 | this.init()
34 | this.sysHeight = uni.getSystemInfoSync().windowHeight
35 | this.sysWidth = uni.getSystemInfoSync().windowWidth
36 | },
37 | async mounted() {
38 |
39 | this.createAnimation()
40 | await this.getData()
41 | },
42 | methods:{
43 | //初始值设置
44 | init(){
45 |
46 | },
47 | //获取数据
48 | getData(){
49 |
50 | },
51 | createAnimation(){
52 | //touch移动动画
53 | this.touchAnimation = uni.createAnimation({
54 | duration:0
55 | });
56 | //其他卡片移动
57 | this.moveAnimation = uni.createAnimation({
58 | duration:0
59 | });
60 | //删除动画
61 | this.delanimation = uni.createAnimation({
62 | duration:this.delTime,
63 |
64 | });
65 | //删除时其他card动画
66 | this.endanimation = uni.createAnimation({
67 | duration:200
68 | });
69 | },
70 | touchStart(e){
71 |
72 | this.oldTouces = e.touches[0]
73 |
74 | },
75 | touchMove(e) {
76 |
77 | if(this.delFlag) return
78 |
79 |
80 | let { oldTouces } = this
81 |
82 |
83 | let newTouces = e.touches[0]
84 | //平移
85 | this.moveX = newTouces.clientX-oldTouces.clientX
86 | this.moveY = newTouces.clientY-oldTouces.clientY
87 | this.dataList[0].moveX = this.moveX
88 | this.dataList[0].moveY = this.moveY
89 |
90 | this.dataList[0].animation = false
91 | //移动图片旋转角度
92 | let angle = this.calcAngleDegrees(this.moveX- this.moveRotate.x,this.moveY- this.moveRotate.y )
93 |
94 | //移动card动画
95 | if(this.type){
96 | //#ifdef APP-PLUS
97 | this.touchAnimation.translateX(this.moveX).translateY(this.moveY).rotate(angle).step();
98 | //#endif
99 | //#ifndef APP-PLUS
100 | this.touchAnimation.rotate(angle).step();
101 | //#endif
102 | }else{
103 | this.touchAnimation.rotate(angle).step();
104 | }
105 |
106 |
107 |
108 |
109 |
110 | this.animationData[0] = this.touchAnimation.export()
111 |
112 | //其他card动画
113 | let d = this.moveX*this.moveX + this.moveY*this.moveY
114 | let ratio = Math.sqrt(d) / this.touchMoveD
115 | ratio = ratio > 1 ? 1 : ratio
116 |
117 | for (var i = 1; i < this.number; i++) {
118 |
119 | if(this.rotate!=0) this.moveAnimation.rotate( this.rotate*(i-ratio) )
120 | if(this.opacity!=1) this.moveAnimation.opacity( 1-(1-this.opacity)*(i-ratio) )
121 | if(this.scale.x!=1) this.moveAnimation.scaleX( 1-(1-this.scale.x)*(i-ratio) )
122 | if(this.scale.y!=1) this.moveAnimation.scaleY( 1-(1-this.scale.y)*(i-ratio) )
123 | if(this.skew.x!=0) this.moveAnimation.skewX( this.skew.x*(i-ratio) )
124 | if(this.skew.y!=0) this.moveAnimation.skewY( this.skew.y*(i-ratio) )
125 | if(this.translate.x!=0) this.moveAnimation.translateX( this.translate.x*(i-ratio) )
126 | if(this.translate.y!=0) this.moveAnimation.translateY( this.translate.y*(i-ratio) )
127 |
128 | this.moveAnimation.step()
129 | this.animationData[i] = this.moveAnimation.export()
130 | }
131 | //触摸中视图变化
132 | this.moveJudge(this.moveX,this.moveY,ratio)
133 | },
134 | touchend(e){
135 |
136 | this.endJudge(this.moveX,this.moveY)
137 |
138 | },
139 | //触摸中判断
140 | moveJudge(x,y,ratio){
141 |
142 | },
143 | //触摸结束判断
144 | endJudge(x,y){
145 | if(x!=0||y!=0){
146 | this._del()
147 | }
148 | },
149 | //返回card
150 | _back(){
151 |
152 | let { oldMove } = this
153 | //移动图片旋转角度
154 | let angle = this.calcAngleDegrees(this.moveX- this.moveRotate.x,this.moveY- this.moveRotate.y )
155 | //移动card动画
156 |
157 | if(this.type){
158 | //#ifdef APP-PLUS
159 | this.delanimation.translateX(-this.moveX/3).translateY(-this.moveY/3).rotate(0).step();
160 | //#endif
161 |
162 | }else{
163 |
164 | }
165 |
166 |
167 | this.moveX = 0
168 | this.moveY = 0
169 | this.dataList[0].moveX = 0
170 | this.dataList[0].moveY = 0
171 | this.dataList[0].animation = true
172 | this.delanimation.translateX(this.moveX).translateY(this.moveY).rotate(0).step();
173 | this.animationData[0] = this.delanimation.export()
174 | setTimeout(() => {
175 | //清除动画
176 | this.animationData[0] = this.delanimation.export()
177 | for (var i = 1; i < this.number; i++) {
178 | this.animationData[i] = this.moveAnimation.export()
179 | }
180 | this.moveX = 0
181 | this.moveY = 0
182 | }, this.delTime)
183 |
184 | //其他card动画
185 | let ratio = 0
186 |
187 | for (var i = 1; i < this.number; i++) {
188 |
189 | if(this.rotate!=0) this.endanimation.rotate( this.rotate*(i-ratio) )
190 | if(this.opacity!=1) this.endanimation.opacity( 1-(1-this.opacity)*(i-ratio) )
191 | if(this.scale.x!=1) this.endanimation.scaleX( 1-(1-this.scale.x)*(i-ratio) )
192 | if(this.scale.y!=1) this.endanimation.scaleY( 1-(1-this.scale.y)*(i-ratio) )
193 | if(this.skew.x!=0) this.endanimation.skewX( this.skew.x*(i-ratio) )
194 | if(this.skew.y!=0) this.endanimation.skewY( this.skew.y*(i-ratio) )
195 | if(this.translate.x!=0) this.endanimation.translateX( this.translate.x*(i-ratio) )
196 | if(this.translate.y!=0) this.endanimation.translateY( this.translate.y*(i-ratio) )
197 |
198 | this.endanimation.step()
199 | this.animationData[i] = this.endanimation.export()
200 | }
201 | },
202 | //删除card
203 | _del(){
204 | if(this.type) {
205 | //#ifdef APP-PLUS
206 | this.delFlag = true
207 | //#endif
208 | }
209 |
210 |
211 | //移动card动画
212 | let d = this.moveX*this.moveX + this.moveY*this.moveY
213 | let y = this.moveY*this.delMoveD/Math.sqrt(d)
214 | let x = this.moveX*this.delMoveD/Math.sqrt(d)
215 | this.delanimation.translateX(x).translateY(y).step();
216 | this.animationData[0] = this.delanimation.export()
217 | setTimeout(() => {
218 |
219 | //清除动画
220 | this.animationData[0] = this.delanimation.export()
221 | for (var i = 1; i < this.number; i++) {
222 | this.animationData[i] = this.moveAnimation.export()
223 | }
224 |
225 | this.delCard(this.moveX,this.moveY)
226 | this.moveX = 0
227 | this.moveY = 0
228 | this.dataList[0].moveX = 0
229 | this.dataList[0].moveY = 0
230 | this.dataList.splice(0,1)
231 | if(this.dataList.length<=this.number) this.getData()
232 | if(this.type) {
233 | //#ifdef APP-PLUS
234 | this.delFlag = false
235 | //#endif
236 | }
237 | }, this.delTime)
238 |
239 | //其他card动画
240 | let ratio = 1
241 |
242 | for (var i = 1; i < this.number; i++) {
243 |
244 | if(this.rotate!=0) this.endanimation.rotate( this.rotate*(i-ratio) )
245 | if(this.opacity!=1) this.endanimation.opacity( 1-(1-this.opacity)*(i-ratio) )
246 | if(this.scale.x!=1) this.endanimation.scaleX( 1-(1-this.scale.x)*(i-ratio) )
247 | if(this.scale.y!=1) this.endanimation.scaleY( 1-(1-this.scale.y)*(i-ratio) )
248 | if(this.skew.x!=0) this.endanimation.skewX( this.skew.x*(i-ratio) )
249 | if(this.skew.y!=0) this.endanimation.skewY( this.skew.y*(i-ratio) )
250 | if(this.translate.x!=0) this.endanimation.translateX( this.translate.x*(i-ratio) )
251 | if(this.translate.y!=0) this.endanimation.translateY( this.translate.y*(i-ratio) )
252 |
253 | this.endanimation.step()
254 | this.animationData[i] = this.endanimation.export()
255 | }
256 | },
257 | delCard(){
258 | console.log(this.dataList[0])
259 | },
260 | calcAngleDegrees(x, y) {
261 | return Math.atan2(y, x) * 180 / Math.PI + 90;
262 | }
263 | },
264 | watch:{
265 |
266 |
267 |
268 | },
269 | watch:{
270 | number:{
271 | immediate:true,
272 | handler(newVal,oldVal){
273 | for (var i = 0; i < newVal; i++) {
274 | let a = {}
275 | a[i] = {}
276 | this.animationData = {...this.animationData,...a}
277 | }
278 | }
279 | },
280 | dataList:{
281 | handler(newVal,oldVal){
282 | for (let item of newVal) {
283 | if(!item._id){
284 | item._id = this.cardId++
285 | item.moveX = 0
286 | item.moveY = 0
287 | item.animation = false
288 | }
289 | }
290 |
291 | }
292 | }
293 | }
294 | }
295 |
296 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App'
3 |
4 | Vue.config.productionTip = false
5 |
6 | App.mpType = 'app'
7 |
8 | const app = new Vue({
9 | ...App
10 | })
11 | app.$mount()
12 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "cardDel",
3 | "appid" : "",
4 | "description" : "",
5 | "versionName" : "1.0.0",
6 | "versionCode" : "100",
7 | "transformPx" : false,
8 | /* 5+App特有相关 */
9 | "app-plus" : {
10 | "usingComponents" : true,
11 | "nvueCompiler" : "uni-app",
12 | "splashscreen" : {
13 | "alwaysShowBeforeRender" : true,
14 | "waiting" : true,
15 | "autoclose" : true,
16 | "delay" : 0
17 | },
18 | /* 模块配置 */
19 | "modules" : {},
20 | /* 应用发布信息 */
21 | "distribute" : {
22 | /* android打包配置 */
23 | "android" : {
24 | "permissions" : [
25 | "",
26 | "",
27 | "",
28 | "",
29 | "",
30 | "",
31 | "",
32 | "",
33 | "",
34 | "",
35 | "",
36 | "",
37 | "",
38 | "",
39 | "",
40 | "",
41 | "",
42 | "",
43 | "",
44 | "",
45 | "",
46 | ""
47 | ]
48 | },
49 | /* ios打包配置 */
50 | "ios" : {},
51 | /* SDK配置 */
52 | "sdkConfigs" : {}
53 | }
54 | },
55 | /* 快应用特有相关 */
56 | "quickapp" : {},
57 | /* 小程序特有相关 */
58 | "mp-weixin" : {
59 | "appid" : "",
60 | "setting" : {
61 | "urlCheck" : false
62 | },
63 | "usingComponents" : true
64 | },
65 | "mp-alipay" : {
66 | "usingComponents" : true
67 | },
68 | "mp-baidu" : {
69 | "usingComponents" : true
70 | },
71 | "mp-toutiao" : {
72 | "usingComponents" : true
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/pages.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
3 | {
4 | "path": "pages/index/index",
5 | "style": {
6 | "navigationBarTitleText": "基本模板"
7 | }
8 | },
9 | {
10 | "path": "pages/qzone/index",
11 | "style": {
12 | "navigationBarTitleText": "qq空间"
13 | }
14 | },
15 | {
16 | "path": "pages/tantan/index",
17 | "style": {
18 | "navigationBarTitleText": "探探"
19 |
20 | }
21 | }
22 | ],
23 | "globalStyle": {
24 | "navigationBarTextStyle": "black",
25 | "navigationBarTitleText": "uni-app",
26 | "navigationBarBackgroundColor": "#F8F8F8",
27 | "backgroundColor": "#F8F8F8"
28 | },
29 | "tabBar": {
30 | "color": "#333333",
31 | "backgroundColor": "#F8F8F8",
32 | "selectedColor": "#00B26A",
33 | "list": [
34 | {
35 | "pagePath": "pages/index/index",
36 | "text": "基本模板"
37 | },
38 | {
39 | "pagePath": "pages/qzone/index",
40 | "text": "qq空间"
41 | },
42 | {
43 | "pagePath": "pages/tantan/index",
44 | "text": "探探"
45 | }
46 | ]
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/pages/index/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
21 |
26 | {{item.id}}
27 |
28 |
29 |
30 |
31 |
32 |
33 |
76 |
77 |
115 |
--------------------------------------------------------------------------------
/pages/qzone/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
21 |
26 |
27 | {{item.name}}
28 |
29 | 查看
30 |
31 | x
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
91 |
92 |
163 |
--------------------------------------------------------------------------------
/pages/tantan/card-box.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{number}}
7 | 擦肩而过1次
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | {{name}}
27 |
28 |
29 | {{old}}
30 | {{constellation}}
31 |
32 | {{address}}
33 |
34 |
35 |
36 |
37 |
133 |
134 |
323 |
--------------------------------------------------------------------------------
/pages/tantan/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
49 |
50 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
65 |
66 |
67 |
68 |
173 |
174 |
175 |
247 |
--------------------------------------------------------------------------------
/static/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/15157757001/cardDel/a54c5aa01e87f150e82cf2aab6ba6563858db3a9/static/1.jpg
--------------------------------------------------------------------------------
/static/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/15157757001/cardDel/a54c5aa01e87f150e82cf2aab6ba6563858db3a9/static/2.jpg
--------------------------------------------------------------------------------
/static/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/15157757001/cardDel/a54c5aa01e87f150e82cf2aab6ba6563858db3a9/static/3.jpg
--------------------------------------------------------------------------------
/static/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/15157757001/cardDel/a54c5aa01e87f150e82cf2aab6ba6563858db3a9/static/4.jpg
--------------------------------------------------------------------------------
/static/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/15157757001/cardDel/a54c5aa01e87f150e82cf2aab6ba6563858db3a9/static/5.jpg
--------------------------------------------------------------------------------
/static/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/15157757001/cardDel/a54c5aa01e87f150e82cf2aab6ba6563858db3a9/static/logo.png
--------------------------------------------------------------------------------
/uni.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * 这里是uni-app内置的常用样式变量
3 | *
4 | * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
5 | * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
6 | *
7 | */
8 |
9 | /**
10 | * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
11 | *
12 | * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
13 | */
14 |
15 | /* 颜色变量 */
16 |
17 | /* 行为相关颜色 */
18 | $uni-color-primary: #007aff;
19 | $uni-color-success: #4cd964;
20 | $uni-color-warning: #f0ad4e;
21 | $uni-color-error: #dd524d;
22 |
23 | /* 文字基本颜色 */
24 | $uni-text-color:#333;//基本色
25 | $uni-text-color-inverse:#fff;//反色
26 | $uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
27 | $uni-text-color-placeholder: #808080;
28 | $uni-text-color-disable:#c0c0c0;
29 |
30 | /* 背景颜色 */
31 | $uni-bg-color:#ffffff;
32 | $uni-bg-color-grey:#f8f8f8;
33 | $uni-bg-color-hover:#f1f1f1;//点击状态颜色
34 | $uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
35 |
36 | /* 边框颜色 */
37 | $uni-border-color:#c8c7cc;
38 |
39 | /* 尺寸变量 */
40 |
41 | /* 文字尺寸 */
42 | $uni-font-size-sm:24upx;
43 | $uni-font-size-base:28upx;
44 | $uni-font-size-lg:32upx;
45 |
46 | /* 图片尺寸 */
47 | $uni-img-size-sm:40upx;
48 | $uni-img-size-base:52upx;
49 | $uni-img-size-lg:80upx;
50 |
51 | /* Border Radius */
52 | $uni-border-radius-sm: 4upx;
53 | $uni-border-radius-base: 6upx;
54 | $uni-border-radius-lg: 12upx;
55 | $uni-border-radius-circle: 50%;
56 |
57 | /* 水平间距 */
58 | $uni-spacing-row-sm: 10px;
59 | $uni-spacing-row-base: 20upx;
60 | $uni-spacing-row-lg: 30upx;
61 |
62 | /* 垂直间距 */
63 | $uni-spacing-col-sm: 8upx;
64 | $uni-spacing-col-base: 16upx;
65 | $uni-spacing-col-lg: 24upx;
66 |
67 | /* 透明度 */
68 | $uni-opacity-disabled: 0.3; // 组件禁用态的透明度
69 |
70 | /* 文章场景相关 */
71 | $uni-color-title: #2C405A; // 文章标题颜色
72 | $uni-font-size-title:40upx;
73 | $uni-color-subtitle: #555555; // 二级标题颜色
74 | $uni-font-size-subtitle:36upx;
75 | $uni-color-paragraph: #3F536E; // 文章段落颜色
76 | $uni-font-size-paragraph:30upx;
--------------------------------------------------------------------------------