Uniapp的movable-view组件,实现悬浮可拖拽功能

页面呈现状态:

将获取文件按钮封装组件,具体代码如下:


<template>
    <movable-area class="fixed-box">
        <movable-view class="fixed-button" direction="all" :inertia="true" x="180" y="-250">
            <view class="menuBox">
                <!-- <u-icon class="mainMenu" name="plus-circle" size="140" @click="declick"></u-icon> -->
                <view class="mainMenu" @click="declick">获取文件</view>
                <view class="posi" :animation="animationData">
                    <button class="menu-btn" hover-class="hClass" open-type="contact" @click="gzwFile()">
                        <!-- <u-icon name="kefu-ermai" size="50"/> -->
                        国资委
                    </button>
                    <button class="menu-btn" hover-class="hClass" open-type="contact" @click="sjFile()">
                        <!-- <u-icon name="map" size="50" /> -->
                        上级
                    </button>
                </view>
            </view>
        </movable-view>
    </movable-area>
</template>

<script>
import request from '@/utils/request'
export default {
    data() {
        return {
            animationData: {},
            off: true,
        }
    },
    // 子组件onLoad,onShow不执行------------避坑
    methods: {
        // 悬浮按钮
        declick() {
            if (this.off) {
                //使用动画
                this.rotateAndScale()
            } else {
                this.norotateAndScale()
            }
            this.off = !this.off
        },
        //定义动画内容
        rotateAndScale() {
            var animation = uni.createAnimation({
                duration: 500,
                trmingFunction: 'ease'
            })
            this.animation = animation
            this.animation.rotate(0).translateY(-167).step();
            //导出动画数据传递给data层
            this.animationData = this.animation.export();
        },
        //当!off的时候动画回到原始位置
        norotateAndScale() {
            this.animation.rotate(0).translateY(0).step();
            this.animationData = this.animation.export();
        },
        gzwFile(){
            
        },
        sjFile(){
            
        }
    }
}
</script>

<style lang="scss" scoped>

button::after {
    border: none;
}

.menuBox {
    width: 140rpx;
    height: 100%;
    z-index: 1;
    position: relative;
    right: -2rpx;
    bottom: 0px;
    overflow: hidden;
    border-radius: 45rpx;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: row;
}

.fixed-box {
    pointer-events: none;
    width: 100vw;
    height: 100vh;
    position: fixed;
    left: 4rpx;
    bottom: 0;
    z-index: 100000;
}

.fixed-button {
    pointer-events: auto;
    width: 200rpx;
    height: 300rpx;
    right: 200rpx;
    left: auto;
    top: 70vh;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: 55rpx;
}

::v-deep .menu-btn {
    height: 40px;
    width: 170rpx;
    background-color: transparent;
    display: inline-block;
    padding-left: 0px !important;
    margin-left: 0px !important;
    font-size: 18px !important;
    color: white;
    text-align: center;
    line-height: 40px;

    &:first-child {
        margin-top: 30rpx;
    }
    // margin-top: 16rpx;
}


.mainMenu {
    width: 140rpx;
    height: 140rpx;
    position: absolute;
    left: 2rpx;
    bottom: -2rpx;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: 45rpx;
    font-size: 15px;
    background-color: #fff;
    border: 2px solid #3c9cff;
    border-radius: 45rpx;

}

.posi {
    width: 140rpx;
    height: 300rpx !important;
    position: absolute;
    left: 2rpx;
    bottom: -315rpx;
    z-index: -1;
    display: flex;
    align-items: center;
    flex-direction: column;
    background-color: #3c9cff;
    border-radius: 20rpx;
}

.posi>image {
    width: 50rpx;
    height: 50rpx;
    margin-top: 30rpx;
}

.hClass{
    background-color: red !important;
}
</style>

使用时的问题

1、uniapp中使用时为子组件,其onLoad和onShow不执行代码

2、拖动图标上方也会响应操作,这个暂未解决,有大佬愿意解决的话那就更好了

声明:此文借鉴了该文----------http://t.csdnimg.cn/Rfk4A

<think> 首先,用户查询是:"我想查找使用uniapp开发App实现全局悬浮球的方法 请问使用uniapp开发App实现全局悬浮球的方法"。这基于提供的引用内容。 引用包括: - 引用[1]:讨论在Uni-App中嵌入悬浮球全局组件,提到在App.vue中添加<HoverBall />组件- 引用[2]:使用uniappmovable-area和movable-view组件实现全局悬浮按钮,可拖动,并涉及事件穿透(pointer-events)。 - 引用[3]:关于悬浮球全局组件,提到全局消息提醒功能和使用Vue store。 用户的需求是实现全局悬浮球方法,所以我需要整合这些信息,提供一个清晰的步骤。 系统级指令: - 所有行内数学表达式必须使用$...$格式。这里可能没有数学表达式,所以可能不需要。 - 独立公式必须使用$$...$$格式并单独成段。可能不适用。 - LaTeX语法正确。确保任何数学内容正确。 - 使用中文回答。 - 生成相关问题。在回答末尾添加相关问题。 - 回答中引用的段落末尾自然地添加引用标识,如[^1]。 - 用户可见层:回答结构清晰,帮助用户逐步解决问题,保证真实可靠。 用户真正的需求是基于引用,所以我应该参考这些引用。 构建回答: 1. **引入主题**:解释全局悬浮球的作用,如快速导航、消息提醒等。 2. **方法概述**:参考引用,总结实现方法。 - 使用全局组件App.vue中添加(来自引用[1])。 - 使用movable-area和movable-view实现可拖动悬浮球(来自引用[2])。 - 涉及事件穿透(pointer-events)来避免父组件事件冲突(来自引用[2])。 - 可能用到全局状态管理如Vuex(来自引用[3])。 3. **步骤详解**:提供逐步指南。 - 步骤1: 创建悬浮组件- 步骤2: 在App.vue中全局注册和添加。 - 步骤3: 实现拖动功能- 步骤4: 处理事件穿透。 - 步骤5: 添加额外功能如消息提醒(可选)。 4. **代码示例**:从引用中提取关键代码片段。 - 引用[2]提供了movable-area和movable-view的使用。 - 确保代码格式正确。 5. **注意事项**:提到防踩坑点,如事件穿透问题(引用[1]和[2]提到)。 6. **生成相关问题**:在末尾添加相关问题部分。 确保引用标识: - 在引用内容的末尾添加[^1], [^2], [^3]。 结构回答: - 开头:简要介绍。 - 主体:分步骤解释。 - 代码块:展示组件代码。 - 结尾:注意事项和相关问题。 相关问题部分: - 生成2-3个相关问题,基于主题,如优化、性能、应用等。 完整回答大纲: 1. 介绍全局悬浮实现方法。 2. 创建悬浮组件。 3. 全局注册组件。 4. 实现拖动功能。 5. 事件穿透处理。 6. 额外功能(如消息提醒)。 7. 注意事项。 8. 相关问题。 使用中文。 </think>基于您的查询,我参考了站内引用资料,整理了使用 UniApp 开发 App 实现全局悬浮球的方法。全局悬浮球通常用于提供快捷操作(如返回首页、消息提醒等),并支持拖动功能实现的核心是使用 UniApp组件系统,结合 Vue.js 的状态管理。引用资料[^1]强调在 App.vue 中全局引入组件,引用[^2]详细说明了使用 `movable-area` 和 `movable-view` 实现拖动,并处理事件穿透问题,引用[^3]提到全局状态管理(如 Vuex)用于高级功能。下面我将分步骤解释实现方法,确保结构清晰且真实可靠。 ### 步骤详解:实现全局悬浮球 1. **创建悬浮组件(新建组件文件)** 在 UniApp 项目中,创建一个 Vue 组件(例如 `HoverBall.vue`),使用 `movable-area` 和 `movable-view` 实现悬浮球的拖动功能。关键点包括: - `movable-area` 定义拖动区域,需设置 `pointer-events: none` 允许事件穿透(避免阻塞父组件事件)。 - `movable-view` 定义悬浮球视图,需设置 `pointer-events: auto` 恢复自身事件。 - 数据绑定 `x` 和 `y` 坐标,实现拖动位置记录。 代码示例(参考引用[^2]): ```vue <template> <view> <movable-area class="movable-area"> <movable-view class="movable-view" :x="x" :y="y" direction="all"> <image src="../static/goHome.png"></image> <!-- 替换为您的悬浮球图标 --> </movable-view> </movable-area> </view> </template> <script> export default { data() { return { x: 320, // 初始 x 坐标(基于屏幕宽度调整) y: 520, // 初始 y 坐标(基于屏幕高度调整) }; } }; </script> <style lang="scss"> $all_width: 96rpx; // 悬浮球宽度 $all_height: 96rpx; // 悬浮球高度 .movable-area { height: 100vh; width: 750rpx; top: 0; position: fixed; pointer-events: none; // 关键:允许事件穿透 .movable-view { width: $all_width; height: $all_height; pointer-events: auto; // 关键:恢复悬浮球事件 image { width: $all_width; height: $all_height; } } } </style> ``` 注意:`pointer-events` 设置是防踩坑点,不加会导致父组件事件失效[^2]。 2. **全局注册并添加组件(在 App.vue 中)** 在 `App.vue` 中引入并全局使用悬浮组件,确保它出现在所有页面。引用[^1]提到直接在 App.vue 的模板中添加组件: ```vue <template> <view id="app"> <!-- 其他全局内容 --> <HoverBall /> <!-- 悬浮组件 --> </view> </template> <script> import HoverBall from '@/components/HoverBall.vue'; // 导入组件路径 export default { components: { HoverBall } }; </script> ``` 这样,悬浮球会在 App 启动时全局显示,无需每个页面单独添加[^1]。 3. **实现拖动和交互功能** - **拖动功能**:`movable-view` 的 `direction="all"` 属性支持全方向拖动,坐标 `x` 和 `y` 自动更新。 - **点击事件**:在 `movable-view` 中添加 `@click` 处理悬浮球点击,例如跳转页面或显示消息: ```vue <movable-view @click="handleClick" ...> ``` 在 `methods` 中定义 `handleClick` 方法。 - **全局状态管理**(可选):如引用[^3]所述,使用 Vuex 管理悬浮球状态(如消息提醒)。在 `store/index.js` 设置状态,然后在组件中通过 `this.$store` 访问。 4. **调试和优化** - 启动项目调试:运行 `npm run dev:app-plus` 测试悬浮球。 - 常见问题: - 事件穿透失败:检查 CSS 中的 `pointer-events` 是否设置正确[^2]。 - 位置偏移:调整 `x` 和 `y` 初始值适应不同屏幕尺寸。 - 性能优化:避免频繁状态更新,使用 `debounce` 限制拖动事件频率。 5. **添加额外功能(如消息提醒)** 参考引用[^3],结合 Vuex 实现全局消息: - 在 `store` 中定义消息状态。 - 悬浮组件监听状态变化,显示红点或数字角标。 示例代码片段: ```vue <movable-view> <image src="..."> <view v-if="$store.state.hasNewMessage" class="badge">!</view> <!-- 消息提醒 --> </movable-view> ``` ### 注意事项 - **事件穿透**:必须设置 `pointer-events: none` 和 `pointer-events: auto`,否则悬浮球会阻塞页面按钮点击[^2]。 - **兼容性**:`movable-area` 在部分 Android 设备可能有性能问题,建议测试多端。 - **全局性**:确保组件只在 App.vue 引入一次,避免重复渲染。 - 调试时,如果悬浮球不显示,检查组件路径和样式单位(使用 `rpx` 适配响应式)[^1]。 通过以上步骤,您可以高效实现一个可拖动、全局可用的悬浮球。如果有更多细节需求(如动画效果),可以基于此扩展。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值