Taro UI框架開(kāi)發(fā)小程序?qū)崿F(xiàn)左滑喜歡右滑不喜歡效果的示例代碼
Taro 就是可以用 React 語(yǔ)法寫(xiě)小程序的框架,擁有多端轉(zhuǎn)換能力,一套代碼可編譯為微信小程序、百度小程序、支付寶小程序、H5、RN等
摘要:
年后入職了一家新公司,與前同事交接完之后,發(fā)現(xiàn)公司有一個(gè)四端的項(xiàng)目(iOS,Android,H5,小程序),iOS和安卓都實(shí)現(xiàn)了左滑右滑的效果,而h5和小程序端沒(méi)實(shí)現(xiàn),詢問(wèn)得知前同事因網(wǎng)上沒(méi)找到對(duì)應(yīng)的插件,相關(guān)博客也特別少,所以沒(méi)做就擱置下來(lái)了。
趁這段時(shí)間相對(duì)來(lái)說(shuō)比較富裕,于是乎在網(wǎng)上也搜索了一下,發(fā)現(xiàn)確實(shí)很少,但是有人提到可以用小程序可拖動(dòng)組件movable-view來(lái)實(shí)現(xiàn),自己嘗試來(lái)一下發(fā)現(xiàn)可行,于是來(lái)寫(xiě)這篇博客記錄一下,希望能幫助到后面需要用到這個(gè)功能的人!
先上效果圖:

主要技術(shù):Taro+Taro UI+React(如果你是小程序原生或者uniapp+vue寫(xiě)法都差不多,可以通用)
可拖動(dòng)組件文檔地址:
Taro:https://taro-docs.jd.com/taro/docs/components/viewContainer/movable-view.html
微信小程序:https://developers.weixin.qq.com/miniprogram/dev/component/movable-view.html
思路:
一,我們首先把movable-area和movable-view標(biāo)簽寫(xiě)出來(lái);
<movable-area> <movable-view> ...... </movable-view> </movable-area>
二,我們可以看到文檔里面有一個(gè)onChange方法,即拖動(dòng)過(guò)程中觸發(fā)的事件;
<movable-area>
<movable-view onChange ={this. onChange.bind(this)}>
......
</movable-view>
</movable-area>
// 觸發(fā)方法,打印參數(shù)
onChange(e) {
console.log('參數(shù)',e);
}
我們可以看到打印出了,拖動(dòng)的位置和產(chǎn)生移動(dòng)的原因等;
三,我們接著加入開(kāi)始o(jì)nTouchstart,移動(dòng)onTouchmove,結(jié)束onTouchcancel,onTouchend三個(gè)事件方法;
<MovableView
key={item.id}
onTouchcancel={this.onCancel}
onTouchend={this.onCancel}
onTouchstart={this.onTouchStart}
onTouchmove={this.onTouchMove}
x={this.state.x} // 橫坐標(biāo)位置
y={this.state.y} // 縱坐標(biāo)位置
direction='all' // 移動(dòng)方向都可以
outOfBounds // 可超過(guò)可移動(dòng)區(qū)域
className='shop-imgbox'
>
<--中間加入圖片之類的滑動(dòng)內(nèi)容-->
</MovableView>
初始數(shù)據(jù)如下:
state = {
x: '16',
y: '16',
like: false,
unlike: false,
shopList: [
{
img: 'https://edgefix-image.edgecom.top/ABD846F6672997A7F76CD38E8A57F954.jpg',
},
{
img: 'https://edgefix-image.edgecom.top/F6E5801C304CC76DA63C02C9FB38B8F4.jpg',
},
{
img: 'https://edgefix-image.edgecom.top/D518952AD1DD61B2D32556E20CC527C4.jpg',
},
{
img: 'https://edgefix-image.edgecom.top/1D187E28B349679908A44BBE81F3D3CA.jpg',
},
{
img: 'https://edgefix-image.edgecom.top/1129A411AC9CF5F81187CBED181B6F57.jpg',
}
]
}
三個(gè)方法我們可以取到移動(dòng)后改變的位置,來(lái)改變喜歡與不喜歡的狀態(tài)css,以及實(shí)現(xiàn)卡片滑動(dòng)的效果:
1.觸摸觸發(fā)的時(shí)候,我們獲取到剛剛開(kāi)始觸摸卡片的x,y的位置坐標(biāo);
2.在觸摸滑動(dòng)時(shí),我們通過(guò)滑動(dòng)后的位置-滑動(dòng)前的位置,來(lái)判斷距離多少來(lái)改變喜歡和不喜歡的值;
3.當(dāng)手離開(kāi)時(shí),觸發(fā)取消事件,我們需要把狀態(tài)數(shù)據(jù)改為原始值,即回到最初的狀態(tài);
// 觸摸觸發(fā)
onTouchStart(e) {
console.log('222',e.touches[0].pageX);
this.setState({
x: e.touches[0].pageX,
y: e.touches[0].pageY,
});
}
// 觸摸移動(dòng)
onTouchMove(e) {
console.log('333',e.touches[0].pageX);
let dx = e.touches[0].pageX - this.state.x;
if (dx > 50) {
this.setState({
like: true,
unlike: false,
});
} else if (dx < -50) {
this.setState({
like: false,
unlike: true,
});
} else {
this.setState({
like: false,
unlike: false,
});
}
}
// 取消
onCancel(e) {
console.log('444',e.changedTouches[0].pageX);
this.setState({
x: '16',
y: '16',
like: false,
unlike: false,
});
}
當(dāng)我們寫(xiě)到這里,我們?nèi)ネ蟿?dòng)我們的卡片時(shí),你會(huì)發(fā)現(xiàn)確實(shí)可以拖動(dòng),并且取消的時(shí)候會(huì)回到原點(diǎn),但是同樣你也會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題,就是你拖動(dòng)的時(shí)候,五張卡片都被觸發(fā)來(lái)移動(dòng)的效果,出現(xiàn)了觸點(diǎn)混亂的問(wèn)題,查找問(wèn)題發(fā)現(xiàn)卡片共用了x,y,因此我們可以給每張卡片設(shè)置獨(dú)立的參數(shù);
四,給每張卡片獨(dú)立的參數(shù)并且設(shè)置卡片傾斜度效果;
1.設(shè)置傾斜度效果
style={{transform:'rotate('+this.state.tiltAngle[index]+'deg)'}}
然后我們通過(guò)卡片移動(dòng)位置計(jì)算出一個(gè)你決定合適的傾斜角度;
// 拖動(dòng)后相差距離進(jìn)行換算角度 let dxangle = (e.touches[0].pageX - this.state.startX) * 45 / 500;
2.設(shè)置獨(dú)立的參數(shù)
方法攜帶索引,我們?nèi)〉綄?duì)應(yīng)的卡片index,來(lái)改變對(duì)應(yīng)卡片的數(shù)據(jù);
<MovableView
key={item.id}
onTouchcancel={this.onCancel.bind(this,index)}
onTouchend={this.onCancel.bind(this,index)}
onTouchstart={this.onTouchStart.bind(this,index)}
onTouchmove={this.onTouchMove.bind(this,index)}
x={this.state.x[index]}
y={this.state.y[index]}
direction='all'
outOfBounds
className='shop-imgbox'
>
</MovableView>
同時(shí),我們需要改變初始參數(shù)的形式為數(shù)組,我們通過(guò)索引改變對(duì)應(yīng)卡片的值;
state = {
// 開(kāi)始位置
startX: '',
// 開(kāi)始位置-最終位置距離
placeX: '',
// 傾斜角度
tiltAngle: ['0','0','0','0','0'],
// 坐標(biāo)
x: ['16','16','16','16','16'],
y: ['16','16','16','16','16'],
// 是否喜歡狀態(tài)
like: [false,false,false,false,false],
unlike: [false,false,false,false,false],
// 推薦商品數(shù)組
shopList: [
{
id: 1,
img: 'https://edgefix-image.edgecom.top/ABD846F6672997A7F76CD38E8A57F954.jpg',
},
{
id: 2,
img: 'https://edgefix-image.edgecom.top/F6E5801C304CC76DA63C02C9FB38B8F4.jpg',
},
{
id: 3,
img: 'https://edgefix-image.edgecom.top/D518952AD1DD61B2D32556E20CC527C4.jpg',
},
{
id: 4,
img: 'https://edgefix-image.edgecom.top/1D187E28B349679908A44BBE81F3D3CA.jpg',
},
{
id: 5,
img: 'https://edgefix-image.edgecom.top/1129A411AC9CF5F81187CBED181B6F57.jpg',
}
]
}
方法我們就舉一個(gè)例子,比如onTouchStart方法,我們遍歷卡片數(shù)組,通過(guò)判斷索引來(lái)得到是那張卡片,從而來(lái)改變對(duì)應(yīng)值
// 觸摸觸發(fā)
onTouchStart(index,e) {
console.log('1111',index,e.touches[0].pageX,e.touches[0].pageY);
// 重定義數(shù)組
var againX = [];
var againY = [];
// 遍歷,判斷拖動(dòng)的該數(shù)組的位置
for (var i=0; i<this.state.shopList.length; i++){
if (i == index) {
againX[i] = e.touches[0].pageX;
againY[i] = e.touches[0].pageY;
} else {
againX[i] = '16';
againY[i] = '16';
}
}
// 賦值
this.setState({
startX: e.touches[0].pageX,
x: againX,
y: againY,
});
}
這樣,我們運(yùn)行代碼,發(fā)現(xiàn)拖動(dòng)第一張卡片不會(huì)影響到后面卡片的位置了,
同時(shí),我們現(xiàn)在拖動(dòng)卡片刪除的是數(shù)組,在實(shí)際項(xiàng)目中,我們?cè)谟|發(fā)刪除數(shù)組的地方接入接口,調(diào)用喜歡,不喜歡改變數(shù)據(jù)參數(shù),從而也能改變數(shù)組的長(zhǎng)度;
五,完整代碼;
下面我將貼出完整的代碼供大家參考
html文件:
import Taro, { Component } from '@tarojs/taro';
import { View, Image, Button, Text, MovableArea, MovableView } from '@tarojs/components';
import { observer, inject } from '@tarojs/mobx';
import { AtButton, AtFloatLayout } from 'taro-ui';
import userStore from '../../store/user.store';
import './stroll.scss';
@inject('userStore')
@observer
class Stroll extends Component {
config = {
navigationBarTitleText: '逛',
}
state = {
// 開(kāi)始位置
startX: '',
// 開(kāi)始位置-最終位置距離
placeX: '',
// 傾斜角度
tiltAngle: ['0','0','0','0','0'],
// 坐標(biāo)
x: ['16','16','16','16','16'],
y: ['16','16','16','16','16'],
// 是否喜歡狀態(tài)
like: [false,false,false,false,false],
unlike: [false,false,false,false,false],
// 推薦商品數(shù)組
shopList: [
{
id: 1,
img: 'https://edgefix-image.edgecom.top/ABD846F6672997A7F76CD38E8A57F954.jpg',
},
{
id: 2,
img: 'https://edgefix-image.edgecom.top/F6E5801C304CC76DA63C02C9FB38B8F4.jpg',
},
{
id: 3,
img: 'https://edgefix-image.edgecom.top/D518952AD1DD61B2D32556E20CC527C4.jpg',
},
{
id: 4,
img: 'https://edgefix-image.edgecom.top/1D187E28B349679908A44BBE81F3D3CA.jpg',
},
{
id: 5,
img: 'https://edgefix-image.edgecom.top/1129A411AC9CF5F81187CBED181B6F57.jpg',
}
]
}
componentWillMount () { }
componentWillReact () { }
componentDidMount () {
}
// 觸摸觸發(fā)
onTouchStart(index,e) {
console.log('1111',index,e.touches[0].pageX,e.touches[0].pageY);
// 重定義數(shù)組
var againX = [];
var againY = [];
// 遍歷,判斷拖動(dòng)的該數(shù)組的位置
for (var i=0; i<this.state.shopList.length; i++){
if (i == index) {
againX[i] = e.touches[0].pageX;
againY[i] = e.touches[0].pageY;
} else {
againX[i] = '16';
againY[i] = '16';
}
}
// 賦值
this.setState({
startX: e.touches[0].pageX,
x: againX,
y: againY,
});
}
// 觸摸離開(kāi)
onTouchMove(index,e) {
console.log('2222',index,e.touches[0].pageX,e.touches[0].pageY);
// 重定義數(shù)組
var tiltAngleT = [];
var againX = [];
var againY = [];
// 拖動(dòng)后相差距離
let dxplace = e.touches[0].pageX - this.state.startX;
// 拖動(dòng)后相差距離進(jìn)行換算角度
let dxangle = (e.touches[0].pageX - this.state.startX) * 45 / 500;
console.log(dxangle);
// 遍歷,判斷拖動(dòng)的該數(shù)組的位置
for (var i=0; i<this.state.shopList.length; i++){
if (i == index && dxplace > 50) {
tiltAngleT[i] = dxangle,
againX[i] = true;
againY[i] = false;
} else if (i == index && dxplace <= -50) {
tiltAngleT[i] = dxangle,
againX[i] = false;
againY[i] = true;
} else if (i == index && dxplace < 50 && dxplace > -50) {
tiltAngleT[i] = dxangle,
againX[i] = false;
againY[i] = false;
} else {
tiltAngleT[i] = '0',
againX[i] = false;
againY[i] = false;
}
}
// 賦值
this.setState({
placeX: dxplace,
tiltAngle: tiltAngleT,
like: againX,
unlike: againY,
});
}
// 取消
onCancel(index,e) {
console.log('3333',index,e.changedTouches[0].pageX,e.changedTouches[0].pageY);
// 賦值
this.setState({
tiltAngle: ['0','0','0','0','0'],
x: ['16','16','16','16','16'],
y: ['16','16','16','16','16'],
like: [false,false,false,false,false],
unlike: [false,false,false,false,false],
});
// 如果偏移已經(jīng)達(dá)到則清除第一張圖片
if (this.state.placeX > 50 || this.state.placeX < -50) {
this.setState({
shopList: this.state.shopList.splice(1,4),
});
}
}
// 不喜歡按鈕點(diǎn)擊
dislikebtn() {
// 改變按鈕的狀態(tài)以及圖片位置及顯示
this.setState({
tiltAngle: ['-18','0','0','0','0'],
x: ['-30','16','16','16','16'],
y: ['267','16','16','16','16'],
unlike: [true,false,false,false,false],
}, () => {
setTimeout( () => {
this.setState({
tiltAngle: ['0','0','0','0','0'],
x: ['16','16','16','16','16'],
y: ['16','16','16','16','16'],
unlike: [false,false,false,false,false],
shopList: this.state.shopList.splice(1,4),
});
},100);
});
}
// 喜歡按鈕點(diǎn)擊
likebtn() {
// 改變按鈕的狀態(tài)以及圖片位置及顯示
this.setState({
tiltAngle: ['18','0','0','0','0'],
x: ['284','16','16','16','16'],
y: ['267','16','16','16','16'],
like: [true,false,false,false,false],
}, () => {
setTimeout( () => {
this.setState({
tiltAngle: ['0','0','0','0','0'],
x: ['16','16','16','16','16'],
y: ['16','16','16','16','16'],
like: [false,false,false,false,false],
shopList: this.state.shopList.splice(1,4),
});
},100);
});
}
componentWillUnmount () { }
componentDidShow () {
}
componentDidHide () { }
render() {
return (
<View className='stroll-tab'>
<View className='stroll-text'>
<Text className='text-tip1'>搭配師每天為你推薦5件單品</Text>
<View className='text-tip2'>
<Text className='t1'>右滑喜歡</Text>
<Image src={require('./img/ic_like.png')} className='icon-image'></Image>
<Text className='t1'>,左滑不喜歡</Text>
<Image src={require('./img/ic_dislike.png')} className='icon-image'></Image>
</View>
</View>
{
this.state.shopList.length != 0&&
<MovableArea className='stroll-shop'>
{
this.state.shopList&&this.state.shopList.map((item,index) => {
return(
<MovableView
key={item.id}
onTouchcancel={this.onCancel.bind(this,index)}
onTouchend={this.onCancel.bind(this,index)}
onTouchstart={this.onTouchStart.bind(this,index)}
onTouchmove={this.onTouchMove.bind(this,index)}
x={this.state.x[index]}
y={this.state.y[index]}
direction='all'
outOfBounds
className='shop-imgbox'
>
<View className='images-box' style={{transform:'rotate('+this.state.tiltAngle[index]+'deg)'}}>
<Image src={item.img} className='images'></Image>
{
this.state.like[index]==true&&
<Image src={require('./img/text_like.png')} className='imagelike'></Image>
}
{
this.state.unlike[index]==true&&
<Image src={require('./img/text_dislike.png')} className='imageunlike'></Image>
}
</View>
</MovableView>
);})
}
</MovableArea>
}
{
this.state.shopList.length === 0&&
<View className='noshop-card'>
<Image src={require('./img/noshop.png')} className='noshop-image'></Image>
</View>
}
<View className='stroll-fotter'>
{
this.state.shopList.length != 0&&
<View className='fot-twoimg'>
{
this.state.unlike[0]==false&&
<Image src={require('./img/dislike_default.png')} className='dislike-image' onClick={this.dislikebtn.bind(this)}></Image>
}
{
this.state.unlike[0]==true&&
<Image src={require('./img/dislike_click.png')} className='dislike-image'></Image>
}
{
this.state.like[0]==false&&
<Image src={require('./img/like_default.png')} className='like-image' onClick={this.likebtn.bind(this)}></Image>
}
{
this.state.like[0]==true&&
<Image src={require('./img/like_click.png')} className='like-image'></Image>
}
</View>
}
<Text className='fot-text'>查看我喜歡的</Text>
</View>
</View>
);
}
}
export default Stroll;
css文件:
page {
height: 100%;
background: #F6F6F6;
}
.stroll-tab {
width: 100%;
min-height: 100vh;
background: #F6F6F6;
.stroll-text {
width: 100%;
margin-top: 40px;
display: flex;
flex-direction: column;
align-items: center;
.text-tip1 {
font-size: 28px;
color: #333333;
}
.text-tip2 {
display: flex;
flex-direction: row;
align-items: center;
.t1 {
font-size: 28px;
color: #333333;
}
.icon-image {
width:20px;
height:20px;
}
}
}
.stroll-shop {
width: 100%;
height: 700px;
margin-top: 40px;
.shop-imgbox {
height: 600px;
border-radius: 24px;
.images-box {
width: 100%;
height: 520px;
border-radius: 24px;
box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.1);
background-color: #fff;
position: relative;
.images {
width: 606px;
height: 480px;
position: absolute;
left: 40px;
top: 20px;
}
.imagelike {
width: 96px;
height: 48px;
position: absolute;
right: 40px;
top: 20px;
}
.imageunlike {
width: 148px;
height: 48px;
position: absolute;
left: 40px;
top: 20px;
}
}
}
.shop-imgbox:nth-child(1) {
width: 686px;
z-index: 50;
}
.shop-imgbox:nth-child(2) {
width: 676px;
z-index: 40;
margin: 15px 0px 0px 5px;
}
.shop-imgbox:nth-child(3) {
width: 666px;
z-index: 30;
margin: 30px 0px 0px 10px;
}
.shop-imgbox:nth-child(4) {
width: 656px;
z-index: 20;
margin: 0px 0px 0px 15px;
}
.shop-imgbox:nth-child(5) {
width: 646px;
z-index: 10;
margin: 0px 0px 0px 20px;
}
}
.noshop-card {
width: 100%;
margin-top: 40px;
padding: 0px 16px;
.noshop-image {
width: 100%;
height: 806px;
}
}
.stroll-fotter {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
margin-top: 20px;
.fot-twoimg {
display: flex;
flex-direction: row;
align-items: center;
.dislike-image {
width: 120px;
height: 120px;
}
.like-image {
width: 120px;
height: 120px;
margin-left: 48px;
}
}
.fot-text {
color: #368BE5;
font-size: 28px;
margin-top: 40px;
margin-bottom: 50px;
}
}
}
總結(jié)
到此這篇關(guān)于Taro UI開(kāi)發(fā)小程序?qū)崿F(xiàn)左滑喜歡右滑不喜歡效果的文章就介紹到這了,更多相關(guān)小程序?qū)崿F(xiàn)左滑喜歡右滑不喜歡內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js創(chuàng)建一個(gè)input數(shù)組并綁定click事件的方法
這篇文章主要介紹了js創(chuàng)建一個(gè)input數(shù)組并綁定click事件的方法,需要的朋友可以參考下2014-06-06
JavaScript學(xué)習(xí)筆記--常用的互動(dòng)方法
本文對(duì)JavaScript中常用的互動(dòng)方法進(jìn)行實(shí)例分析介紹,圖文并茂,有需要的朋友可以看下2016-12-12
JavaScript基于面向?qū)ο髮?shí)現(xiàn)的猜拳游戲
這篇文章主要介紹了JavaScript基于面向?qū)ο髮?shí)現(xiàn)的猜拳游戲,結(jié)合完整實(shí)例形式分析了javascript基于面向?qū)ο髮?shí)現(xiàn)猜拳游戲的具體頁(yè)面布局、樣式及功能相關(guān)操作技巧,需要的朋友可以參考下2018-01-01
禁止彈窗中蒙層底部頁(yè)面跟隨滾動(dòng)的幾種方法
我們大家在做彈出層的時(shí)候,必不可少的一個(gè)元素就是蒙層,也就是遮罩層,當(dāng)彈出層滾動(dòng)的時(shí)候,蒙層底部的頁(yè)面一般是要求固定不動(dòng)的,所以這篇文章就來(lái)給大家介紹了如何禁止彈窗中蒙層底部頁(yè)面跟隨滾動(dòng)的幾種方法,需要的朋友可以參考下。2017-12-12
js監(jiān)聽(tīng)html頁(yè)面的上下滾動(dòng)事件方法
今天小編就為大家分享一篇js監(jiān)聽(tīng)html頁(yè)面的上下滾動(dòng)事件方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
uniapp使用vue-cli新建項(xiàng)目并打包的步驟
這篇文章主要介紹了uniapp使用vue-cli新建項(xiàng)目并打包,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-11-11

