uniapp浮动面板-movable-area

优点:拖动响应快

缺点:动画有点奇怪

TypeScript 复制代码
<script setup lang="ts">
import { computed, onMounted, ref } from "vue";

interface Props {
  /**
   * 头部高度(px)
   * 默认 50
   */
  headHeight?: number;
  /**
   * 内容高度(px)
   * 默认 300
   */
  contentHeight?: number;
  /**
   * 锚点,单位px
   * 默认为[50, 200]
   */
  anchors?: number[];
}
const props = withDefaults(defineProps<Props>(), {
  headHeight: 50,
  //   contentHeight: 300,
  //   anchors: () => [50, 200],
  contentHeight: 600,
  anchors: () => [100, 300],
});
// 屏幕显示区域高度
const maxAnchorsHeight = computed(() => {
  return Math.max(...props.anchors);
});

// 拖动区域
const dragAreaHeight = computed(() => {
  return props.contentHeight + props.headHeight + maxAnchorsHeight.value;
});

// 偏移offsetY
const offsetY = ref(0);
// 当前拖动的y
let curY = 0;
// 结束定时器
let dragEndTimer: any = null;

onMounted(() => {
  offsetY.value = getOffsetYByAnchor(Math.min(...props.anchors));
});
const getOffsetYByAnchor = (anchor: number): number => {
  const anchorHeight = maxAnchorsHeight.value;
  return anchorHeight - anchor;
};

// 管理拖动结束
const handleDragEnd = () => {
  console.log("拖动结束");
  dragEndTimer = null;
  if (curY === offsetY.value) return;
  const anchor = findNearestAnchor(getOffsetYByAnchor(curY));
  // 这里的锚点是相对于屏幕的,而offsetY是相对于拖动区域的,需要转换
  const result = getOffsetYByAnchor(anchor);
  offsetY.value = result === offsetY.value ? result - 0.01 : result;
  console.log("最终位置", offsetY.value);
};

// 鼠标松开事件
const handleTouchEnd = () => {
  if (dragEndTimer) clearTimeout(dragEndTimer);
  dragEndTimer = setTimeout(handleDragEnd, 100);
  dragEndTimer = null;
};

// 拖动中事件
const handleTouchMove = (e: any) => {
  curY = e.detail.y;
  if (!dragEndTimer) return;
  // 如果有结束定时器,说明已经拖动结束了,在做惯性动画
  // 在做惯性动画,重新开启定时器,一直没有拖动为直
  clearTimeout(dragEndTimer);
  dragEndTimer = setTimeout(handleDragEnd, 100);
  console.log("重新开启定时器");
};

// 计算最近的锚点(用于可能的自动吸附)
const findNearestAnchor = (currentY: number): number => {
  return props.anchors.reduce((prev, curr) => {
    return Math.abs(curr - currentY) < Math.abs(prev - currentY) ? curr : prev;
  });
};
</script>

<template>
  <view class="floating-panel">
    <movable-area
      class="floating-panel__drag-area"
      :style="{
        bottom: maxAnchorsHeight - dragAreaHeight + 'px',
        height: `${dragAreaHeight}px`,
      }"
    >
      <movable-view
        class="floating-panel__movable-view"
        :style="{
          height: `${props.contentHeight + props.headHeight}px`,
        }"
        :y="offsetY"
        direction="vertical"
        @touchend="handleTouchEnd"
        @change="handleTouchMove"
      >
        <view>
          <slot name="head">
            <view
              class="floating-panel__head"
              :style="{
                height: `${props.headHeight}px`,
              }"
            ></view>
          </slot>
          <view
            class="floating-panel__content"
            :style="{
              height: `${props.contentHeight}px`,
            }"
          >
            <slot></slot>
          </view>
        </view>
      </movable-view>
    </movable-area>
  </view>
</template>

<style lang="scss" scoped>
.floating-panel {
  position: fixed;
  bottom: 0;
  left: 0;
  z-index: 20;
  color: #fff;
  width: 100%;
  .floating-panel__drag-area {
    position: absolute;
    left: 0;
    bottom: 200px;
    width: 100%;
    .floating-panel__movable-view {
      width: 100%;
      background-color: pink;
    }
  }
}
</style>
相关推荐
2501_915921434 小时前
iOS App 电耗管理 通过系统电池记录、Xcode Instruments 与克魔(KeyMob)组合使用
android·ios·小程序·https·uni-app·iphone·webview
岳哥i4 小时前
vue鼠标单机复制文本
javascript
jacGJ4 小时前
记录学习--文件读写
java·前端·学习
毕设源码-赖学姐5 小时前
【开题答辩全过程】以 基于WEB的实验室开放式管理系统的设计与实现为例,包含答辩的问题和答案
前端
幻云20105 小时前
Python深度学习:从筑基到登仙
前端·javascript·vue.js·人工智能·python
我即将远走丶或许也能高飞7 小时前
vuex 和 pinia 的学习使用
开发语言·前端·javascript
钟离墨笺7 小时前
Go语言--2go基础-->基本数据类型
开发语言·前端·后端·golang
爱吃泡芙的小白白7 小时前
Vue 3 核心原理与实战:从响应式到企业级应用
前端·javascript·vue.js
卓怡学长8 小时前
m115乐购游戏商城系统
java·前端·数据库·spring boot·spring·游戏
码上成长8 小时前
JavaScript 数组合并性能优化:扩展运算符 vs concat vs 循环 push
开发语言·javascript·ecmascript