使⽤vue制作FullPage页⾯滚动效果
前⾔
已经有好久没有更新博客了,⼤三下了要准备实习了,才发现⾃⼰很多东西都不会,所以赶紧了个现在流⾏的MVVM框架学习⼀下。我学习的是Vue,所以拿Vue写了⼀个FullPage的模板,可以供⾃⼰和其他⼈使⽤。
项⽬讲解
为了加深理解,我把我制作这个FullPage页⾯的思路和流程记录下来,也可以给其他和我⼀样的初学者⼀个参考。
分解思路
⾸先,我根据Vue的组件开发思想,把这个FullPage页⾯分为两个主要的组件模块:页⾯组件(Page)和页⾯控制组件(PageController)。除了这两个组件模块之外,还有⼀个整合的App.vue⽂件。
其中,Page组件主要负责每个FullPage页⾯的样式和位置控制,⽽PageController组件则⽤来发起页⾯的切换请求。
因为Vue是单向数据流形式的,因此将所有需要的数据都定义在App.vue⽂件中,由App组件向下传递数据。
数据需求分析
要制作⼀个FullPage页⾯,每个Page页⾯需要的是页⾯⾃⾝的内容(页⾯的内容和样式配置),⽽控制器所需要的数据有当前正在显⽰的页⾯以及总的页⾯数,⽤这两个属性计算出其他需要的属性。
其中,总页⾯数即是Page总数,有多少个Page,就有多少个Page的配置,因此可以通过计算Page配置信息对象的数量来获得总页⾯数。
我在App.vue的组件data中定义了两个属性:
currentPage表⽰的是当前页⾯的序号(从1开始计算);
options是⼀个数组,其中的每⼀个对象表⽰的是对应序号的页⾯的配置信息,可以通过修改⾥⾯的对象属性从⽽改变对应Page的样式。
Page组件只需要知道当前页⾯是第⼏个页⾯和⾃⾝的配置,因此只含有两个属性:
currentPage
option 表⽰⾃⾝的配置
PageController需要对页⾯进⾏切换控制,因此需要两个属性:
rotate属性currentPage
pageNum 表⽰总的页⾯数量
编写页⾯样式
App组件的结构为:
<div id="app" class="app">
<!-- page为单独的页⾯组件,page内可以编写任意的页⾯内容 -->
<page :currentPage="currentPage"></page>
<!-- page-controller为控制器组件 -->
<page-controller :pageNum="pageNum" :currentPage="currentPage" @changePage="changePage" :arrowsType="arrowsType"></page-controller>
</div>
App组件主要样式:
/* 页⾯宽⾼为100%,overflow为hidden隐藏溢出部分 */
html,body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
overflow: hidden;
}
.app {
height: 100%;
width: 100%;
}
Page组件结构为:
<section class="page" v-if="options"
:
:class="{'page-before': options.index < currentPage,'page-after': options.index > currentPage}">
<div :class="{'page-center': options.isCenter}">
<slot></slot>
</div>
</section>
<section class="page" v-else>页⾯正在渲染中。。。</section>
其中slot内为在App.vue的page标签内编写的html内容,并且根据Page组件内的option属性,为Page页⾯添加不同的样式(包括背景颜⾊、字体颜⾊、居中等,⽽且可以⾃由扩展)
Page组件的主要样式为:
.page {
position: absolute;
width: 100%;
height: 100%;
transition: all 0.5s ease 0s;
}
.page-before {
transform: translate3d(0,-100%,0);
}
.page-after {
transform: translate3d(0,100%,0);
}
通过⽐较当前页⾯的index与currentPage的⼤⼩,可以判断Page组件处于之前的页⾯,当前的页⾯和之后的页⾯三个状态中的哪⼀种。
将所有页⾯都⽤absolute定位在同⼀个位置上,对于处于之前的页⾯的Page,添加page-before类标签,使其在Y轴上向上偏移⾃⾝⾼度距离,同理,对之后的页⾯做Y轴上向下的⾃⾝⾼度偏移。
在page标签上添加transition样式,使其在切换时可以产⽣动画效果。
PageController组件的结构为:
<nav class="controller">
<button v-if="arrowsType != 'no'" class="prev-btn" :class="{moving:arrowsType === 'animate'}" @clic
k="changePage(prevIndex)"></button>
<ul>
<li @click="changePage(index)" v-for="index in pageNum" :key="'controller-'+index" class="controller-item"></li>
</ul>
<button v-if="arrowsType != 'no'" class="next-btn" :class="{moving:arrowsType === 'animate'}" @click="changePage(nextIndex)"></button>
</nav>
PageController组件中分为两块,控制上下滚动的上下箭头按钮和控制所有页⾯的ul列表。
因为PageController中的样式较多,因此不在⽂章中详细说明,只做简单介绍。
button和ul标签⽤fixed定位,使其处于整个页⾯的上⽅、下⽅和右侧。
button使⽤rotate和border属性,制作出箭头的样式,并添加对应的动画效果(可以通过传递props选
择关闭)。
编写页⾯逻辑
切换页⾯逻辑
因为所有的页⾯切换都是由PageController发起,⽽控制currentPage的组件并不是PageController,所以需要有⼀个⽗⼦组件事件,由⼦组件PageController发起,传递⼀个参数表⽰要切换到第⼏个页⾯,因此在PageController中定义⼀个method:
changePage (index) {
this.$emit('changePage', index);
}
⽗组件接受该事件并调⽤⾃⼰定义的changePage⽅法,修改⾃⾝的currentPage属性
changePage (index) {
// 改变page
this.currentPage = index;
}
箭头按钮上下滚动
为了实现上下滚动,需要知道当前页⾯的前⼀个页⾯和后⼀个页⾯分别是第⼏个页⾯,因此可以使⽤计算属性,计算出前⼀个和后⼀个页⾯的index值:
// PageController.vue
nextIndex () {
if (this.currentPage === this.pageNum) {
return 1;
} else {
return this.currentPage + 1;
}
},
prevIndex () {
if (this.currentPage === 1) {
return this.pageNum;
} else {
return this.currentPage - 1;
}
}
在点击箭头时,将对应的nextIndex或prevIndex值当做参数传给changePage⽅法。
滚轮滚动和移动端滚动
滚轮滚动和移动端滚动主要依靠window的监听事件,根据传⼊的event属性,计算出页⾯是应该向上还是向下滚动,将需要滚动的⽅向作为参数传递给处理函数handler。
因为代码略长,因此不全部显⽰在⽂章中,只显⽰处理函数相关逻辑
let _this = this;
let timer = null;
function scrollHandler (direction) {
// 防⽌重复触发滚动事件
if (timer != null) {
return;
}
if (direction === 'down') {
_this.changePage(_Index);
} else {
_this.changePage(_this.prevIndex);
}
timer = setTimeout(function() {
clearTimeout(timer);
timer = null;
}, 500);
}
需要注意的⼀点是,移动端做滚动判断时,要求touches和changedTouches之间需要⼀定的间隔,不然容易误触发滚动事件。
OPTIONS属性的分发
为了使使⽤者更加⽅便地编写页⾯内容⽽不在意具体的页⾯序号,我采⽤了⾃动对page内的option赋值的⽅法。其实现原理是在App.vue⽂件中,使⽤钩⼦函数mounted,对page中的option属性进⾏设置。
mounted () {
this.$children.forEach((child, index) => {
// 动态设置各个page内的options
if (child.option === null) {
let childOption = this.options[index];
this.$set(childOption,'index',index+1);
child.option = childOption;
}
});
}
⾼级属性:新的钩⼦函数
为了满⾜部分使⽤者的需求,我在设置了两个钩⼦函数:beforeLeave和afterEnter。
这两个钩⼦函数可以设置在对应页⾯的options属性对象中,并且含有⼀个默认的参数,为对应页⾯的page组件实例对象。
其实现⽅式为在原先的changePage函数(App.vue)内添加新的逻辑:
changePage (index) {
// beforeLeave
let beforeIndex = this.currentPage - 1;
let leaveFunction = this.options[beforeIndex].beforeLeave;
typeof leaveFunction === 'function' && leaveFunction.call(this,this.$children[beforeIndex]);
// 改变page
this.currentPage = index;
// afterEnter
let nextIndex = index-1;
let enterFunction = this.options[nextIndex].afterEnter;
this.$nextTick(function () {
typeof enterFunction === 'function' && enterFunction.call(this,this.$children[nextIndex]);
})
}
总结
这篇⽂章记录了我开发⼀个FullPage页⾯的总体流程,将主要的逻辑重新顺理了⼀遍,还有⼀些⼩的细节没有写在⽂章中,有兴趣的可以去具体的
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论