记录前端菜鸟的日常——小程序内嵌H5页面自定义分享按钮

一个新的小需求,客户想把某一个页面(在H5里写的)的右上角的三个点分享禁掉,改成用悬浮在页面某个位置且可拖动的按钮进行分享

我之前只知道两种方式可以进行分享:onShareAppMessage和button按钮上的open-type="share"

一、自定义分享按钮

最开始想的是h5来写这个按钮,然后向小程序原生用postMessage发送消息,小程序进行监听并且触发分享,但是后来发现监听完之后也只能是修改消息内容,并不能触发分享事件,然后我就想在小程序原生里把按钮给加上,用open-type="share"的方式

如果是直接写的话都会被webview的优先级把页面写的内容都覆盖掉

h5的页面使用webview内嵌进来的,问了chat和看一位大佬的文章了解到cover-view组件优先级比webview要高https://blog.csdn.net/m0_47791238/article/details/133789009?ops_request_misc=%257B%2522request%255Fid%2522%253A%25229557455c43ea01001c42aa6e36b05764%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=9557455c43ea01001c42aa6e36b05764&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-1-133789009-null-null.142^v102^pc_search_result_base4&utm_term=cover-view%E5%92%8Cwebview&spm=1018.2226.3001.4187

cover-view功能描述:

这里面还能写button真是天助我也,不过需要注意cover-view的样式我本来用的是absolute结果真机调试的时候不出现,用了fixed才好,不过fixed也是不影响按钮拖动的(本地看不见按钮必须真机调试)

二、按钮拖动效果

按钮出现之后就是拖动功能了,先上代码

wxml:

复制代码
<view>
  <web-view src="{{currentDetailUrl}}" bindmessage="handleWebviewMessage"></web-view>
  <cover-view 
    class="draggable-btn" 
    style="left: {{btnLeft}}px; top: {{btnTop}}px;"
    bindtouchstart="onTouchStart"
    bindtouchmove="onTouchMove"
    bindtouchend="onTouchEnd"
  >
    <button class="text" open-type="share">分享</button>
  </cover-view>
</view>

js:

复制代码
data: {
    // 初始位置(单位:px)
    btnLeft: 30,   // 距离左边
    btnTop: 100,   // 距离顶部
    // 当前拖动状态
    startX: 0,
    startY: 0,
    isMoving: false
  },
// 触摸开始
onTouchStart(e) {
  const { clientX, clientY } = e.touches[0];
  this.setData({
    startX: clientX - this.data.btnLeft,
    startY: clientY - this.data.btnTop,
    isMoving: true
  });
},

// 触摸移动
onTouchMove(e) {
  if (!this.data.isMoving) return;

  if (this.throttle) return;
  this.throttle = true;

  setTimeout(() => {
    this.throttle = false;
  }, 16);

  const { clientX, clientY } = e.touches[0];
  let left = clientX - this.data.startX;
  let top = clientY - this.data.startY;

  const { windowWidth, windowHeight } = wx.getSystemInfoSync();
  const btnWidth = 60;
  const btnHeight = 40;

  left = Math.max(10, Math.min(left, windowWidth - btnWidth - 10));
  top = Math.max(80, Math.min(top, windowHeight - btnHeight - 10));

  this.setData({
    btnLeft: left,
    btnTop: top
  });
},

// 触摸结束
onTouchEnd() {
  this.setData({
    isMoving: false
  });
},

  onLoad(options) {
    // wx.hideShareMenu()
    this.setData({
      btnLeft: 30,
      btnTop: 100
    });

我画了一个图片帮助理解,字不好看不过应该能看懂

这里的30和100都是初始按钮所在的位置,e.touches[0]是第一个触摸点,这个点能拿到手指与手机左上角的距离,分别一减就是手指与按钮左上角的距离,拿到这个距离之后按钮就能跟着你手指头跑了,只要能拿到你手指头距离左上角,我就可以计算出按钮应该top多少、left多少

这里还需要注意不要让按钮超出手机可视区域,得到手机视宽/高

left = Math.max(10, Math.min(left, windowWidth - btnWidth - 10));

top = Math.max(80, Math.min(top, windowHeight - btnHeight - 10));

以left为例,这句代码是让按钮位于距左侧10到windowWidth-btnWidth-10之间,如果在中间的话,left是多少就是多少(10是为了美观,不让按钮那么贴边)

这样做完之后性能不太好,移动按钮的时候会卡顿,我让chat帮我做了下优化用节能锁不频繁赋值但是效果不大,cover-view可包含的标签太少,高级组件不能用,所以性能方面先这样

最后就是我本来疑问e.touches[0]为什么一直是0,我以为第二次触摸的话就是1,后来搜了一下知道n的意思是同时有多少根手指在屏幕上移动,所以这里就一直是0

撒花~

(做完之后还被领导夸了,因为上一个离职的同事说不能在这页自定义按钮分享领导以为不能实现,小小开心一下继续加油!)