vue-router 手勢滑動觸發返回


   vue-router的路由變換只存在“變換前”和“變換后”,不存在“切換中”的狀態,所以做不到大多數app(微信那樣的)在滑動過程中讓界面跟隨手指移動。但滑動事件還是可以監聽的,我們可以在滑動之后再觸發路由回退事件。

  微博的滑動返回基本上就是這樣的原理:先滑動、再觸發返回事件,但用起來很是怪異,有嚴重的滯后感。誇克瀏覽器做的就比較好:一是滑動時界面雖然不動,但是界面上有小圖標提示,能讓用戶接受到反饋;二是返回過程很快,沒有多余的過渡動畫。

  app.vue文件如下:

  1 <template>
  2     <div id="app" v-on:touchstart="bodyTouchStart" v-on:touchmove="bodyTouchMove" v-on:touchend="bodyTouchEnd">
  3         <transition :name="direction">
  4             <keep-alive include="home">
  5                 <router-view class="appView"></router-view>
  6             </keep-alive>
  7         </transition>
  8     </div>
  9 </template>
 10 
 11 <script>
 12 var swidth = document.documentElement.clientWidth;
 13 
 14 export default {
 15     name: 'app',
 16     data: () => ({
 17         // direction 頁面切換的過渡動畫,配合transition組件使用
 18         direction: "slide-left",
 19         // touchLeft 划動起點界限,起點在靠近屏幕左側時才有效
 20         touchLeft: swidth*2/5,
 21         // touchStartPoint 記錄起始點X坐標
 22         touchStartPoint: 0,
 23         // distance 記錄划動的距離
 24         distance: 0,
 25         // 回退按鈕的dom,根據頁面上是否存在此dom來判斷該路由是否可回退
 26         backBtn: null
 27     }),
 28 
 29     watch: {
 30         // 監聽路有變化,決定頁面過渡動畫
 31         $route(to, from) {
 32             if (from.name == "login" || from.path.indexOf("home") > -1) {
 33                 this.direction = "slide-left";
 34             } else if (to.path.indexOf("home") > -1) {
 35                 this.direction = "slide-right";
 36             } else {
 37                 const toDepth = to.path.split("/").length;
 38                 const fromDepth = from.path.split("/").length;
 39                 this.direction = toDepth < fromDepth ? "slide-right" : "slide-left";
 40             }
 41         }
 42     },
 43 
 44     methods: {
 45         bodyTouchStart: function(event) {
 46             this.backBtn = document.getElementById("navback");
 47             if (this.backBtn) {
 48                 // 獲得起點X坐標,初始化distance為0
 49                 this.touchStartPoint = event.targetTouches[0].pageX;
 50                 this.distance = 0;
 51             }
 52         },
 53         bodyTouchMove: function(event) {
 54             if (this.backBtn && this.touchStartPoint < this.touchLeft) {
 55                 // 只監聽單指划動,多指划動不作響應
 56                 if (event.targetTouches.length > 1) {
 57                     return;
 58                 }
 59                 // 實時計算distance
 60                 this.distance = event.targetTouches[0].pageX - this.touchStartPoint;
 61                 // 根據distance在頁面上做出反饋。這里演示通過返回按鈕的背景變化作出反饋
 62                 if (this.distance > 0 && this.distance < 100) {
 63                     this.backBtn.style.backgroundPosition = ((this.distance - 100) / 100) * 50 + "px 0";
 64                 } else if (this.distance >= 100) {
 65                     this.backBtn.style.backgroundPosition = "0 0";
 66                 } else {
 67                     this.backBtn.style.backgroundPosition = "-50px 0";
 68                 }
 69             }
 70         },
 71         bodyTouchEnd: function(event) {
 72             if (this.backBtn && this.touchStartPoint < this.touchLeft) {
 73                 // 划動結束,重置數據
 74                 this.touchStartPoint = 0;
 75                 this.backBtn.style.backgroundPosition = "-50px 0";
 76                 // 當划動距離超過100px時,觸發返回事件
 77                 if (this.distance > 100) {
 78                     // 返回前修改樣式,讓過渡動畫看起來更快
 79                     document.getElementById("app").classList.add("quickback");
 80                     this.$router.back();
 81                     setTimeout(function(){
 82                         document.getElementById("app").classList.remove("quickback");
 83                     },250)
 84                 }
 85             }
 86         }
 87     }
 88 }
 89 </script>
 90 
 91 <style>
 92 #app {
 93     -webkit-font-smoothing: antialiased;
 94     -moz-osx-font-smoothing: grayscale;
 95     width: 100%;
 96     overflow-x: hidden;
 97 }
 98 .appView {
 99     position: absolute;
100     width: 100%;
101     background: #fff;
102     min-height: 100vh;
103     transition: transform 0.24s ease-out;
104 }
105 #app.quickback .appView{
106     transition-duration: 0.1s;
107 }
108 .slide-left-enter {
109     transform: translate(100%, 0);
110 }
111 .slide-left-leave-active {
112     transform: translate(-50%, 0);
113 }
114 .slide-right-enter {
115     transform: translate(-50%, 0);
116 }
117 .slide-right-leave-active {
118     transform: translate(100%, 0);
119 }
120 </style>

 

 代碼案例見 https://github.com/yource/VueSPA


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM