在 vue 中实现移动端拖拽浮窗滑动效果
随着移动端应用的普及,浮窗滑动效果成为了移动端设计中越来越常见的一种交互方式。在 vue 中,我们可以使用一些插件或自己编写代码来实现这种效果。
一、使用第三方插件
- vue-draggable
vue-draggable 是一个基于 Vue.js 的拖拽组件库,它提供了一些常见的拖拽效果,包括拖拽排序、拖拽复制、拖拽删除等。我们可以使用它来实现移动端浮窗的拖拽效果。
首先,我们需要引入 vue-draggable 的依赖:
npm install vuedraggable --save
然后,在需要使用拖拽效果的组件中,引入并注册 vue-draggable:
import draggable from 'vuedraggable'
export default {
components: {
draggable
},
data() {
return {
items: [
{ id: 1, name: 'item 1' },
{ id: 2, name: 'item 2' },
{ id: 3, name: 'item 3' },
{ id: 4, name: 'item 4' },
{ id: 5, name: 'item 5' }
]
}
}
}
接着,在模板中使用 draggable 组件来展示拖拽效果:
<template>
<draggable v-model="items">
<div v-for="item in items" :key="item.id">{{ item.name }}</div>
</draggable>
</template>
这样,我们就可以在移动端实现浮窗的拖拽效果了。
- vue-touch-ripple
vue-touch-ripple 是一个基于 Vue.js 的触摸波纹效果插件,它可以给任何元素添加触摸波纹效果。我们可以使用它来实现移动端浮窗的滑动效果。
首先,我们需要引入 vue-touch-ripple 的依赖:
npm install vue-touch-ripple --save
然后,在需要使用触摸波纹效果的组件中,引入并注册 vue-touch-ripple:
import VueTouchRipple from 'vue-touch-ripple'
export default {
directives: {
'ripple': VueTouchRipple.directive
}
}
接着,在模板中使用 ripple 指令来展示触摸波纹效果:
<template>
<div v-ripple>Content</div>
</template>
这样,我们就可以在移动端实现浮窗的滑动效果了。
二、自己编写代码
如果我们不想使用第三方插件,也可以自己编写代码来实现移动端浮窗的拖拽和滑动效果。
- 实现浮窗的拖拽效果
首先,我们需要在浮窗组件的模板中添加 touchstart、touchmove 和 touchend 事件:
<template>
<div class="float-window"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
>
Content
</div>
</template>
接着,在组件的 script 中定义 onTouchStart、onTouchMove 和 onTouchEnd 三个方法:
export default {
data() {
return {
startX: 0,
startY: 0,
offsetX: 0,
offsetY: 0,
left: 0,
top: 0
}
},
methods: {
onTouchStart(e) {
this.startX = e.touches[0].clientX
this.startY = e.touches[0].clientY
this.offsetX = this.left
this.offsetY = this.top
},
onTouchMove(e) {
const x = e.touches[0].clientX - this.startX + this.offsetX
const y = e.touches[0].clientY - this.startY + this.offsetY
const maxX = window.innerWidth - this.$refs.floatWindow.offsetWidth
const maxY = window.innerHeight - this.$refs.floatWindow.offsetHeight
this.left = x < 0 ? 0 : (x > maxX ? maxX : x)
this.top = y < 0 ? 0 : (y > maxY ? maxY : y)
},
onTouchEnd(e) {
// do nothing
}
}
}
在 onTouchStart 方法中,我们记录下触摸起始点的位置和浮窗的偏移量。在 onTouchMove 方法中,我们根据触摸移动的距离和浮窗的偏移量计算出浮窗的新位置,并限制浮窗的移动范围。在 onTouchEnd 方法中,我们暂时不做任何操作。
最后,在组件的 style 中定义浮窗的位置:
<style scoped>
.float-window {
position: fixed;
left: 0;
top: 0;
transform: translate3d(0, 0, 0);
}
</style>
这样,我们就可以在移动端实现浮窗的拖拽效果了。
- 实现浮窗的滑动效果
接着,我们需要在浮窗组件的模板中添加 touchstart、touchmove 和 touchend 事件:
<template>
<div class="float-window"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
>
Content
</div>
</template>
接着,在组件的 script 中定义 onTouchStart、onTouchMove 和 onTouchEnd 三个方法:
export default {
data() {
return {
startX: 0,
startY: 0,
offsetX: 0,
offsetY: 0,
left: 0,
top: 0,
isScrolling: false
}
},
methods: {
onTouchStart(e) {
this.startX = e.touches[0].clientX
this.startY = e.touches[0].clientY
this.offsetX = this.left
this.offsetY = this.top
this.isScrolling = false
},
onTouchMove(e) {
const x = e.touches[0].clientX - this.startX + this.offsetX
const y = e.touches[0].clientY - this.startY + this.offsetY
const maxX = window.innerWidth - this.$refs.floatWindow.offsetWidth
const maxY = window.innerHeight - this.$refs.floatWindow.offsetHeight
this.left = x < 0 ? 0 : (x > maxX ? maxX : x)
this.top = y < 0 ? 0 : (y > maxY ? maxY : y)
if (Math.abs(e.touches[0].clientX - this.startX) > 5 || Math.abs(e.touches[0].clientY - this.startY) > 5) {
this.isScrolling = true
}
},
onTouchEnd(e) {
if (!this.isScrolling) {
if (e.changedTouches[0].clientX < window.innerWidth / 2) {
this.left = 0
} else {
this.left = window.innerWidth - this.$refs.floatWindow.offsetWidth
}
}
}
}
}
在 onTouchStart 方法中,我们记录下触摸起始点的位置和浮窗的偏移量,并设置 isScrolling 标志位为 false。在 onTouchMove 方法中,我们根据触摸移动的距离和浮窗的偏移量计算出浮窗的新位置,并限制浮窗的移动范围。同时,如果触摸移动的距离超过了 5px,我们设置 isScrolling 标志位为 true。在 onTouchEnd 方法中,如果 isScrolling 标志位为 false,说明触摸是滑动而不是拖拽,我们就根据触摸结束的位置来设置浮窗的位置。
最后,在组件的 style 中定义浮窗的位置:
<style scoped>
.float-window {
position: fixed;
left: 0;
top: 0;
transform: translate3d(0, 0, 0);
transition: left 0.3s ease-out;
}
</style>
这样,我们就可以在移动端实现浮窗的滑动效果了。
举例说明
假设我们需要在移动端实现一个浮窗组件,它可以拖拽和滑动。我们可以先编写一个 FloatWindow 组件:
<template>
<div class="float-window"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
ref="floatWindow"
:style="{left: left + 'px', top: top + 'px'}"
>
<slot></slot>
</div>
</template>
<script>
export default {
data() {
return {
startX: 0,
startY: 0,
offsetX: 0,
offsetY: 0,
left: 0,
top: 0,
isScrolling: false
}
},
methods: {
onTouchStart(e) {
this.startX = e.touches[0].clientX
this.startY = e.touches[0].clientY
this.offsetX = this.left
this.offsetY = this.top
this.isScrolling = false
},
onTouchMove(e) {
const x = e.touches[0].clientX - this.startX + this.offsetX
const y = e.touches[0].clientY - this.startY + this.offsetY
const maxX = window.innerWidth - this.$refs.floatWindow.offsetWidth
const maxY = window.innerHeight - this.$refs.floatWindow.offsetHeight
this.left = x < 0 ? 0 : (x > maxX ? maxX : x)
this.top = y < 0 ? 0 : (y > maxY ? maxY : y)
if (Math.abs(e.touches[0].clientX - this.startX) > 5 || Math.abs(e.touches[0].clientY - this.startY) > 5) {
this.isScrolling = true
}
},
onTouchEnd(e) {
if (!this.isScrolling) {
if (e.changedTouches[0].clientX < window.innerWidth / 2) {
this.left = 0
} else {
this.left = window.innerWidth - this.$refs.floatWindow.offsetWidth
}
}
}
}
}
</script>
<style scoped>
.float-window {
position: fixed;
left: 0;
top: 0;
transform: translate3d(0, 0, 0);
transition: left 0.3s ease-out;
}
</style>
然后,我们可以在父组件中引入 FloatWindow 组件并使用它:
<template>
<div>
<float-window>
浮窗内容
</float-window>
</div>
</template>
<script>
import FloatWindow from './FloatWindow.vue'
export default {
components: {
FloatWindow
}
}
</script>
这样,我们就可以在移动端实现一个可以拖拽和滑动的浮窗组件了。
相关文章
Vue - An In-Depth Guide to Lifecycle Hooks
发布时间:2025/02/21 浏览次数:117 分类:Vue
-
Vue has many lifecycle hooks, and it can be confusing to understand the meaning or purpose of each one. In this article, we will explain the function of each lifecycle hook and how to use them.
Solution for Flickering During Vue Template Parsing
发布时间:2025/02/21 浏览次数:103 分类:Vue
-
Solution for Flickering During Vue Template Parsing, Recently, while working on a project, I noticed that when the internet speed is slow, the screen flickers and the expression message appears. This happens because when the internet speed i
如何在 Vue.js 中滚动到页面顶部或底部
发布时间:2023/04/03 浏览次数:508 分类:Vue
-
Vue.js 是一种流行的前端框架,它可以帮助开发者构建高效、可维护的应用程序。在Vue.js中,滚动页面到顶部或底部是一个常见的需求。在本文中,我们将介绍如何在Vue.js中实现这一功能
在 vue 中鼠标悬停时显示元素或文本
发布时间:2023/04/03 浏览次数:415 分类:Vue
-
Vue.js 是一种流行的 JavaScript 框架,可以使 Web 应用程序的开发变得更加轻松和高效。在这篇教程里,我们将学习如何利用 Vue.js 来在鼠标悬停时显示元素或文本。 本教程将涵盖以下主题
在 Vue 中watch监听一个对象时,如何排除某些属性的监听
发布时间:2023/03/31 浏览次数:858 分类:Vue
-
在 Vue 中使用 watch 时,你可能需要监听一个对象,但只关心对象中的某些属性,而不是对象的所有属性。这种情况下,你可以使用深度监听和计算属性,或者在 watch 中添加一些选项来排
在 Vue 中 watch 的 immediate 属性有什么用?
发布时间:2023/03/31 浏览次数:480 分类:Vue
-
在Vue中, watch 是一种数据变化时执行异步任务或触发响应式依赖的方式。在大多数情况下,watch 都会被默认延迟执行。这意味着,只有当所监视的值发生变化后,watch才会被触发,并且
在 Vue 中设置复选框功能
发布时间:2023/03/30 浏览次数:384 分类:Vue
-
在 Vue 中,复选框是一种非常常见的交互组件,它可以让用户选择多个选项。本文将介绍如何在 Vue 中设置复选框功能,并提供一些实际示例。 使用 v-model 指令 Vue 中的 v-model 指令可以实
在 Vue 中如果子组件改变props里的数据会发生什么
发布时间:2023/03/30 浏览次数:453 分类:Vue
-
在 Vue 中,子组件改变 props 中的数据会导致父组件和其他子组件的响应性发生变化。 首先,需要了解 props 是从父组件向子组件传递数据的一种方式。在组件中定义 props 后,父组件可以
如何在 Vue 中刷新页面
发布时间:2023/03/29 浏览次数:191 分类:Vue
-
Vue 是一个流行的 JavaScript 框架,它提供了许多便捷的工具和方法来构建 Web 应用程序。在 Vue 中,页面的更新通常是通过数据绑定和响应式系统来实现的。但是有时候需要手动刷新页面