使用vue制作FullPage页面滚动效果


Posted in Javascript onAugust 21, 2017

前言

已经有好久没有更新博客了,大三下了要准备找实习了,才发现自己很多东西都不会,所以赶紧找了个现在流行的MVVM框架学习一下。我学习的是Vue,所以拿Vue写了一个FullPage的模板,可以供自己和其他人使用。

项目的地址是:https://github.com/hzxszsk/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需要对页面进行切换控制,因此需要两个属性:

  • 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"
:style="{background:options.background,color:options.color||'#fff'}" 
: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'}" @click="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(_this.nextIndex);
 } 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页面的总体流程,将主要的逻辑重新顺理了一遍,还有一些小的细节没有写在文章中,有兴趣的可以去具体的项目页面看源码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery load方法用法集锦
Dec 06 Javascript
jquery动画4.升级版遮罩效果的图片走廊--带自动运行效果
Aug 24 Javascript
深入理解JavaScript系列(17):面向对象编程之概论详细介绍
Mar 04 Javascript
移动Web中图片自适应的两种JavaScript解决方法
Jun 18 Javascript
js实现的简单radio背景颜色选择器代码
Aug 18 Javascript
JQuery.validate在ie8下不支持的快速解决方法
May 18 Javascript
jquery遍历table的tr获取td的值实现方法
May 19 Javascript
jQuery实现表格元素动态创建功能
Jan 09 Javascript
一步步教你利用Canvas对图片进行处理
Sep 19 Javascript
浅谈vux之x-input使用以及源码解读
Nov 04 Javascript
微信小程序使用setData修改数组中单个对象的方法分析
Dec 30 Javascript
解决vue无法侦听数组及对象属性的变化问题
Jul 17 Javascript
详解Layer弹出层样式
Aug 21 #Javascript
JS数组操作之增删改查的简单实现
Aug 21 #Javascript
JS实现评价的星星功能
Aug 20 #Javascript
详解A标签中href=&quot;&quot;的几种用法
Aug 20 #Javascript
Cropper.js 实现裁剪图片并上传(PC端)
Aug 20 #Javascript
Bootstrap 模态框(Modal)带参数传值实例
Aug 20 #Javascript
mui 打开新窗口的方式总结及注意事项
Aug 20 #Javascript
You might like
php下用GD生成生成缩略图的两个选择和区别
2007/04/17 PHP
PHP STRING 陷阱原理说明
2010/07/24 PHP
php中使用DOM类读取XML文件的实现代码
2011/12/14 PHP
php.ini中的request_order推荐设置
2015/05/10 PHP
TP5框架页面跳转样式操作示例
2020/04/05 PHP
javascript 单例/单体模式(Singleton)
2011/04/07 Javascript
jQuery EasyUI API 中文文档 - Pagination分页
2011/09/29 Javascript
js截取固定长度的中英文字符的简单实例
2013/11/22 Javascript
jquery validate添加自定义验证规则(验证邮箱 邮政编码)
2013/12/04 Javascript
js代码实现的加入收藏效果并兼容主流浏览器
2014/06/23 Javascript
js获取元素相对窗口位置的实现代码
2014/09/28 Javascript
js cookie实现记住密码功能
2017/01/17 Javascript
react.js 翻页插件实例代码
2017/01/19 Javascript
javascript 正则表达式去空行方法
2017/01/24 Javascript
深入理解ES6中let和闭包
2018/02/22 Javascript
基于mpvue的小程序项目搭建的步骤
2018/05/22 Javascript
vue单文件组件lint error自动fix与styleLint报错自动fix详解
2019/01/08 Javascript
JS学习笔记之数组去重实现方法小结
2019/05/29 Javascript
JavaScript字符串处理常见操作方法小结
2019/11/15 Javascript
我所理解的JavaScript中的this指向
2020/09/04 Javascript
[01:03:38]2014 DOTA2国际邀请赛中国区预选赛5.21 CNB VS CIS
2014/05/22 DOTA
[01:28:56]2014 DOTA2华西杯精英邀请赛 5 24 CIS VS DK
2014/05/26 DOTA
PyCharm安装第三方库如Requests的图文教程
2018/05/18 Python
python计算列表内各元素的个数实例
2018/06/29 Python
Django如何防止定时任务并发浅析
2019/05/14 Python
Python操控mysql批量插入数据的实现方法
2020/10/27 Python
css3实现背景颜色渐变让图片不再是唯一的实现方式
2012/12/18 HTML / CSS
男方父母证婚词
2014/01/12 职场文书
《将心比心》教学反思
2014/04/08 职场文书
珍爱生命演讲稿
2014/05/10 职场文书
小学生放飞梦想演讲稿
2014/08/26 职场文书
2014年药品销售工作总结
2014/12/16 职场文书
公司规章制度范本
2015/08/03 职场文书
幼儿园2016年圣诞活动总结
2016/03/31 职场文书
Redis模仿手机验证码发送的实现示例
2021/11/02 Redis
SQL中去除重复数据的几种方法汇总(窗口函数对数据去重)
2023/05/08 MySQL