中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

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

發布時間:2021-08-02 10:08:14 來源:億速云 閱讀:176 作者:小新 欄目:web開發

這篇文章主要為大家展示了“vue移動端UI框架如何實現QQ側邊菜單組件”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“vue移動端UI框架如何實現QQ側邊菜單組件”這篇文章吧。

效果展示

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

vue移動端UI框架如何實現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" :>
  <slot name="menu"></slot>
 </div>
 <div class="r-slide-menu-content" :
 @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" :>
  <slot name="menu"></slot>
 </div>
 <div class="r-slide-menu-content" :class="transitionClass" :
  @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側邊菜單組件”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

武冈市| 宝鸡市| 岳池县| 台南市| 邳州市| 石门县| 会泽县| 特克斯县| 建瓯市| 屏山县| 宝兴县| 鹤庆县| 潞城市| 全椒县| 耒阳市| 卫辉市| 遂川县| 合水县| 金溪县| 吐鲁番市| 老河口市| 无为县| 海阳市| 镇平县| 兴文县| 古蔺县| 桃园县| 盖州市| 锡林浩特市| 石屏县| 宜都市| 东至县| 晋中市| 赞皇县| 江孜县| 上思县| 台前县| 德惠市| 洛川县| 大余县| 宣威市|