使用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获取文本节点之 text()/val()/html() 方法区别
Mar 01 Javascript
DB.ASP 用Javascript写ASP很灵活很好用很easy
Jul 31 Javascript
javaScript复制功能调用实现方案
Dec 13 Javascript
使用jQuery避免鼠标双击的解决方案
Aug 21 Javascript
Js 导出table内容到Excel的简单实例
Nov 19 Javascript
jquery实现select下拉框美化特效代码分享
Aug 18 Javascript
jquery.cookie实现的客户端购物车操作实例
Dec 24 Javascript
JavaScript截取、切割字符串的技巧
Jan 07 Javascript
浅谈jQuery效果函数
Sep 16 Javascript
Vue 实用分页paging实例代码
Apr 12 Javascript
详解Angular-ui-BootStrap组件的解释以及使用
Jul 13 Javascript
JavaScript获取时区实现过程解析
Sep 24 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的错误信息
2006/10/09 PHP
php实现利用phpexcel导出数据
2013/08/24 PHP
php json转换成数组形式代码分享
2014/11/10 PHP
详解WordPress中过滤链接与过滤SQL语句的方法
2015/12/18 PHP
js DOM的学习笔记
2011/12/22 Javascript
分享10个优化代码的CSS和JavaScript工具
2016/05/11 Javascript
Bootstrap简单表单显示学习笔记
2016/11/15 Javascript
EasyUI在Panel上动态添加LinkButton按钮
2017/08/11 Javascript
新手vue构建单页面应用实例代码
2017/09/18 Javascript
vue实现在表格里,取每行的id的方法
2018/03/09 Javascript
layer弹出层父子页面事件相互调用方法
2018/08/17 Javascript
Angular2使用SVG自定义图表(条形图、折线图)组件示例
2019/05/10 Javascript
详解javascript中var与ES6规范中let、const区别与用法
2020/01/11 Javascript
vue-cli3 取消eslint校验代码的解决办法
2020/01/16 Javascript
JavaScript创建表格的方法
2020/04/13 Javascript
vue实现五子棋游戏
2020/05/28 Javascript
js实现轮播图效果 纯js实现图片自动切换
2020/08/09 Javascript
[04:44]DOTA2西游记战队视频彩蛋流出 师徒开黑巧遇林书豪
2016/08/03 DOTA
讲解Python中for循环下的索引变量的作用域
2015/04/15 Python
Python 3.x读写csv文件中数字的方法示例
2017/08/29 Python
Python3.6.0+opencv3.3.0人脸检测示例
2018/05/25 Python
Python使用re模块正则提取字符串中括号内的内容示例
2018/06/01 Python
django admin 后台实现三级联动的示例代码
2018/06/22 Python
django之跨表查询及添加记录的示例代码
2018/10/16 Python
详解Python循环作用域与闭包
2019/03/21 Python
Python3的socket使用方法详解
2020/02/18 Python
Django+python服务器部署与环境部署教程详解
2020/03/30 Python
Python3 ffmpeg视频转换工具使用方法解析
2020/08/10 Python
python 爬虫网页登陆的简单实现
2020/11/30 Python
浅谈CSS3中display属性的Flex布局的方法
2017/08/14 HTML / CSS
《一个中国孩子的呼声》教学反思
2014/02/12 职场文书
消防安全责任书范本
2014/04/15 职场文书
假释思想汇报范文
2014/10/11 职场文书
小学端午节活动总结
2015/02/11 职场文书
幼儿园2016年圣诞活动总结
2016/03/31 职场文书
创业计划书之旅游网站
2019/09/06 职场文书