未加星标

vue移动端UI框架实现QQ侧边菜单组件

字体大小 | |
[前端(javascript) 所属分类 前端(javascript) | 发布者 店小二03 | 时间 | 作者 红领巾 ] 0人收藏点击收藏

最近面试发现很多前端程序员都从来没有写过插件的经验,基本上都是网上百度。所以打算写一系列文章,手把手的教一些没有写过组件的兄弟们如何去写插件。本系列文章都基于VUE,核心内容都一样,会了之后大家可以快速的改写成react、angular或者是小程序等组件。这篇文章是第一篇,写的是一个类似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" :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事件处理函数,事件的逻辑如下:

手指按下瞬间,记录下当前手指所触摸的点,以及当前主容器的位置
手指移动的时候,获取到移动的点的位置
计算当前手指所在点移动的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加速,提升动画流畅度。最终代码如下:

<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侧边菜单组件,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!


您可能感兴趣的文章:基于VUE.JS的移动端框架Mint UI的使用浅谈基于Vue.js的移动组件库cube-uiMint UI 基于 Vue.js 移动端组件库

本文前端(javascript)相关术语:javascript是什么意思 javascript下载 javascript权威指南 javascript基础教程 javascript 正则表达式 javascript设计模式 javascript高级程序设计 精通javascript javascript教程

主题: 程序员VU谢大百度定位面试
tags: gt,lt,div,move,menu,width,style,slide,class,moveX,菜单,slot,容器,oldPoint
分页:12
转载请注明
本文标题:vue移动端UI框架实现QQ侧边菜单组件
本站链接:https://www.codesec.net/view/573635.html


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 前端(javascript) | 评论(0) | 阅读(71)