HTML
<view wx:if="{{advertiseFlag}}" class="advertise-wrapper" style="background-color:{{ == 'playing'?'rgba(255,255,255,0)':''}}" bindtap="jumpFn"> <view class="advertise-box" style="width:{{}};height:{{}};left:{{}};top:{{}};opacity:{{}};animation:{{}}"> <image data-status="{{}}" catchtap="handleJumpValue" src="{{ || '/certification/2024-06-13/'}}"> </image> <view class="jump-box" catchtap="jumpFn" data-status="{{}}"> jump over{{defaultTime?defaultTime:''}} </view> </view> </view>
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
Animation functions
Parameters of options
from: Start value For example: 0
to : End value For example: 100
TotalMS: Total time of change, for example: 1000
duration : The number of times changes every second For example: 1
onmove: The callback function that starts moving
oneend: The callback function that ends the move
let timer; function createAnimation(option) { // Start value, end value, total change time var { from, to, totalMS, duration, onmove, onend } = option; totalMS = totalMS || 1000; duration = duration || 10; // Change every time var times = (totalMS / duration); // Number of changes var dis = (to - from) / times; // The amount of change per time var curTimes = 0; // Functions for each change var timer = setInterval(() => { from += dis; curTimes++; // Changes are completed, here we ensure that onmove is executed before oneend if (curTimes >= times) { from = to; onmove && onmove(from); onend && onend(); clearInterval(timer); return; } onmove && onmove(from); }, duration); }
Get dom
When we click to jump, we first need to get the status of the current click dom. If the current status is playing, directly return, otherwise we will start to obtain the current dom information, find the current click dom and the location of the dom you want to jump to, and then find the location you want to jump to, and then pass the currently clicked dom and the dom you want to go to to the animation function that starts
handleGetDom(type) { if (!type || type <= 0) return let _this = this ().select('.advertise-box').boundingClientRect() .selectAll('.grid-container .item').boundingClientRect().exec((ret) => { const [popRect, endDoms] = ret; const targetIndex = ((item) => == type); if (targetIndex === -1) return; const endDom = endDoms[targetIndex]; _this.startTransition(popRect, endDom); }) },
Start the animation transition
According to obtaindom And the position of the dom you want to go to, set the status status to playing before you get the dom to end, so that we can set the animation effect and pass the corresponding parameters to the animation function createAnimation.
// Start the animation transition startTransition(popRect, endDom) { const _this = this; // Set the click status to play _this.setData({ transitionData: { ..._this., statusBtn: 'playing' } }); const centerX = const centerY = _this.setData({ transitionData: { ..._this., animation: "shrinkAndMoveToPosition 2s forwards" } }); createAnimation({ from: , to: centerX, totalMS: 1000, onmove: (n) => { _this.updateTransitionData(endDom, centerX, centerY); }, onend: () => { _this.endTransition(endDom); } }); },
Animation update function
It should be noted in this place that in Alipay, there is no need to add px for left and top, and the width and height are determined by yourself whether to divide by 2.
// Update data during animation updateTransitionData(endDom, centerX, centerY) { ({ transitionData: { ..., width: `${ / 2}px`, height: `${ / 2}px`, left: `${centerX}px`, top: `${centerY}px` } }); },
The end function of the animation
At the end of the animation, we need to change status to end, opacity to 0, and clear the timer
// End the animation and handle jump endTransition(endDom) { const _this = this; (); _this.setData({ transitionData: { ..._this., statusBtn: 'end', opacity: 0 }, advertiseFlag: false }); clearInterval(timer); const currItem = { ..., richTextType: 2, appletAdvertisementId: } _this.handleJumpTypePage(currItem); },
Animate all related event functions
// Jump type handleJumpValue(e) { let { relationHomeSwitch, relationHomeType, id } = (id) if (relationHomeType && relationHomeSwitch == 1) { let status = // Determine whether statusBtn has been clicked if (status == 'playing') return; (relationHomeType) } else if (relationHomeSwitch == 2) { let data = { ..., richTextType: 3, } (data) } else { (); ({ advertiseFlag: false }); clearInterval(timer); } }, // Get dom handleGetDom(type) { if (!type || type <= 0) return let _this = this ().select('.advertise-box').boundingClientRect() .selectAll('.grid-container .item').boundingClientRect().exec((ret) => { const [popRect, endDoms] = ret; const targetIndex = ((item) => == type); if (targetIndex === -1) return; const endDom = endDoms[targetIndex]; _this.startTransition(popRect, endDom); }) }, // Start the animation transition startTransition(popRect, endDom) { const _this = this; // Set the click status to play _this.setData({ transitionData: { ..._this., statusBtn: 'playing' } }); const centerX = const centerY = _this.setData({ transitionData: { ..._this., animation: "shrinkAndMoveToPosition 2s forwards" } }); createAnimation({ from: , to: centerX, totalMS: 1000, onmove: (n) => { _this.updateTransitionData(endDom, centerX, centerY); }, onend: () => { _this.endTransition(endDom); } }); }, // Update data during animation updateTransitionData(endDom, centerX, centerY) { ({ transitionData: { ..., width: `${ / 2}px`, height: `${ / 2}px`, left: `${centerX}px`, top: `${centerY}px` } }); }, // End the animation and handle jump endTransition(endDom) { const _this = this; (); _this.setData({ transitionData: { ..._this., statusBtn: 'end', opacity: 0 }, advertiseFlag: false }); clearInterval(timer); const currItem = { ..., richTextType: 2, appletAdvertisementId: } _this.handleJumpTypePage(currItem); }, // Click handleHomeConfigClick(id) { let params = { id: id } ('/main-service/home-config/click', params).then((res) => { if ( == 1) { (res, 'res'); } }).catch((err) => { (err, 'err'); }) }, jumpFn() { (); ({ advertiseFlag: false }); clearInterval(timer); }, // Animationend
Complete implementation code
// pages/prize/ const api = require('../../common/api') const App = getApp() const getAuthCode = require('../../common/').getAuthCode let timer; let count = 0; function createAnimation(option) { // Start value, end value, total change time var { from, to, totalMS, duration, onmove, onend } = option; totalMS = totalMS || 1000; duration = duration || 10; // Not much time to change once var times = (totalMS / duration); // Number of changes var dis = (to - from) / times; // The amount of change per time var curTimes = 0; // Functions for each change var timer = setInterval(() => { from += dis; curTimes++; // Changes are completed, here we ensure that onmove is executed before oneend if (curTimes >= times) { from = to; onmove && onmove(from); onend && onend(); clearInterval(timer); return; } onmove && onmove(from); }, duration); } Page({ data: { transitionData: { statusBtn: '', // Have you clicked left: '', top: '', width: '580rpx', height: '980rpx', opacity: 1 }, marketingId: "", // Marketing id styleConfigData: {}, imgSrc: [], paramStr: '', indicatorDots: false, autoplay: true, vertical: false, interval: 2000, circular: true, duration: 1500, defaultTime: 4, //Default time advertiseFlag: false, advertiseMsg: {}, activityData: { sourceType: '' }, styleHomeImage: {}, activeIndex: "", // Switch subscript interval: 3000, advertisingRotation: [], // Advertising space carousel newHomepage: [], }, /** * Lifecycle function-listen to page load */ onLoad: function (options) { // () // () () () () () }, onShow() { let token = ('token') if ( == 'activity' && < 2 && token) { () } }, handleActivity() { const params = ('/main-service/customer-invite-record', params).then((res) => { if ( === 1) { ('Invitation processing was successful') = 2 } if ( == 1010002) { ('Invitation processing failed') = 1 } }) }, // Get the home page header configuration getHomeConfigPage() { ("/main-service/home-config/list").then((res) => { if ( == 1) { let originalHomepage = && ((a, b) => { return - }) || [] // Process data, add extra properties for rendering const processedHomepage = (item => { return { ...item, shouldDisplay: (item), className: (), imageMode: (), showMenu: >= 5, defaultImage: () }; }); ({ newHomepage: processedHomepage }) } }).catch((err) => { (err, 'err'); }) }, // Get page style configuration getStyleConfig() { ('/main-service/activity_style_config').then((res) => { if ( === 1) { const { data } = res ({ styleConfigData: { ...data, topImg: (",")[0], bottomImg: (",")[1], } }) } }) }, //data handleGetAxiosData() { let params = { type: 39 } (`/main-service/sys/info`, params).then((res) => { (res, 'res') if ( == 1) { ({ styleHomeImage: ? () : {}, }) } }) }, getImage() { ('/main-service/home-page/advertising').then(res => { ({ imgSrc: }) }) }, // Get the ad space carousel getAdvertisement() { const params = { position: 1 } ('/main-service/advertisement', params).then((res) => { if ( == 1) { ({ advertisingRotation: }) } }) }, // Change the picture changeImg(e) { = ({ activeIndex: }) }, getAuth() { getAuthCode().then(res => { let authCode = ; let params = { code: authCode }; (params); }); }, //Get pop-up ad information getAdvertiseMsg(params) { ("/main-service/applet-advertisement/v2", params).then(res => { if ( == 1) { ({ advertiseFlag: == 1 ? true : false, advertiseMsg: , advertisingPopup: { ... } }); if () { (); } if ( == 1) { timer = setInterval(() => { if ( > 0) { let time = ( -= 1); ({ defaultTime: time }); return; } if (!) { clearInterval(timer); (); } }, 1000); } } }); }, //Is it interested isLike() { let id = ; if (id) { (`/main-service/applet-advertisement/${id}`).then(res => { if ( == 1) { ("interested"); } }); } }, // Jump details handleJumpDetails(item) { let { id, jumpType } = if (jumpType == 13) { ({ url: `/addressManagement/pages/richText/richText?jumpId=${id}` }); } }, // Page jump handleJumpToPage(e) { let { item } = () () let data = { ...item, richTextType: 2, appletAdvertisementId: } () (data) }, // Process page jump according to jump type handleJumpTypePage(item) { const jumpType = Number(); () const routes = { 1: () => (), 2: () => ({ url: "/addressManagement/pages/invitingWithCourtesy/invitingWithCourtesy" }), 3: () => ({ url: `/addressManagement/pages/invitationGiftDetail/invitationGiftDetail?id=${}` }), 4: () => ({ url: '/pages/activity/activity' }), 5: () => ({ url: `/pages/activityDetail/activityDetail?activityId=${}` }), 6: () => ({ url: `/addressManagement/pages/richText/richText?jumpId=${}&type=${}` }), // 7: () => ({ url: `/pages/content-detail/content-detail?id=${}&type=1` }), // 8: () => ({ url: `/pages/content-detail/content-detail?id=${}&type=3` }), 9: () => ({ url: `/addressManagement/pages/richText/richText?jumpId=${}&status=btn&type=${}` }), 10: () => ({ url: `/addressManagement/pages/marketing/marketing?id=${}&type=home` }), }; if (routes[jumpType]) { routes[jumpType](); } }, // Click on the data handleClickDataSave(id) { let params = { appletAdvertisementCustomerRecordId: id } ('/main-service/applet-advertisement/save-click-data', params).then((res) => { if ( == 1) { (res, 'res'); } }).catch((err) => { (err, 'err'); }) }, // Jump type handleJumpValue(e) { let { relationHomeSwitch, relationHomeType, id } = (id) if (relationHomeType && relationHomeSwitch == 1) { let status = // Determine whether statusBtn has been clicked if (status == 'playing') return; (relationHomeType) } else if (relationHomeSwitch == 2) { let data = { ..., richTextType: 3, } (data) } else { (); ({ advertiseFlag: false }); clearInterval(timer); } }, // Get dom handleGetDom(type) { if (!type || type <= 0) return let _this = this ().select('.advertise-box').boundingClientRect() .selectAll('.grid-container .item').boundingClientRect().exec((ret) => { const [popRect, endDoms] = ret; const targetIndex = ((item) => == type); if (targetIndex === -1) return; const endDom = endDoms[targetIndex]; _this.startTransition(popRect, endDom); }) }, // Start the animation transition startTransition(popRect, endDom) { const _this = this; // Set the click status to play _this.setData({ transitionData: { ..._this., statusBtn: 'playing' } }); const centerX = const centerY = _this.setData({ transitionData: { ..._this., animation: "shrinkAndMoveToPosition 2s forwards" } }); createAnimation({ from: , to: centerX, totalMS: 1000, onmove: (n) => { _this.updateTransitionData(endDom, centerX, centerY); }, onend: () => { _this.endTransition(endDom); } }); }, // Update data during animation updateTransitionData(endDom, centerX, centerY) { ({ transitionData: { ..., width: `${ / 2}px`, height: `${ / 2}px`, left: `${centerX}px`, top: `${centerY}px` } }); }, // End the animation and handle jump endTransition(endDom) { const _this = this; (); _this.setData({ transitionData: { ..._this., statusBtn: 'end', opacity: 0 }, advertiseFlag: false }); clearInterval(timer); const currItem = { ..., richTextType: 2, appletAdvertisementId: } _this.handleJumpTypePage(currItem); }, // Click handleHomeConfigClick(id) { let params = { id: id } ('/main-service/home-config/click', params).then((res) => { if ( == 1) { (res, 'res'); } }).catch((err) => { (err, 'err'); }) }, jumpFn() { (); ({ advertiseFlag: false }); clearInterval(timer); }, // animation end handlePageTo: function () { let that = this ({ title: 'loading', mask: true }) () // () }, // getUserInfo() { // let that = this // getAuthCode().then((res) => { // const { // authCode // } = res // let params = { // loginType: 7, // isRelatedPhoneNumber: 0, // grantCode: authCode // } // ('/main-service/customer/login', params).then(({ // data // }) => { // const { // isRelatedPhoneNumber, // phoneNumber, // token // } = data // if (isRelatedPhoneNumber == 0) { // () // ({ // url: '/pages/login/login?sourceType=prize' // }); // return // } // if (isRelatedPhoneNumber == 1) { // () // ('token', token) // () // return // } // }) // }) // }, checkAttestation() { ('/main-service/pregnant-certification/status').then(({ data }) => { () const { isWhite, isSellOut, status, identityType, isSyncTaoBao } = data if (isWhite == 0) { if (status == 0) { // Jump to the authentication page ({ url: '/pages/authentication/authentication' }) } if (status == 1) { // Jump authentication ({ url: '/pages/AddCustomer/AddCustomer' }) } if (status == 2) { // Open the collection link if (isSellOut) { // The gifts are sold out // "identityType": 1: Pregnant mother 2: Baoma if (!isSyncTaoBao) { ({ url: '/pages/sellOut/sellOut' }) // if (identityType == 1) { // ({ // url: '/pages/sellOut/sellOut' // }) // } // if (identityType == 2) { // ({ // url: `/pages/certificationPassed/certificationPassed` // }) // } } else { // Modified logic ({ url: `/pages/giftGuide/giftGuide?status=${status}` }) } } else { ({ url: `/pages/giftGuide/giftGuide?status=${status}` }) // if (identityType == 1) { // ({ // url: `/pages/giftGuide/giftGuide?status=${status}` // }) // } // if (identityType == 2) { // ({ // url: `/pages/certificationPassed/certificationPassed` // }) // } } } if (status == 3) { // Jump to the rejection page ({ url: '/pages/certificationReject/certificationReject' }) } if (status == 4) { // Jump back to the page to edit again ({ url: `/pages/authentication/authentication?status=${status}` }) } } if (isWhite == 1) { if (isSellOut) { ({ url: '/pages/sellOut/sellOut' }) } else { ({ url: `/pages/giftGuide/giftGuide?status=${status}` }) } } }) }, handleClickBanner() { ({ url: '/addressManagement/pages/bannerDetail/bannerDetail', }) }, // Jump to the venue handleToShare() { ({ url: `/addressManagement/pages/taobaoVenue/taobaoVenue?type=home`, }); }, // Turn on sharing onShareAppMessage() {}, // Determine whether to display the item shouldDisplayItem(item) { if ( >= 5 && !== 1) return false; return !! || <= 4; // Always displayed when type is less than or equal to 4 }, // Return the corresponding class name according to 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 ''; } }, // Return to the mode of the image according to type getImageMode(type) { return type >= 5 ? 'widthFix' : 'scaleToFill'; }, // Get the default image URL getDefaultImage(type) { return '/certification/2024-06-13/'; }, onPullDownRefresh() { ([()]).then(res => { (); }); }, onUnload() { () }, })
This is the article about the WeChat/Alipay mini program that implements pop-up animation zoom to a certain position. For more related pop-up animation zoom to a certain position, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!