HTML
html
<view wx:if="{{advertiseFlag}}" class="advertise-wrapper" style="background-color:{{transitionData.statusBtn == 'playing'?'rgba(255,255,255,0)':''}}" bindtap="jumpFn">
<view class="advertise-box" style="width:{{transitionData.width}};height:{{transitionData.height}};left:{{transitionData.left}};top:{{transitionData.top}};opacity:{{transitionData.opacity}};animation:{{transitionData.animation}}">
<image data-status="{{transitionData.statusBtn}}" catchtap="handleJumpValue" src="{{ advertiseMsg.url || 'https://yizhen-mamapai-dev.oss-cn-zhangjiakou.aliyuncs.com/certification/2024-06-13/b1791b525e974c0aae8a0c82a8410a9b.png'}}">
</image>
<view class="jump-box" catchtap="jumpFn" data-status="{{transitionData.statusBtn}}">
跳过{{defaultTime?defaultTime:''}}
</view>
</view>
</view>
CSS
css
.advertise-wrapper {
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, 0.75);
position: fixed;
top: 0;
left: 0;
z-index: 999;
display: flex;
justify-content: center;
align-items: center;
}
.advertise-box {
width: 580rpx;
height: 980rpx;
position: absolute;
transition: all 1s linear;
}
@keyframes shrinkAndMoveToPosition {
from {
transform: scale(1);
opacity: 1;
}
to {
transform: scale(0.5);
opacity: 0;
}
}
.advertise-box image {
width: 100%;
height: 100%;
}
.jump-box {
background: rgba(0, 0, 0, 0.8);
border-radius: 10px;
padding: 4rpx 16rpx;
position: absolute;
top: 20rpx;
right: 20rpx;
color: #fff;
font-size: 12px;
}
JS
动画函数
options的参数
from : 起始值 比如:0
to : 结束值 比如:100
totalMS :变化总时间 比如: 1000
duration : 每多少秒变化的次数 比如: 1
onmove :开始移动的回调函数
onend :移动结束的回调函数
javascript
let timer;
function createAnimation(option) {
// 起始值、结束值、变化总时间
var {
from,
to,
totalMS,
duration,
onmove,
onend
} = option;
totalMS = totalMS || 1000;
duration = duration || 10; // 每多少时间变化一次
var times = Math.floor(totalMS / duration); // 变化的次数
var dis = (to - from) / times; // 每次变化的量
var curTimes = 0;
// 每次变化的函数
var timer = setInterval(() => {
from += dis;
curTimes++;
// 变化完成,这里保证onmove 在 onend以前执行
if (curTimes >= times) {
from = to;
onmove && onmove(from);
onend && onend();
clearInterval(timer);
return;
}
onmove && onmove(from);
}, duration);
}
获取dom
我们点击跳转的时候,首先需要获取到当前点击 dom 的 status,如果当前的状态为 playing 直接 return,否则开始获取当前的 dom 信息,找到当前点击的 dom 和所要跳转到的 dom 所在位置,然后找到所要跳转的位置后,把当前点击的dom和所要去的dom传给开始的动画函数
javascript
handleGetDom(type) {
if (!type || type <= 0) return
let _this = this
wx.createSelectorQuery().select('.advertise-box').boundingClientRect()
.selectAll('.grid-container .item').boundingClientRect().exec((ret) => {
const [popRect, endDoms] = ret;
const targetIndex = endDoms.findIndex((item) => item.id == type);
if (targetIndex === -1) return;
const endDom = endDoms[targetIndex];
_this.startTransition(popRect, endDom);
})
},
开始动画过渡
根据获取 dom和所要去的 dom 的位置,在拿到要结束 dom 之前先把 status 状态设置为 playing ,这样后我们就可以设置动画效果然后把对应的参数传给动画函数 createAnimation 。
javascript
// 开始动画过渡
startTransition(popRect, endDom) {
const _this = this;
// 设置点击状态为playing
_this.setData({
transitionData: {
..._this.data.transitionData,
statusBtn: 'playing'
}
});
const centerX = endDom.left
const centerY = endDom.top
_this.setData({
transitionData: {
..._this.data.transitionData,
animation: "shrinkAndMoveToPosition 2s forwards"
}
});
createAnimation({
from: popRect.left,
to: centerX,
totalMS: 1000,
onmove: (n) => {
_this.updateTransitionData(endDom, centerX, centerY);
},
onend: () => {
_this.endTransition(endDom);
}
});
},
动画的更新函数
这个地方需要注意的是在支付宝中 left、top 不用需要加 px,width和height自行决定用不用除以2
javascript
// 更新动画过程中的数据
updateTransitionData(endDom, centerX, centerY) {
this.setData({
transitionData: {
...this.data.transitionData,
width: `${endDom.width / 2}px`,
height: `${endDom.height / 2}px`,
left: `${centerX}px`,
top: `${centerY}px`
}
});
},
动画的结束函数
在动画结束的时候我们需要把 status 更改为 end , opacity 设置为 0,清除定时器就可以了
javascript
// 结束动画并处理跳转
endTransition(endDom) {
const _this = this;
wx.showTabBar();
_this.setData({
transitionData: {
..._this.data.transitionData,
statusBtn: 'end',
opacity: 0
},
advertiseFlag: false
});
clearInterval(timer);
const currItem = {
...endDom.dataset.item,
richTextType: 2,
appletAdvertisementId: endDom.dataset.item.type
}
_this.handleJumpTypePage(currItem);
},
动画所有相关的事件函数
javascript
// 跳转类型
handleJumpValue(e) {
let {
relationHomeSwitch,
relationHomeType,
id
} = this.data.advertisingPopup
this.handleClickDataSave(id)
if (relationHomeType && relationHomeSwitch == 1) {
let status = e.currentTarget.dataset.status
// 判断是否有点击过 statusBtn
if (status == 'playing') return;
this.handleGetDom(relationHomeType)
} else if (relationHomeSwitch == 2) {
let data = {
...this.data.advertisingPopup,
richTextType: 3,
}
this.handleJumpTypePage(data)
} else {
wx.showTabBar();
this.setData({
advertiseFlag: false
});
clearInterval(timer);
}
},
// 获取dom
handleGetDom(type) {
if (!type || type <= 0) return
let _this = this
wx.createSelectorQuery().select('.advertise-box').boundingClientRect()
.selectAll('.grid-container .item').boundingClientRect().exec((ret) => {
const [popRect, endDoms] = ret;
const targetIndex = endDoms.findIndex((item) => item.id == type);
if (targetIndex === -1) return;
const endDom = endDoms[targetIndex];
_this.startTransition(popRect, endDom);
})
},
// 开始动画过渡
startTransition(popRect, endDom) {
const _this = this;
// 设置点击状态为playing
_this.setData({
transitionData: {
..._this.data.transitionData,
statusBtn: 'playing'
}
});
const centerX = endDom.left
const centerY = endDom.top
_this.setData({
transitionData: {
..._this.data.transitionData,
animation: "shrinkAndMoveToPosition 2s forwards"
}
});
createAnimation({
from: popRect.left,
to: centerX,
totalMS: 1000,
onmove: (n) => {
_this.updateTransitionData(endDom, centerX, centerY);
},
onend: () => {
_this.endTransition(endDom);
}
});
},
// 更新动画过程中的数据
updateTransitionData(endDom, centerX, centerY) {
this.setData({
transitionData: {
...this.data.transitionData,
width: `${endDom.width / 2}px`,
height: `${endDom.height / 2}px`,
left: `${centerX}px`,
top: `${centerY}px`
}
});
},
// 结束动画并处理跳转
endTransition(endDom) {
const _this = this;
wx.showTabBar();
_this.setData({
transitionData: {
..._this.data.transitionData,
statusBtn: 'end',
opacity: 0
},
advertiseFlag: false
});
clearInterval(timer);
const currItem = {
...endDom.dataset.item,
richTextType: 2,
appletAdvertisementId: endDom.dataset.item.type
}
_this.handleJumpTypePage(currItem);
},
// 点击
handleHomeConfigClick(id) {
let params = {
id: id
}
api.post('/main-service/home-config/click', params).then((res) => {
if (res.code == 1) {
console.log(res, 'res');
}
}).catch((err) => {
console.log(err, 'err');
})
},
jumpFn() {
wx.showTabBar();
this.setData({
advertiseFlag: false
});
clearInterval(timer);
},
// 动画end
完整实现代码
javascript
// pages/prize/prize.js
const api = require('../../common/api')
const App = getApp()
const getAuthCode = require('../../common/authen.js').getAuthCode
let timer;
let count = 0;
function createAnimation(option) {
// 起始值、结束值、变化总时间
var {
from,
to,
totalMS,
duration,
onmove,
onend
} = option;
totalMS = totalMS || 1000;
duration = duration || 10; // 没多少时间变化一次
var times = Math.floor(totalMS / duration); // 变化的次数
var dis = (to - from) / times; // 每次变化的量
var curTimes = 0;
// 每次变化的函数
var timer = setInterval(() => {
from += dis;
curTimes++;
// 变化完成,这里保证onmove 在 onend以前执行
if (curTimes >= times) {
from = to;
onmove && onmove(from);
onend && onend();
clearInterval(timer);
return;
}
onmove && onmove(from);
}, duration);
}
Page({
data: {
transitionData: {
statusBtn: '', // 是否已经点击过
left: '',
top: '',
width: '580rpx',
height: '980rpx',
opacity: 1
},
marketingId: "", // 营销id
styleConfigData: {},
imgSrc: [],
paramStr: '',
indicatorDots: false,
autoplay: true,
vertical: false,
interval: 2000,
circular: true,
duration: 1500,
defaultTime: 4, //默认时间
advertiseFlag: false,
advertiseMsg: {},
activityData: {
sourceType: ''
},
styleHomeImage: {},
activeIndex: "", // 切换下标
interval: 3000,
advertisingRotation: [], // 广告位轮播
newHomepage: [],
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
// this.getImage()
// this.getStyleConfig()
this.getAuth()
this.getHomeConfigPage()
this.handleGetAxiosData()
this.getAdvertisement()
},
onShow() {
let token = wx.getStorageSync('token')
if (App.globalData.activityData.sourceType == 'activity' && App.globalData.inviteCustomerNum < 2 && token) {
this.handleActivity()
}
},
handleActivity() {
const params = App.globalData.activityData
api.post('/main-service/customer-invite-record', params).then((res) => {
if (res.code === 1) {
console.log('邀请处理成功')
App.globalData.inviteCustomerNum = 2
}
if (res.code == 1010002) {
console.log('邀请处理失败')
App.globalData.inviteCustomerNum = 1
}
})
},
// 获取首页头部配置
getHomeConfigPage() {
api.get("/main-service/home-config/list").then((res) => {
if (res.code == 1) {
let originalHomepage = res.data && res.data.sort((a, b) => {
return a.type - b.type
}) || []
// 处理数据,添加额外属性用于渲染
const processedHomepage = originalHomepage.map(item => {
return {
...item,
shouldDisplay: this.shouldDisplayItem(item),
className: this.getClassByType(item.type),
imageMode: this.getImageMode(item.type),
showMenu: item.type >= 5,
defaultImage: this.getDefaultImage(item.type)
};
});
this.setData({
newHomepage: processedHomepage
})
}
}).catch((err) => {
console.log(err, 'err');
})
},
// 获取页面样式配置
getStyleConfig() {
api.get('/main-service/activity_style_config').then((res) => {
if (res.code === 1) {
const {
data
} = res
this.setData({
styleConfigData: {
...data,
topImg: res.data.imgUrl.split(",")[0],
bottomImg: res.data.imgUrl.split(",")[1],
}
})
}
})
},
//数据
handleGetAxiosData() {
let params = {
type: 39
}
api.get(`/main-service/sys/info`, params).then((res) => {
console.log(res, 'res')
if (res.code == 1) {
this.setData({
styleHomeImage: res.data.remark ? JSON.parse(res.data.remark) : {},
})
}
})
},
getImage() {
api.get('/main-service/home-page/advertising').then(res => {
this.setData({
imgSrc: res.data.weChatBackgroundUrl
})
})
},
// 获取 广告位轮播图
getAdvertisement() {
const params = {
position: 1
}
api.get('/main-service/advertisement', params).then((res) => {
if (res.code == 1) {
this.setData({
advertisingRotation: res.data
})
}
})
},
// 改变图片
changeImg(e) {
this.activeIndex = e.detail.current
this.setData({
activeIndex: e.detail.current
})
},
getAuth() {
getAuthCode().then(res => {
let authCode = res.authCode;
let params = {
code: authCode
};
this.getAdvertiseMsg(params);
});
},
//获取弹窗广告信息
getAdvertiseMsg(params) {
api.get("/main-service/applet-advertisement/v2", params).then(res => {
if (res.code == 1) {
this.setData({
advertiseFlag: res.data.status == 1 ? true : false,
advertiseMsg: res.data,
advertisingPopup: {
...res.data
}
});
if (res.data.id) {
wx.hideTabBar();
}
if (res.data.status == 1) {
timer = setInterval(() => {
if (this.data.defaultTime > 0) {
let time = (this.data.defaultTime -= 1);
this.setData({
defaultTime: time
});
return;
}
if (!this.data.defaultTime) {
clearInterval(timer);
this.isLike();
}
}, 1000);
}
}
});
},
//是否感兴趣
isLike() {
let id = this.data.advertiseMsg.id;
if (id) {
api.get(`/main-service/applet-advertisement/${id}`).then(res => {
if (res.code == 1) {
console.log("感兴趣");
}
});
}
},
// 跳转详情
handleJumpDetails(item) {
let {
id,
jumpType
} = item.currentTarget.dataset.value
if (jumpType == 13) {
wx.navigateTo({
url: `/addressManagement/pages/richText/richText?jumpId=${id}`
});
}
},
// 页面跳转
handleJumpToPage(e) {
let {
item
} = e.currentTarget.dataset
this.handleHomeConfigClick(item.id)
wx.hideLoading()
let data = {
...item,
richTextType: 2,
appletAdvertisementId: item.type
}
wx.hideLoading()
this.handleJumpTypePage(data)
},
// 根据跳转类型处理页面跳转
handleJumpTypePage(item) {
const jumpType = Number(item.jumpType);
this.jumpFn()
const routes = {
1: () => this.handlePageTo(),
2: () => wx.navigateTo({
url: "/addressManagement/pages/invitingWithCourtesy/invitingWithCourtesy"
}),
3: () => wx.navigateTo({
url: `/addressManagement/pages/invitationGiftDetail/invitationGiftDetail?id=${item.jumpValue}`
}),
4: () => wx.switchTab({
url: '/pages/activity/activity'
}),
5: () => wx.navigateTo({
url: `/pages/activityDetail/activityDetail?activityId=${item.jumpValue}`
}),
6: () => wx.navigateTo({
url: `/addressManagement/pages/richText/richText?jumpId=${item.appletAdvertisementId}&type=${item.richTextType}`
}),
// 7: () => wx.navigateTo({ url: `/pages/content-detail/content-detail?id=${item.jumpValue}&type=1` }),
// 8: () => wx.navigateTo({ url: `/pages/content-detail/content-detail?id=${item.jumpValue}&type=3` }),
9: () => wx.navigateTo({
url: `/addressManagement/pages/richText/richText?jumpId=${item.appletAdvertisementId}&status=btn&type=${item.richTextType}`
}),
10: () => wx.navigateTo({
url: `/addressManagement/pages/marketing/marketing?id=${item.type}&type=home`
}),
};
if (routes[jumpType]) {
routes[jumpType]();
}
},
// 点击数据
handleClickDataSave(id) {
let params = {
appletAdvertisementCustomerRecordId: id
}
api.get('/main-service/applet-advertisement/save-click-data', params).then((res) => {
if (res.code == 1) {
console.log(res, 'res');
}
}).catch((err) => {
console.log(err, 'err');
})
},
// 跳转类型
handleJumpValue(e) {
let {
relationHomeSwitch,
relationHomeType,
id
} = this.data.advertisingPopup
this.handleClickDataSave(id)
if (relationHomeType && relationHomeSwitch == 1) {
let status = e.currentTarget.dataset.status
// 判断是否有点击过 statusBtn
if (status == 'playing') return;
this.handleGetDom(relationHomeType)
} else if (relationHomeSwitch == 2) {
let data = {
...this.data.advertisingPopup,
richTextType: 3,
}
this.handleJumpTypePage(data)
} else {
wx.showTabBar();
this.setData({
advertiseFlag: false
});
clearInterval(timer);
}
},
// 获取dom
handleGetDom(type) {
if (!type || type <= 0) return
let _this = this
wx.createSelectorQuery().select('.advertise-box').boundingClientRect()
.selectAll('.grid-container .item').boundingClientRect().exec((ret) => {
const [popRect, endDoms] = ret;
const targetIndex = endDoms.findIndex((item) => item.id == type);
if (targetIndex === -1) return;
const endDom = endDoms[targetIndex];
_this.startTransition(popRect, endDom);
})
},
// 开始动画过渡
startTransition(popRect, endDom) {
const _this = this;
// 设置点击状态为playing
_this.setData({
transitionData: {
..._this.data.transitionData,
statusBtn: 'playing'
}
});
const centerX = endDom.left
const centerY = endDom.top
_this.setData({
transitionData: {
..._this.data.transitionData,
animation: "shrinkAndMoveToPosition 2s forwards"
}
});
createAnimation({
from: popRect.left,
to: centerX,
totalMS: 1000,
onmove: (n) => {
_this.updateTransitionData(endDom, centerX, centerY);
},
onend: () => {
_this.endTransition(endDom);
}
});
},
// 更新动画过程中的数据
updateTransitionData(endDom, centerX, centerY) {
this.setData({
transitionData: {
...this.data.transitionData,
width: `${endDom.width / 2}px`,
height: `${endDom.height / 2}px`,
left: `${centerX}px`,
top: `${centerY}px`
}
});
},
// 结束动画并处理跳转
endTransition(endDom) {
const _this = this;
wx.showTabBar();
_this.setData({
transitionData: {
..._this.data.transitionData,
statusBtn: 'end',
opacity: 0
},
advertiseFlag: false
});
clearInterval(timer);
const currItem = {
...endDom.dataset.item,
richTextType: 2,
appletAdvertisementId: endDom.dataset.item.type
}
_this.handleJumpTypePage(currItem);
},
// 点击
handleHomeConfigClick(id) {
let params = {
id: id
}
api.post('/main-service/home-config/click', params).then((res) => {
if (res.code == 1) {
console.log(res, 'res');
}
}).catch((err) => {
console.log(err, 'err');
})
},
jumpFn() {
wx.showTabBar();
this.setData({
advertiseFlag: false
});
clearInterval(timer);
},
// 动画end
handlePageTo: function () {
let that = this
wx.showLoading({
title: '加载中',
mask: true
})
this.checkAttestation()
// that.getUserInfo()
},
// getUserInfo() {
// let that = this
// getAuthCode().then((res) => {
// const {
// authCode
// } = res
// let params = {
// loginType: 7,
// isRelatedPhoneNumber: 0,
// grantCode: authCode
// }
// api.post('/main-service/customer/login', params).then(({
// data
// }) => {
// const {
// isRelatedPhoneNumber,
// phoneNumber,
// token
// } = data
// if (isRelatedPhoneNumber == 0) {
// wx.hideLoading()
// wx.reLaunch({
// url: '/pages/login/login?sourceType=prize'
// });
// return
// }
// if (isRelatedPhoneNumber == 1) {
// wx.hideLoading()
// wx.setStorageSync('token', token)
// that.checkAttestation()
// return
// }
// })
// })
// },
checkAttestation() {
api.get('/main-service/pregnant-certification/status').then(({
data
}) => {
wx.hideLoading()
const {
isWhite,
isSellOut,
status,
identityType,
isSyncTaoBao
} = data
if (isWhite == 0) {
if (status == 0) {
// 跳转认证页面
wx.navigateTo({
url: '/pages/authentication/authentication'
})
}
if (status == 1) {
// 跳转认证中
wx.navigateTo({
url: '/pages/AddCustomer/AddCustomer'
})
}
if (status == 2) {
// 打开领取链接
if (isSellOut) {
// 礼品售罄
// "identityType": 1:孕妈 2:宝妈
if (!isSyncTaoBao) {
wx.navigateTo({
url: '/pages/sellOut/sellOut'
})
// if (identityType == 1) {
// wx.navigateTo({
// url: '/pages/sellOut/sellOut'
// })
// }
// if (identityType == 2) {
// wx.navigateTo({
// url: `/pages/certificationPassed/certificationPassed`
// })
// }
} else {
// 修改之后的逻辑
wx.navigateTo({
url: `/pages/giftGuide/giftGuide?status=${status}`
})
}
} else {
wx.navigateTo({
url: `/pages/giftGuide/giftGuide?status=${status}`
})
// if (identityType == 1) {
// wx.navigateTo({
// url: `/pages/giftGuide/giftGuide?status=${status}`
// })
// }
// if (identityType == 2) {
// wx.navigateTo({
// url: `/pages/certificationPassed/certificationPassed`
// })
// }
}
}
if (status == 3) {
// 跳转拒绝页面
wx.navigateTo({
url: '/pages/certificationReject/certificationReject'
})
}
if (status == 4) {
// 跳转退回页面重新编辑
wx.navigateTo({
url: `/pages/authentication/authentication?status=${status}`
})
}
}
if (isWhite == 1) {
if (isSellOut) {
wx.navigateTo({
url: '/pages/sellOut/sellOut'
})
} else {
wx.navigateTo({
url: `/pages/giftGuide/giftGuide?status=${status}`
})
}
}
})
},
handleClickBanner() {
wx.navigateTo({
url: '/addressManagement/pages/bannerDetail/bannerDetail',
})
},
// 跳转会场
handleToShare() {
wx.navigateTo({
url: `/addressManagement/pages/taobaoVenue/taobaoVenue?type=home`,
});
},
// 开启分享
onShareAppMessage() {},
// 判断是否展示该 item
shouldDisplayItem(item) {
if (item.type >= 5 && item.showSwitch !== 1) return false;
return !!item.url || item.type <= 4; // 当 type 小于等于 4 时总是展示
},
// 根据 type 返回对应的类名
getClassByType(type) {
switch (type) {
case 1:
return 'new-mom-gift';
case 2:
return 'xhs-volunteer';
case 3:
return 'douyin-volunteer';
case 4:
return 'invitation-gift';
case 5:
return 'advertising-space-one';
case 6:
return 'advertising-space-two';
case 7:
return 'advertising-space-three';
default:
return '';
}
},
// 根据 type 返回图片的 mode
getImageMode(type) {
return type >= 5 ? 'widthFix' : 'scaleToFill';
},
// 获取默认图片 URL
getDefaultImage(type) {
return 'https://yizhen-mamapai-dev.oss-cn-zhangjiakou.aliyuncs.com/certification/2024-06-13/3cb773c6e3614c389619a24d55f868d4.png';
},
onPullDownRefresh() {
Promise.all([this.getHomeConfigPage()]).then(res => {
this.stopPullDownRefresh();
});
},
onUnload() {
this.jumpFn()
},
})