這次為大家帶來vue行動裝置的UI框架實作側邊選單外掛程式效果,vue行動裝置的UI框架實作側邊選單外掛程式的注意事項有哪些,以下就是實戰案例,一起來看一下。
最近面試發現很多前端程式設計師從來沒有寫過外掛的經驗,基本上都是網路百度。所以打算寫一系列文章,手把手的教一些沒有寫過組件的兄弟們如何去寫插件。本系列文章都基於VUE,核心內容都一樣,會了之後大家可以快速的改寫成react、angular或是小程式等元件。這篇文章是第一篇,寫的是一個類似QQ的側邊選單元件。
開始製作
DOM結構
# 整體架構中應該存在兩個容器:1. 選單容器 2. 主頁面容器;因此目前DOM結構如下:
<template> <p class="r-slide-menu"> <p class="r-slide-menu-wrap"></p> <p class="r-slide-menu-content"></p> </p> </template>
為了讓選單內容和主題內容能夠定制,我們再給兩個容器中加入兩個slot插槽:預設插槽中放置主體內容、選單放置到menu插槽內:
<template> <p class="r-slide-menu"> <p class="r-slide-menu-wrap"> <slot name="menu"></slot> </p> <p class="r-slide-menu-content"> <slot></slot> </p> </p> </template>
css樣式
# 我專案中使用了scss,程式碼如下:
<style lang="scss"> @mixin one-screen { position: absolute; left:0; top:0; width:100%; height:100%; overflow: hidden; } .r-slide-menu{ @include one-screen; &-wrap, &-content{ @include one-screen; } &-transition{ -webkit-transition: transform .3s; transition: transform .3s; } } </style>
此時我們就得到了兩個絕對定位的容器
現在開始正式的程式碼編寫了,首先我們理清下互動邏輯:
手指左右滑動的時候主體容器和選單容器都跟著手指運動動作
# 當手指移動的距離超過選單容器寬度的時候頁面不能繼續向右滑動
# 當手指向左移動使得選單和頁面的移動距離歸零的時候頁面不能繼續向左移動
當手指釋放離開螢幕的時候,頁面滑動如果超過一定的距離(整個選單寬度的比例)則打開整個選單,如果小於一定距離則關閉選單
所以現在咱們需要在使用元件的時候能夠入參定制菜單寬度以及觸發菜單收起關閉的臨界值和菜單寬度的比例,同時需要給主體容器添加touch事件,最後我們給菜單容器和主體容器添加各自添加一個控制他們運動的style,透過控制這個style來控制容器的移動
<template> <p class="r-slide-menu"> <p class="r-slide-menu-wrap" :style="wrapStyle"> <slot name="menu"></slot> </p> <p class="r-slide-menu-content" :style="contentStyle" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"> <slot></slot> </p> </p> </template> <script> export default { props: { width: { type: String, default: '250' }, ratio: { type: Number, default: 2 } }, data () { return { isMoving: false, transitionClass: '', startPoint: { X: 0, y: 0 }, oldPoint: { x: 0, y: 0 }, move: { x: 0, y: 0 } } }, computed: { wrapStyle () { let style = { width: `${this.width}px`, left: `-${this.width / this.ratio}px`, transform: `translate3d(${this.move.x / this.ratio}px, 0px, 0px)` } return style }, contentStyle () { let style = { transform: `translate3d(${this.move.x}px, 0px, 0px)` } return style } }, methods: { touchstart (e) {}, touchmove (e) {}, touchend (e) {} } }
接下來,我們來實作我們最核心的touch事件處理函數,事件的邏輯如下:
手指按下瞬間,記錄下目前手指所觸摸的點,以及目前主容器的位置
手指移動的時候,取得到移動的點的位置
# 計算目前手指所在點移動的X、Y軸距離,若X移動的距離大於Y移動的距離則判定為橫向運動,否則為垂直運動
如果橫向運動則判斷目前移動的距離是在合理的移動區間(0到選單寬度)移動,如果是則改變兩個容器的位置(移動過程中阻止頁面中其他的事件觸發)
# 手指離開畫面:如果累積移動距離超過臨界值則運用動畫開啟選單,否則關閉選單
touchstart (e) { this.oldPoint.x = e.touches[0].pageX this.oldPoint.y = e.touches[0].pageY this.startPoint.x = this.move.x this.startPoint.y = this.move.y this.setTransition() }, touchmove (e) { let newPoint = { x: e.touches[0].pageX, y: e.touches[0].pageY } let moveX = newPoint.x - this.oldPoint.x let moveY = newPoint.y - this.oldPoint.y if (Math.abs(moveX) < Math.abs(moveY)) return false e.preventDefault() this.isMoving = true moveX = this.startPoint.x * 1 + moveX * 1 moveY = this.startPoint.y * 1 + moveY * 1 if (moveX >= this.width) { this.move.x = this.width } else if (moveX <= 0) { this.move.x = 0 } else { this.move.x = moveX } }, touchend (e) { this.setTransition(true) this.isMoving = false this.move.x = (this.move.x > this.width / this.ratio) ? this.width : 0 }, setTransition (isTransition = false) { this.transitionClass = isTransition ? 'r-slide-menu-transition' : '' }
上面,這段核心程式碼中有一個setTransition 函數,這個函數的作用是在手指離開的時候給容器元素添加transition屬性,讓容器有一個過渡動畫,完成關閉或打開動畫;所以在手指按下去的瞬間需要把容器上的這個transition屬性去除,避免滑動過程中出現容器和手指滑動延遲的不良體驗。 最後提醒下,程式碼中使用translate3d而非translate的原因是為了啟動行動手機的動畫3D加速,提升動畫流暢度。最終程式碼如下:
<script> export default { props: { width: { type: String, default: '250' }, ratio: { type: Number, default: 2 } }, data () { return { isMoving: false, transitionClass: '', startPoint: { X: 0, y: 0 }, oldPoint: { x: 0, y: 0 }, move: { x: 0, y: 0 } } }, computed: { wrapStyle () { let style = { width: `${this.width}px`, left: `-${this.width / this.ratio}px`, transform: `translate3d(${this.move.x / this.ratio}px, 0px, 0px)` } return style }, contentStyle () { let style = { transform: `translate3d(${this.move.x}px, 0px, 0px)` } return style } }, methods: { touchstart (e) { this.oldPoint.x = e.touches[0].pageX this.oldPoint.y = e.touches[0].pageY this.startPoint.x = this.move.x this.startPoint.y = this.move.y this.setTransition() }, touchmove (e) { let newPoint = { x: e.touches[0].pageX, y: e.touches[0].pageY } let moveX = newPoint.x - this.oldPoint.x let moveY = newPoint.y - this.oldPoint.y if (Math.abs(moveX) < Math.abs(moveY)) return false e.preventDefault() this.isMoving = true moveX = this.startPoint.x * 1 + moveX * 1 moveY = this.startPoint.y * 1 + moveY * 1 if (moveX >= this.width) { this.move.x = this.width } else if (moveX <= 0) { this.move.x = 0 } else { this.move.x = moveX } }, touchend (e) { this.setTransition(true) this.isMoving = false this.move.x = (this.move.x > this.width / this.ratio) ? this.width : 0 }, // 点击切换 switch () { this.setTransition(true) this.move.x = (this.move.x === 0) ? this.width : 0 }, setTransition (isTransition = false) { this.transitionClass = isTransition ? 'r-slide-menu-transition' : '' } } } </script> <style lang="scss"> @mixin one-screen { position: absolute; left:0; top:0; width:100%; height:100%; overflow: hidden; } .r-slide-menu{ @include one-screen; &-wrap, &-content{ @include one-screen; } &-transition{ -webkit-transition: transform .3s; transition: transform .3s; } } </style>
相信看了本文案例你已經掌握了方法,更多精彩請關注php中文網其它相關文章!
推薦閱讀:
以上是vue行動端的UI框架實現側邊選單插件效果的詳細內容。更多資訊請關注PHP中文網其他相關文章!