亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 課堂 > 小程序 > 正文

微信小程序中懸浮窗功能的實現代碼

2020-03-21 15:49:57
字體:
來源:轉載
供稿:網友

問題場景

所謂懸浮窗就是圖中微信圖標的按鈕,采用fixed定位,可拖動和點擊。

這算是一個比較常見的實現場景了。

微信小程序,懸浮窗

為什么要用cover-view做懸浮窗?原生組件出來背鍋了~

最初我做懸浮窗用的不是cover-view,而是view。

這是簡化的代碼結構:

index.wxml:<view class="move-view" style=" top:{{top}}px;left:{{left}}px;" bindtap="goToHome" catchtouchmove="setTouchMove"> <image class="img" src="https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=4294841024,3545417298&fm=179&app=42&f=PNG?w=56&h=56"> </image></view><textarea placeholder='我是textarea組件,用來輸入一些信息'></textarea><view> 一大段test,占個位,表示下存在感</view>index.js:Page({ /** * 頁面的初始數據 */ data: { left: 20, top: 250, isIos: true }, /** * 拖拽移動 */ setTouchMove: function (e) { if (e.touches[0].clientX > 0 && e.touches[0].clientY > 0) {  this.setData({  left: e.touches[0].clientX - 30,  top: e.touches[0].clientY - 30  }) } else {  this.setData({  left: 20, //默認顯示位置 left距離  top: 250 //默認顯示位置 top距離  }) } }, /** * 返回首頁 */ goToHome: () => { wx.reLaunch({  url: '/pages/index/index', }) }})

為什么要用cover-view呢?

因為頁面上有個textarea組件,這個組件是原生組件,當懸浮窗移動到這個textarea組件上時,將無法繼續拖動和點擊。

如果懸浮窗一開始就定位在textarea上,那么就更慘了,一開始就不能點擊和拖動了。

這個原因時因為微信小程序的原生組件層級高于非原生組件,不是你修改幾下樣式就能解決的問題。

這里就不講什么原生組件了,如果想進一步了解,可以參考我之前寫的一篇博客:微信小程序在ios下Echarts圖表不能滑動的解決方案。

如果你的頁面上面沒有原生組件,那么像上面的代碼一樣用view做懸浮窗即可。

如果有,那么就可以跟著我繼續踩坑,使用cover-view這個原生組件層級的組件來做懸浮窗。

安卓下的cover-view拖動起來,抖得不像帕金森,像是魔鬼的步伐

以下是我們修改為cover-view之后的代碼:

<cover-view class="move-view" style=" top:{{top}}px;left:{{left}}px;" bindtap="goToHome" catchtouchmove="setTouchMove"> <cover-image class="img" src="https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=4294841024,3545417298&fm=179&app=42&f=PNG?w=56&h=56"> </cover-image></cover-view><textarea placeholder='我是textarea組件,用來輸入一些信息'></textarea><view> 一大段test,占個位,表示下存在感</view>

注意這里,我們的image也改為了cover-image,因為cover-view只支持嵌套 cover-view、cover-image,不過可在 cover-view 中使用 button。

這樣雖然解決了可在原生組件上自由拖動點擊的問題,但是在安卓上出現了一個很奇怪的現象,以至于我認為已經無法用抖動可以來形容了:

微信小程序,懸浮窗

上圖是就是我滑動這個懸浮窗之后的效果,我只是很緩慢地在移動手指,但是這個懸浮窗的表現簡直就像一個受驚的兔子。

當我第一眼看見這個效果的時候一臉懵逼,我都不知道說什么好。

雖然在ios上cover-view移動起來表現良好,但是在安卓上拖動起來的表現簡直沒法看。

勉強能看的補丁方案

安卓上這么挫,還不如原來的呢。

所以來個補丁方案好了,在ios下用cover-view完美拖動,在安卓上用view先跑著。

<cover-view wx-if="{{isIos}}" class="move-view" style=" top:{{top}}px;left:{{left}}px;" bindtap="goToHome" catchtouchmove="setTouchMove"> <cover-image class="img" src="https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=4294841024,3545417298&fm=179&app=42&f=PNG?w=56&h=56"> </cover-image></cover-view><view wx-if="{{!isIos}}" class="move-view" style=" top:{{top}}px;left:{{left}}px;" bindtap="goToHome" catchtouchmove="setTouchMove"> <image class="img" src="https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=4294841024,3545417298&fm=179&app=42&f=PNG?w=56&h=56"> </image></view><textarea placeholder='我是textarea組件,用來輸入一些信息'></textarea><view> 一大段test,占個位,表示下存在感</view>

當然少不了要在js里面加上這句代碼:

onLoad: function (options) { wx.getSystemInfo({ success: (res) => {  if (res.platform == "android") {  this.setData({   isIos: false  })  } } })}

不要忘記isIos默認為true哦。

反正ios環境下可以完美使用了,至于安卓下拖到textarea組件上沒法再拖的問題,調整下懸浮框的初始位置就好了。

而且只要不是刻意移動到textarea組件上,拖動著懸浮框經過textarea組件也是沒有問題的嘛。

像我這么聰明的用戶還懂得滑動下面的頁面來使懸浮窗移動到非原生組件的地方,這樣就又可以拖動了嘛。

你又以為你的測試一定能發現這個問題?發現了又怎樣,我已經盡力了,還給你整出這么多理論依據,足夠你把鍋牢牢地按在微信小程序官方的頭上。

使用movable-view:仿佛發現了新大陸,結果發現這個還是個弟弟

甩鍋是一定要甩鍋的,但是段位要高。

所以要遍查官方文檔,探討一切可能性,以免甩鍋的時候被打臉。

我們仔細觀察小程序官方文檔,發現還是有個專門用來拖動的組件叫movable-view。

這個組件和cover-view擺放在一起仿佛很厲害的樣子,緊接著我們在原生組件使用限制文檔中發現了它并不是原生組件。

也就是說這個東西的層級一定還是低于咱們的textarea組件的。

雖然已經很確定這個東西沒什么用了,但是最后還是試探一把,結果發現是個真弟弟,這里就不給出代碼了。

我寫這個弟弟方案放在這里的目的主要是為了不要浪費你的驗證時間。

理論上行得通的方案:將拖動事件的捕獲放在父級

現在我們確認的最優甩鍋方案里,已經實現了功能和甩鍋兩不誤。

那么作為一名有追求的技術人員,還是需要去探討以下這個問題到底有沒有完美的解決方案。

因為我最開始是把這個懸浮窗做成了一個組件,那么作為組件來講,這個東西就只能做到這個地步了。

不過如果你是像我現在的例子一樣直接做在了頁面里,那么實現起來也不是說沒有辦法的。

我們將拖動的事件放在父級上就可以了,請看接下來的代碼:

index.wxml:<view bindtouchmove="setTouchMove"> <view class="move-view" style=" top:{{top}}px;left:{{left}}px;" bindtap="goToHome">  <image class="img" src="https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=4294841024,3545417298&fm=179&app=42&f=PNG?w=56&h=56">  </image> </view> <textarea placeholder='我是textarea組件,用來輸入一些信息'></textarea> <view>  一大段test,占個位,表示下存在感 </view></view>index.js:Page({ /** * 頁面的初始數據 */ data: { left: 20, top: 250 }, /** * 拖拽移動 */ setTouchMove: function (e) { const MOVE_VIEW_RADIUS = 30 // 懸浮窗半徑 const touchPosX = e.touches[0].clientX const touchPosY = e.touches[0].clientY const moveViewCenterPosX = this.data.left + MOVE_VIEW_RADIUS const moveViewCenterPosY = this.data.top + MOVE_VIEW_RADIUS // 確保手指在懸浮窗上才可以移動 if (Math.abs(moveViewCenterPosX - touchPosX) < MOVE_VIEW_RADIUS + 60 && Math.abs(moveViewCenterPosY - touchPosY) < MOVE_VIEW_RADIUS + 60) {  if (touchPosX > 0 && touchPosY > 0) {  this.setData({   left: touchPosX - MOVE_VIEW_RADIUS,   top: touchPosY - MOVE_VIEW_RADIUS  })  } else {  this.setData({   left: 20, // 默認顯示位置 left距離   top: 250 // 默認顯示位置 top距離  })  } } }, /** * 返回首頁 */ goToHome: () => { wx.reLaunch({  url: '/pages/index/index', }) }})

關鍵代碼就是這塊了:

// 確保手指在懸浮窗上才可以移動if (Math.abs(moveViewCenterPosX - touchPosX) < MOVE_VIEW_RADIUS + 60 && Math.abs(moveViewCenterPosY - touchPosY) < MOVE_VIEW_RADIUS + 60) {}

只要確保手指在懸浮窗的范圍內就可以觸發移動了,這里的60是為了確保你的手指太大,或者移動得比較快時超出了懸浮窗區域依然可以觸發拖動,這個可以自己設定數值。

這個方案在理論上很合理,并且還加上了60這個緩沖區域,但是實際在拖動的時候你仍然會面臨下面三個問題:

1.如果懸浮窗下方有滾動區域,那么拖動的時候就會滾動頁面,效果會顯得比較奇怪。
2.實際移動沒法移動太順暢,只能拖著懸浮窗亦步亦趨,要不然很容易超過60這個緩沖區域,導致拖動不繼續觸發。
2.如果將緩沖區域設置過大,那么又會出現一種比較奇怪的場景:明明不準備拖動懸浮窗,只是準備滑動頁面,懸浮窗卻跳到自己手指這里了。

進階解決方案:禁止冒泡的拖動 + 理論方案

這個解決方案基于我們的最初方案,并且使用我們的理論方案作為補充。

先上代碼:

index.wxml:<view bindtouchmove="handleSetMoveViewPos"> <view class="move-view" style=" top:{{top}}px;left:{{left}}px;" bindtap="goToHome" catchtouchmove="handleTouchMove">  <image class="img" src="https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=4294841024,3545417298&fm=179&app=42&f=PNG?w=56&h=56">  </image> </view> <textarea placeholder='我是textarea組件,用來輸入一些信息'></textarea> <view>  一大段test,占個位,表示下存在感 </view></view>index.js:Page({ /** * 頁面的初始數據 */ data: { left: 20, top: 250 }, /** * 拖拽移動(補丁) */ handleSetMoveViewPos: function (e) { const MOVE_VIEW_RADIUS = 30 // 懸浮窗半徑 const touchPosX = e.touches[0].clientX const touchPosY = e.touches[0].clientY const moveViewCenterPosX = this.data.left + MOVE_VIEW_RADIUS const moveViewCenterPosY = this.data.top + MOVE_VIEW_RADIUS // 確保手指在懸浮窗上才可以移動 if (Math.abs(moveViewCenterPosX - touchPosX) < MOVE_VIEW_RADIUS+30 && Math.abs(moveViewCenterPosY - touchPosY) < MOVE_VIEW_RADIUS+30 ) {  if (touchPosX > 0 && touchPosY > 0) {  this.setData({   left: touchPosX - MOVE_VIEW_RADIUS,   top: touchPosY - MOVE_VIEW_RADIUS  })  } else {  this.setData({   left: 20, // 默認顯示位置 left距離   top: 250 // 默認顯示位置 top距離  })  } } }, /** * 拖拽移動 */ handleTouchMove: function (e) { const MOVE_VIEW_RADIUS = 30 // 懸浮窗半徑 const touchPosX = e.touches[0].clientX const touchPosY = e.touches[0].clientY if (touchPosX > 0 && touchPosY > 0) {  this.setData({  left: touchPosX - MOVE_VIEW_RADIUS,  top: touchPosY - MOVE_VIEW_RADIUS  }) } else {  this.setData({  left: 20, //默認顯示位置 left距離  top: 250 //默認顯示位置 top距離  }) } }, /** * 返回首頁 */ goToHome: () => { wx.reLaunch({  url: '/pages/index/index', }) }})

這個方案的核心點在于:catchtouchmove="handleTouchMove" 。

當我們正常拖動懸浮窗時,通過catchtouchmove,我們可以捕獲在懸浮窗上的滑動事件,并且不冒泡到父元素,那么我們綁在父層級的滑動事件就不會觸發。

而當我們拖動在原生組件之上的懸浮窗時,因為點不到這個懸浮窗,就不會觸發handleTouchMove函數,只會觸發綁定在父元素上的handleSetMoveViewPos函數。

另外如果你細心的話,就會發現在handleSetMoveViewPos函數這里我縮小了那個60的緩沖區域為30,這樣做的目的是因為觸發這個函數只會在原生組件上,所以多番權衡距離之后,盡量避免近距離滑動操作就觸發拖動懸浮框。

通過我們的方案,我們可以在非原生組件上自由拖動,在原生組件上比較順暢地拖動。

本來我是準備將這個方案作為最終方案的,但是ios下,懸浮窗在原生組件上時,在父元素上的滑動事件竟然不觸發。

棋差一招,棋差一招??!

最終解決方案:更多的補丁,更多的快樂

這個最終解決方案,當然是把我們之前所有的補丁方案全部結合起來。

代碼如下:

index.wxml:<view bindtouchmove="handleSetMoveViewPos"> <view wx-if="{{!isIos}}" class="move-view" style=" top:{{top}}px;left:{{left}}px;" bindtap="goToHome" catchtouchmove="handleTouchMove">  <image class="img" src="https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=4294841024,3545417298&fm=179&app=42&f=PNG?w=56&h=56">  </image> </view> <cover-view wx-if="{{isIos}}" class="move-view" style=" top:{{top}}px;left:{{left}}px;" bindtap="goToHome" catchtouchmove="handleTouchMove">  <cover-image class="img" src="https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=4294841024,3545417298&fm=179&app=42&f=PNG?w=56&h=56">  </cover-image> </cover-view> <textarea placeholder='我是textarea組件,用來輸入一些信息'></textarea> <view>  一大段test,占個位,表示下存在感 </view></view>index.js:Page({ /** * 頁面的初始數據 */ data: { left: 20, top: 250, isIos: true }, /** * 生命周期函數--監聽頁面加載 */ onLoad: function (options) { wx.getSystemInfo({  success: (res) => {  if (res.platform == "android") {   this.setData({   isIos: false   })  }  } }) }, /** * 拖拽移動(補丁) */ handleSetMoveViewPos: function (e) { // 在ios下永遠都不會走這個方案,以免引起無用的計算 if (!ios) {  const MOVE_VIEW_RADIUS = 30 // 懸浮窗半徑  const touchPosX = e.touches[0].clientX  const touchPosY = e.touches[0].clientY  const moveViewCenterPosX = this.data.left + MOVE_VIEW_RADIUS  const moveViewCenterPosY = this.data.top + MOVE_VIEW_RADIUS  // 確保手指在懸浮窗上才可以移動  if (Math.abs(moveViewCenterPosX - touchPosX) < MOVE_VIEW_RADIUS && Math.abs(moveViewCenterPosY - touchPosY) < MOVE_VIEW_RADIUS) {  if (touchPosX > 0 && touchPosY > 0) {   this.setData({   left: touchPosX - MOVE_VIEW_RADIUS,   top: touchPosY - MOVE_VIEW_RADIUS   })  } else {   this.setData({   left: 20, // 默認顯示位置 left距離   top: 250 // 默認顯示位置 top距離   })  }  } } }, /** * 拖拽移動 */ handleTouchMove: function (e) { const MOVE_VIEW_RADIUS = 30 // 懸浮窗半徑 const touchPosX = e.touches[0].clientX const touchPosY = e.touches[0].clientY if (touchPosX > 0 && touchPosY > 0) {  this.setData({  left: touchPosX - MOVE_VIEW_RADIUS,  top: touchPosY - MOVE_VIEW_RADIUS  }) } else {  this.setData({  left: 20, //默認顯示位置 left距離  top: 250 //默認顯示位置 top距離  }) } }, /** * 返回首頁 */ goToHome: () => { wx.reLaunch({  url: '/pages/index/index', }) }})

這個最終解決方案在ios下直接使用cover-view來做懸浮窗,而在android的非原生組件上移動時,使用view來做懸浮窗,不冒泡滑動事件,在原生組件上移動時捕獲冒泡的滑動事件來繼續移動操作。

總結

雖然問題解決了,但是這仍然只是一個補丁方案。

最好的方式依然是微信小程序官方能修復cover-view在安卓移動時的BUG,但是我發現最早有人反饋這個問題是在2018年11月,到了現在2019年8月都沒有結果。

如果不是微信小程序的官方態度有問題,那么只能說明這個問題的解決確實有難度或者優先級并不高,無論是哪一種,暫時都還是得用補丁方案。

這個方案并沒有那么完美,他在一些邊界的銜接上面可能還是會存在一些小問題,但它至少可用,并且應該是大多數用戶可以接受的。

以上所述是小編給大家介紹的微信小程序中懸浮窗功能的實現 ,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VEVB武林網網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
xvideos成人免费中文版| 久久精品国产亚洲一区二区| 久久久电影免费观看完整版| 亚洲欧美在线播放| 55夜色66夜色国产精品视频| 成人午夜在线影院| 亚洲午夜精品久久久久久性色| 久久免费视频在线观看| 欧美日韩免费区域视频在线观看| 亚洲电影免费观看高清完整版在线| 欧美有码在线观看视频| 久久久久免费精品国产| 中文字幕在线日韩| 亚洲天堂男人天堂| 国产精品99久久久久久www| 奇米4444一区二区三区| 欧美午夜激情视频| 亚洲欧美成人在线| 亚洲精品成a人在线观看| 日韩精品免费电影| 午夜精品国产精品大乳美女| 成人国产在线激情| 国产在线播放不卡| 国产精品99导航| 欧美裸体视频网站| 538国产精品一区二区免费视频| 91精品国产九九九久久久亚洲| 久久欧美在线电影| 国产精品人成电影在线观看| 日韩av一卡二卡| 日韩av在线免费| 国产精品一区二区三区免费视频| 亚洲人成人99网站| 日韩欧美在线视频日韩欧美在线视频| 久久成人免费视频| 亚洲国产免费av| 96sao精品视频在线观看| 亚洲美女在线观看| www.久久草.com| 久久久久久九九九| 国产成人综合亚洲| 国产视频久久网| 亲子乱一区二区三区电影| 中文字幕在线观看亚洲| 国产精品久久久久久av福利| 亚洲综合在线做性| 九色精品美女在线| 美女福利视频一区| 久久久精品久久| 欧美精品在线免费观看| 国产精品视频白浆免费视频| 2020欧美日韩在线视频| 日韩免费在线免费观看| 亚洲国产欧美一区二区三区同亚洲| 成人黄色免费片| 亚洲最大成人免费视频| 国产成人精品久久| 久久伊人精品天天| 正在播放国产一区| 欧美一区二粉嫩精品国产一线天| 亚洲女人被黑人巨大进入al| 亚洲精品白浆高清久久久久久| 日日骚av一区| 日韩中文字幕在线视频| 午夜精品久久久久久久男人的天堂| 日韩美女在线观看一区| 日韩精品免费在线视频| 国产日产欧美a一级在线| 亚洲男女自偷自拍图片另类| 国产经典一区二区| 欧美日韩一区二区免费在线观看| 久久综合伊人77777蜜臀| 欧美日韩一区二区在线播放| 久久成人亚洲精品| 日本精品性网站在线观看| 亚洲欧洲激情在线| 91久热免费在线视频| 国产精品丝袜一区二区三区| 日韩免费观看在线观看| 91亚洲精华国产精华| 91精品综合久久久久久五月天| 91免费高清视频| 精品国产视频在线| 亚洲系列中文字幕| 国产欧美欧洲在线观看| 日韩一区视频在线| 欧美一区二区影院| 久久精品国产一区二区电影| 日韩欧美亚洲一二三区| 精品国产一区二区在线| 久久精品中文字幕| 亚洲视频网站在线观看| 亚洲跨种族黑人xxx| 精品亚洲夜色av98在线观看| 日本精品一区二区三区在线| 亚洲国产精品va在线| 久久精品91久久久久久再现| 综合国产在线视频| 国产精品成人av性教育| 欧美华人在线视频| 国产成人精品优优av| 美日韩精品视频免费看| 亚洲精品福利在线观看| 亚洲一级片在线看| 国产在线拍揄自揄视频不卡99| 欧美午夜视频在线观看| 欧美日韩加勒比精品一区| 欧美在线欧美在线| 国内精品久久久久影院 日本资源| 中文字幕少妇一区二区三区| 国产一区二区三区在线| 亚洲欧美国产另类| 国产欧美日韩视频| 26uuu另类亚洲欧美日本老年| 欧美成人免费全部观看天天性色| 亚洲精品小视频| 555www成人网| 欧美日韩在线视频首页| 国产欧美日韩精品在线观看| 日韩欧美视频一区二区三区| 黑人精品xxx一区| 国内精品视频在线| 欧美黑人极品猛少妇色xxxxx| 亚洲成人中文字幕| 中文字幕精品久久久久| 午夜精品在线观看| 九九热这里只有精品免费看| 亚洲天堂av在线免费| 国产成人福利视频| 欧美在线视频播放| 国产99久久精品一区二区 夜夜躁日日躁| 91av免费观看91av精品在线| 一区二区国产精品视频| 日本久久中文字幕| 国产欧美va欧美va香蕉在| 国产一区二区三区网站| 亚洲国产美女久久久久| 少妇精69xxtheporn| 久久91亚洲精品中文字幕| 国产97在线|日韩| 国产精品视频资源| 亚洲性av网站| 欧美激情精品在线| 久久中文字幕国产| 91产国在线观看动作片喷水| 综合网日日天干夜夜久久| 国产精品久久久久久久电影| 亚洲女同性videos| 久久综合网hezyo| 成人久久一区二区三区| 97视频在线观看免费高清完整版在线观看| 欧美性做爰毛片| 在线播放日韩精品| 欧美最猛性xxxxx亚洲精品| 久久久久久久网站| 日韩av在线直播| 国产欧美 在线欧美| 精品欧美一区二区三区| 不卡毛片在线看| 国产精品爽爽ⅴa在线观看| 亚洲精品自拍视频| 免费av在线一区| 欧美精品九九久久| 亚洲最大在线视频|