国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

vue移動端UI框架實現QQ側邊菜單組件

2019-11-19 14:12:29
字體:
來源:轉載
供稿:網友

最近面試發現很多前端程序員都從來沒有寫過插件的經驗,基本上都是網上百度。所以打算寫一系列文章,手把手的教一些沒有寫過組件的兄弟們如何去寫插件。本系列文章都基于VUE,核心內容都一樣,會了之后大家可以快速的改寫成react、angular或者是小程序等組件。這篇文章是第一篇,寫的是一個類似QQ的側邊菜單組件。

效果展示

先讓大家看個效果展示,知道咱們要做的東西是個怎么樣的樣子,圖片有點模糊,大家先將就點:

開始制作

DOM結構

整體結構中應該存在兩個容器:1. 菜單容器 2. 主頁面容器;因此當前DOM結構如下:

<template> <div class="r-slide-menu"> <div class="r-slide-menu-wrap"></div> <div class="r-slide-menu-content"></div> </div></template>

為了使得菜單內容和主題內容能夠定制,我們再給兩個容器中加入兩個slot插槽:默認插槽中放置主體內容、菜單放置到menu插槽內:

<template> <div class="r-slide-menu"> <div class="r-slide-menu-wrap">  <slot name="menu"></slot> </div> <div class="r-slide-menu-content">  <slot></slot> </div> </div></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

現在開始正式的代碼編寫了,首先我們理清下交互邏輯:

  • 手指左右滑動的時候主體容器和菜單容器都跟著手指運動運動
  • 當手指移動的距離超過菜單容器寬度的時候頁面不能繼續向右滑動
  • 當手指向左移動使得菜單和頁面的移動距離歸零的時候頁面不能繼續向左移動
  • 當手指釋放離開屏幕的時候,頁面滑動如果超過一定的距離(整個菜單寬度的比例)則打開整個菜單,如果小于一定距離則關閉菜單

所以現在咱們需要在使用組件的時候能夠入參定制菜單寬度以及觸發菜單收起關閉的臨界值和菜單寬度的比例,同時需要給主體容器添加touch事件,最后我們給菜單容器和主體容器添加各自添加一個控制他們運動的style,通過控制這個style來控制容器的移動

<template> <div class="r-slide-menu"> <div class="r-slide-menu-wrap" :style="wrapStyle">  <slot name="menu"></slot> </div> <div class="r-slide-menu-content" :style="contentStyle" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend">  <slot></slot> </div> </div></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事件處理函數,事件的邏輯如下:

  1. 手指按下瞬間,記錄下當前手指所觸摸的點,以及當前主容器的位置
  2. 手指移動的時候,獲取到移動的點的位置
  3. 計算當前手指所在點移動的X、Y軸距離,如果X移動的距離大于Y移動的距離則判定為橫向運動,否則為豎向運動
  4. 如果橫向運動則判斷當前移動的距離是在合理的移動區間(0到菜單寬度)移動,如果是則改變兩個容器的位置(移動過程中阻止頁面中其他的事件觸發)
  5. 手指離開屏幕:如果累計移動距離超過臨界值則運用動畫打開菜單,否則關閉菜單
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> <div class="r-slide-menu"> <div class="r-slide-menu-wrap" :class="transitionClass" :style="wrapStyle">  <slot name="menu"></slot> </div> <div class="r-slide-menu-content" :class="transitionClass" :style="contentStyle"  @touchstart="touchstart"  @touchmove="touchmove"  @touchend="touchend">  <slot></slot> </div> </div></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側邊菜單組件,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 乐平市| 濮阳县| 尤溪县| 山阳县| 宁明县| 凌源市| 宁波市| 隆回县| 临夏市| 阳西县| 安仁县| 永寿县| 昭平县| 永靖县| 石首市| 广汉市| 遂溪县| 四会市| 清远市| 孟村| 凌云县| 射洪县| 千阳县| 阳信县| 广水市| 宁阳县| 饶阳县| 汉寿县| 信丰县| 汶上县| 塔城市| 镇坪县| 嘉鱼县| 茌平县| 黑河市| 宁波市| 修文县| 吉木乃县| 江西省| 中牟县| 裕民县|