這篇文章主要介紹了vue行動端UI框架實現仿qq側邊選單元件,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
最近面試發現很多前端程式設計師都從來沒有寫過插件的經驗,基本上都是網路百度。所以打算寫一系列文章,手把手的教一些沒有寫過組件的兄弟們如何去寫插件。本系列文章都基於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>此時我們就得到了兩個絕對定位的容器
javascript
現在開始正式的程式碼編寫了,首先我們理清下交互邏輯:<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事件處理函數,事件的邏輯如下:
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加速,提升動畫流暢度。最終程式碼如下:
<template> <p class="r-slide-menu"> <p class="r-slide-menu-wrap" :class="transitionClass" :style="wrapStyle"> <slot name="menu"></slot> </p> <p class="r-slide-menu-content" :class="transitionClass" :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) { 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>上面是我整理給大家的,希望今後會對大家有幫助。 相關文章:
##
以上是利用vue行動裝置UI框架如何實現QQ側邊選單(詳細教學)的詳細內容。更多資訊請關注PHP中文網其他相關文章!