vue實(shí)現(xiàn)移動(dòng)端拖拽懸浮按鈕
本文實(shí)例為大家分享了vue實(shí)現(xiàn)移動(dòng)端拖拽懸浮按鈕的具體代碼,供大家參考,具體內(nèi)容如下
功能介紹:
在移動(dòng)端開發(fā)中,實(shí)現(xiàn)懸浮按鈕在側(cè)邊顯示,為不遮擋頁(yè)面內(nèi)容,允許手指拖拽換位。
大致需求:
1、按鈕在頁(yè)面?zhèn)冗厬腋★@示;
2、手指長(zhǎng)按按鈕,按鈕改變樣式,允許拖拽改變位置;
3、按鈕移動(dòng)結(jié)束,手指松開,計(jì)算距離左右兩側(cè)距離并自動(dòng)移動(dòng)至側(cè)邊顯示;
4、移動(dòng)至側(cè)邊后,按鈕根據(jù)具體左右兩次位置判斷改變現(xiàn)實(shí)樣式;
整體思路:
1、按鈕實(shí)行position:fixed布局,在頁(yè)面兩側(cè)最上層懸浮顯示;
2、手指長(zhǎng)按可使用定時(shí)器來(lái)判斷,若手指松開,則關(guān)閉定時(shí)器,等待下次操作再啟用;
3、跟隨手指移動(dòng)計(jì)算按鈕與頁(yè)面兩側(cè)的距離,判斷手指松開時(shí)停留的位置;
簡(jiǎn)單效果展示:



具體實(shí)現(xiàn):
一、position:fixed布局:
使用定位實(shí)現(xiàn)
<!-- 外層ul控制卡片范圍 -->
<div>
? ? <div class="floatBtn"?
? ? ? ? :class="[{moveBtn: longClick}, `${btnType}Btn`]">
? ? <span>懸浮按鈕</span>
? </div>
</div><style lang="scss" scoped>
? @mixin notSelect{
? ? -moz-user-select:none; /*火狐*/
? ? -webkit-user-select:none; /*webkit瀏覽器*/
? ? -ms-user-select:none; /*IE10*/
? ? -khtml-user-select:none; /*早期瀏覽器*/
? ? user-select:none;
? }
? @mixin not-touch {
? ? -webkit-touch-callout: none;
? ? -webkit-user-select: none;
? ? -khtml-user-select: none;
? ? -moz-user-select: none;
? ? -ms-user-select: none;
? ? user-select: none;
? }
? .floatBtn {
? ? @include notSelect;
? ? @include not-touch();
? ? position: fixed;
? ? z-index: 1;
? ? overflow: hidden;
? ? width: 100px;
? ? left: calc(100% - 100px);
? ? top: calc(100% - 100px);
? ? color: #E0933A;
? ? background: #FCEBD0;
? ? font-size: 14px;
? ? height: 36px;
? ? line-height: 36px;
? ? text-align: center;
? ? box-sizing: border-box;
? ? display: flex;
? ? justify-content: center;
? ? align-items: center;
? ? padding: 10px;
? ? &.rightBtn {
? ? ? border-radius: 20px 0 0 20px;
? ? }
? ? &.leftBtn {
? ? ? border-radius: 0 20px 20px 0;
? ? }
? ? &.moveBtn {
? ? ? border-radius: 20px;
? ? }
? }
</style>二、touch事件綁定:
應(yīng)用到touchstart,touchmove,touchend事件,使用定時(shí)器實(shí)現(xiàn)長(zhǎng)按效果:
<div class="floatBtn"
? ? :class="[{moveBtn: longClick}, `${btnType}Btn`]"
? ? @touchstart="touchstart($event)"
? ? @touchmove="touchMove($event)"
? ? @touchend="touchEnd($event)"
>
? ? <span>懸浮按鈕</span>
</div><script>
export default {
? ? data() {
? ? ? ? return {
? ? ? ? ? ? timeOutEvent: 0,
? ? ? ? ? ? longClick: 0,
? ? ? ? ? ? // 手指原始位置
? ? ? ? ? ? oldMousePos: {},
? ? ? ? ? ? // 元素原始位置
? ? ? ? ? ? oldNodePos: {},
? ? ? ? ? ? btnType: 'right'
? ? ? ? };
? ? },
? ? touchstart(ev) {
? ? ? ? // 定時(shí)器控制長(zhǎng)按時(shí)間,超過(guò)500毫秒開始進(jìn)行拖拽
? ? ? ? this.timeOutEvent = setTimeout(() => {
? ? ? ? ? ? this.longClick = 1;
? ? ? ? }, 500);
? ? ? ? const selectDom = ev.currentTarget;
? ? ? ? const { pageX, pageY } = ev.touches[0]; // 手指位置
? ? ? ? const { offsetLeft, offsetTop } = selectDom; // 元素位置
? ? ? ? // 手指原始位置
? ? ? ? this.oldMousePos = {
? ? ? ? ? ? x: pageX,
? ? ? ? ? ? y: pageY
? ? ? ? };
? ? ? ? // 元素原始位置
? ? ? ? this.oldNodePos = {
? ? ? ? ? ? x: offsetLeft,
? ? ? ? ? ? y: offsetTop
? ? ? ? };
? ? ? ? selectDom.style.left = `${offsetLeft}px`;
? ? ? ? selectDom.style.top = `${offsetTop}px`;
? ? },
? ? touchMove(ev) {
? ? ? ? // 未達(dá)到500毫秒就移動(dòng)則不觸發(fā)長(zhǎng)按,清空定時(shí)器
? ? ? ? clearTimeout(this.timeOutEvent);
? ? ? ? if (this.longClick === 1) {
? ? ? ? ? ? const selectDom = ev.currentTarget;
? ? ? ? ? ? // x軸偏移量
? ? ? ? ? ? const lefts = this.oldMousePos.x - this.oldNodePos.x;
? ? ? ? ? ? // y軸偏移量
? ? ? ? ? ? const tops = this.oldMousePos.y - this.oldNodePos.y;
? ? ? ? ? ? const { pageX, pageY } = ev.touches[0]; // 手指位置
? ? ? ? ? ? selectDom.style.left = `${pageX - lefts}px`;
? ? ? ? ? ? selectDom.style.top = `${pageY - tops}px`;
? ? ? ? }
? ? },
? ? touchEnd(ev) {
? ? ? ? // 清空定時(shí)器
? ? ? ? clearTimeout(this.timeOutEvent);
? ? ? ? if (this.longClick === 1) {
? ? ? ? ? ? this.longClick = 0;
? ? ? ? ? ? const selectDom = ev.currentTarget;
? ? ? ? ? ? const {clientWidth, clientHeight} = document.body;
? ? ? ? ? ? const {offsetLeft, offsetTop} = selectDom;
? ? ? ? ? ? selectDom.style.left =?
? ? ? ? ? ? ? ? (offsetLeft + 50) > (clientWidth / 2) ??
? ? ? ? ? ? ? ? 'calc(100% - 100px)' : 0;
? ? ? ? ? ? if (offsetTop < 90) {
? ? ? ? ? ? ? ? selectDom.style.top = '90px';
? ? ? ? ? ? } else if (offsetTop + 36 > clientHeight) {
? ? ? ? ? ? ? ? selectDom.style.top = `${clientHeight - 36}px`;
? ? ? ? ? ? }
? ? ? ? ? ? this.btnType =?
? ? ? ? ? ? ? ? (offsetLeft + 50) > (clientWidth / 2) ??
? ? ? ? ? ? ? ? 'right' : 'left';
? ? ? ? }
? ? },
};
</script>三、頁(yè)面引入:
單個(gè)頁(yè)面引入
<template> ?? ?<floatBtn/> </template>
<script>
import floatBtn from './floatBtn';
export default {
? ? components: {
? ? ? ? floatBtn
? ? },
};
</script>以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue如何監(jiān)聽頁(yè)面的滾動(dòng)的開始和結(jié)束
這篇文章主要介紹了vue如何監(jiān)聽頁(yè)面的滾動(dòng)的開始和結(jié)束,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
vue解析Json數(shù)據(jù)獲取Json里面的多個(gè)id問(wèn)題
這篇文章主要介紹了vue解析Json數(shù)據(jù)獲取Json里面的多個(gè)id問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
淺談vue+webpack項(xiàng)目調(diào)試方法步驟
本篇文章主要介紹了淺談vue+webpack項(xiàng)目調(diào)試方法步驟,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09
詳解vue服務(wù)端渲染瀏覽器端緩存(keep-alive)
在使用服務(wù)器端渲染時(shí),除了服務(wù)端的接口緩存、頁(yè)面緩存、組建緩存等,瀏覽器端也避免不了要使用緩存,減少頁(yè)面的重繪。這篇文章主要介紹了詳解vue服務(wù)端渲染瀏覽器端緩存(keep-alive),感興趣的小伙伴們可以參考一下2018-10-10
關(guān)于移動(dòng)端與大屏幕自適應(yīng)適配方案
這篇文章主要介紹了關(guān)于移動(dòng)端與大屏幕自適應(yīng)適配方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10
解決在el-dialog中無(wú)法正確獲取DOM的問(wèn)題
這篇文章主要介紹了解決在el-dialog中無(wú)法正確獲取DOM的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
Vue項(xiàng)目打包優(yōu)化實(shí)踐指南(推薦!)
如果引入的庫(kù)眾多,那么vendor.js文件體積將會(huì)相當(dāng)?shù)拇?影響首開的體驗(yàn),這篇文章主要給大家介紹了關(guān)于Vue項(xiàng)目打包優(yōu)化實(shí)踐的相關(guān)資料,需要的朋友可以參考下2022-06-06

