封装自己的jq myFullpage插件
- 首先了解fullPage的工作原理
可以鼠标键盘监听事件和鼠标滚轮来控制屏幕滚动的那种效果
类似于这样的布局方式,创建class类名box容器,然后在容器里面根据需求生成三个section页面,在根据需求在section页面里面生成silde横屏滚动,在创建一个WapperSilde容器将silde页面包裹起来插入在section当中
jq方式引入fullpage插件
- 重要参数,监测页数滚动完成和过程中
- onLeave :页面离开后触发,index显示当前页数
- afterLoad :离开后到达当前页面触发,index显示页数,两个参数,第二个参数是页数
//示例 $("#wapper").fullpage({ afterLoad : function (a,index){ console.log("后",index) }, onLeave : function (index){ console.log("先",index) } })
封装自己的myFullPgae
需要填写的参数和值,自定义
- 将自己要生成的classbox类名加工进方法里
pageEngine.init(".box",["red" ,"yellow", "green"])
.addSection("oneSection1")//生成第一个section
//第一个页面的样式,这里就不复制粘贴了基本上每一个样式都是一样的
.addComponent({
className: "jiuyi",
type: 'base', //根据该属性来生成不一样的效果
width: 100,
height: 100,
text: "这里是九依的fullpage demo11",
center: true,
css: {
position: "absolute",
opacity: 0,
top: 0,
backgroundImage: "url(./src/images/6.jpg)",
backgroundSize: "100% 100%",
padding: "10px 15px 10px 15px",
textAlign: "justify",
fontSize: "18px",
fontWeight: "900",
lineHeight: "25px",
},
event : {
click : function (){
},
mouseover : function(){
}
},
//下两个控制入场离场动画
animateIn: {
opacity: 1,
top: 240,
},
animateOut: {
opacity: 0,
top: 0,
},
delay:500 //延迟时间
})
.addSection("oneSection2")//生成第二个section
.addSilde("2-1 silde")//生成第二个section的第一个silde
.addSilde("2-2 silde")//生成第二个section的第二个silde
.addSilde("2-3 silde")//生成第二个section的第三个silde
.addSection("oneSection3")//生成第三个section
//启动
.load()
封装pageEngine方法 - 容器生成
//开始生成,启动函数,初始化值
var pageEngine = {
//准备工作
init: function (selector, colorsArray) {
this.$W = $(selector); //将传进来的值jq包装
this.colorsArray = colorsArray; //第二个参数,颜色
this.sildeFlag = false; //判断是section,还是silde
return this; //链式调用的精髓,将当前方法返回回去,该对象全局都可以用
},
//生成section页面 class自定义类名
addSection: function (className) {
this.sildeFlag = false; //这是生成类名 用户自定义类名
this.$Pgae = $("<div class = ' section' />").addClass(className);
this.$Pgae.appendTo(this.$W) //将该secition塞入进box容器里面
return this;
},
//生成silde页面
addSilde: function (className) {
this.sildeFlag = true;
this.$silde = $("<div class = 'silde' />").addClass(className);
this.$silde.appendTo(this.$Pgae) //this指向pageEngine
return this;
},
//将创建出来的页面设置用户传入的Css值,留接口
addComponent: function (config) {
var oCp = null;
switch (config.type) { //根据type,来生成不一样的效果
case "base": {
oCp = ComponentFactory(config); //设置css值的方法
break;
}
}
//如果sildeFlag是ture,就把oCp加入在silde里面,如果是false就加入在section里
this.sildeFlag ? this.$silde.append(oCp) : this.$Pgae.append(oCp);
return this;
},
}
ComponentFactory方法
var ComponentFactory = function (config) {
var $Div = $('<div class="component base"</div>'); //生成展示类容
//用户自定义属性
config.className && $Div.addClass(config.className);
config.width && $Div.css("width", config.width);
config.height && $Div.css("height", config.height);
config.text && $Div.text(config.text);
config.center && $Div.css({ position: "absolute", left: "50%", marginLeft: -config.width / 2 });
config.css && $Div.css(config.css);
//事件处理
if (config.event) {
for (var prop in config.event) {
$Div.on(prop, config.event[prop]);
}
}
//自定义事件,动画
$Div.on("cpLeave", function () {
var self = this; //当前展示效果盒子记录
setTimeout(function () {
//用户自定义动画移出效果
config.animateOut && $(self).animate(config.animateOut)
//延迟时间
}, config.delay);
});
$Div.on("cpLoad", function () {
var self = this;
setTimeout(function () {
//用户自定义动画移入效果
config.animateIn && $(self).animate(config.animateIn)
}, config.delay);
});
return $Div; //这个时候oCp拿着这个闭包的,展示效果
}
接着上面的继续来
var pageEngine = {
//准备工作
init: function (selector, colorsArray) {
this.$W = $(selector); //将传进来的值jq包装
this.colorsArray = colorsArray; //第二个参数,颜色
this.sildeFlag = false; //判断是section,还是silde
return this; //链式调用的精髓,将当前方法返回回去,该对象全局都可以用
},
//生成section页面 class自定义类名
addSection: function (className) {
this.sildeFlag = false; //这是生成类名 用户自定义类名
this.$Pgae = $("<div class = ' section' />").addClass(className);
this.$Pgae.appendTo(this.$W) //将该secition塞入进box容器里面
return this;
},
//生成silde页面
addSilde: function (className) {
this.sildeFlag = true;
this.$silde = $("<div class = 'silde' />").addClass(className);
this.$silde.appendTo(this.$Pgae) //this指向pageEngine
return this;
},
//将创建出来的页面设置用户传入的Css值,留接口
addComponent: function (config) {
var oCp = null;
switch (config.type) { //根据type,来生成不一样的效果
case "base": {
oCp = ComponentFactory(config); //设置css值的方法
break;
}
}
//如果sildeFlag是ture,就把oCp加入在silde里面,如果是false就加入在section里
this.sildeFlag ? this.$silde.append(oCp) : this.$Pgae.append(oCp);
return this;
},
bindEvent: function () {
this.$W.find(".section").on({
//这是控制里面的动画,就是控制翻页之后的移入移出动画,是ComponentFactory方法里面的
_leave: function () {
//移出
$(this).find(".component").trigger("cpLeave")
},
_load: function () {
//移入
//$(this).find(".component")就是oCp生成的那个容器,让他做出相应动画
$(this).find(".component").trigger("cpLoad")
}
})
},
//启动函数
load: function () {
//生成完所有容器启动该方法
var self = this;
this.bindEvent();
//主角fullPage方法
this.$W.myFullpage({
colorsArray: this.colorsArray,
onLeave: function (index) {
self.$W.find(".section").eq(index).trigger("_leave");
},
afterLoad: function (index) {
self.$W.find(".section").eq(index).trigger("_load");
}
});
//初始话第一个section加入移出移入动画效果
this.$W.find(".section").eq(0).trigger("_load");
}
}
封装自己的myFullPage
- 首先先在jq工具方法里面加入自己的方法名称,config用于接收传递参数
$.fn.extend({
myFullpage: function (config) {
}
})
初始化值,准备工作
$.fn.extend({
myFullpage: function (config) {
var colorArray = config.colorsArray; //页面颜色,用于开发
var $W = $(this); //将传递的box,先用jq包裹起来后面用得到
var $Section = $W.find(".section") //生成的section子页
// 初始化值
var chuShiHhua = { //整屏高度宽度初始化占满整屏
width: "100%",
height: "100%"
}
//获取当前窗口的高度宽度
var clientWidth = window.innerWidth;
var clientHeight = window.innerHeight;
var curindex = 0; //后续参数,用于计数,页数,看向上向下移动的时候的参数
var key = true; // 防止用户键盘按的过快出现的bug
var curindexLeft = 0; //记录水平方向页数
}
})
初始化CSS和生成容器
// 让因为要让Html整屏滚动,所以就在这里设置的外边距,溢出部分隐藏
$("html")
.css({
margin: "0px",
overflow: "hidden",
position: "relative"
})
//集中操作
.add("body")
.add($W)
.add($Section)
.css(chuShiHhua)
$W
.css({
position: "absolute",
left: "0px",
top: "0px"
})
//选中section对每一个页面添加颜色,方便开发
.find($Section).each(function (index, ele) {
$(ele)
.css({ backgroundColor: colorArray[index], position: "relative" })
//如果下面有silde的话就让她的宽高等于整个屏幕宽度并且浮动
.find(".silde")
.css({ width: clientWidth, height: clientHeight, float: "left", position: "relative" })
//再给silde创建一个className为WapperSIlde的父容器
.wrapAll("<div class ='WapperSilde'></div>")
})
//对WapperSilde进行样式操作
$Section.find(".WapperSilde")
.css({ position: "absolute", left: "0px", top: "0px" })
.each(function (index, ele) {
$(ele)
.css({
width: $(ele)
.find(".silde")
//整体宽度的关于他的儿子容器 * 屏幕宽度
.size() * innerWidth, height: innerHeight
})
})
//运动,页面运动+active激活状态
$Section.eq(0)
//给第一个section一个active类名
.addClass("active")
//回退操作
.end()
.find(".WapperSilde")
//给每一个WapperSilde下面的silde添加一个inneractive类名
.each(function (index, ele) {
$(ele).
find(".silde")
.eq(0)
.addClass("inneractive")
})
// 鼠标滚轮判断事件
// 全局鼠标判断 防抖
//我这里直接将防抖放进来,以供参考
function debounce(handler, delay) {
var timer = null;
return function () {
var _self = this, _arg = arguments;
//先清除上一个定时器
clearTimeout(timer);
timer = setTimeout(function () {
//当前handler的this指向为document
handler.apply(_self, _arg);
//延迟时间
}, 500)
}
}
$(document).on("mousewheel DOMMouseScroll", debounce(function (event) {
//获取当前整屏高度
var newtop = $W.offset().top;
//局部变量,检测鼠标向上滚动或者向下滚动,预留接口,保留向上向下移动的值
var dicrction = "";
var dicrction = (event.originalEvent.wheelDelta && (event.originalEvent.wheelDelta > 0 ? 1 : -1)) || (event.originalEvent.detail && (event.originalEvent.detail > 0 ? -1 : 1));
//向上移动越界判断
if(dicrction == 1 && curindex != 0){
/向上移动
dicrction = "top";
//当前的位置,向上
config.onLeave(curindex, dicrction)
curindex--;
//让newtop加等于clientHeight高的位置
newtop += clientHeight;
//向下移动
}else if(dicrction == -1 && curindex != $Section.size() - 1){
dicrction = "bottom";
config.onLeave(curindex, dicrction)
curindex++;
newtop -= clientHeight;
}
//动画效果
//全局匀速运动,
$W.animate({ top: newtop }, 500, "swing", function () {
//锁,防止在运动之后有其他操作出现的bug
key = true;
//给section当前的页数加上acrive激活效果
$Section.eq(curindex).addClass("active");
//dirction的作用来了,如果是向上,让之前的那个acrive消除
if (dicrction == "top") {
//如果是向上,那就当前位置的上一个,就是+1的索引位置去掉active
$Section.eq(curindex + 1).removeClass("active");
} else {
//如果是向下,那就当前位置的上一个,就是-1的索引位去掉active
$Section.eq(curindex - 1).removeClass("active")
}
//移动之后触发的当前页面的索引位和方向
config.afterLoad(curindex, dicrction)
})
}, 1500));
// 键盘事件
$(document).on("keydown", function (e) {
//判断垂直方向,和鼠标滚动事件一模一样
if (e.which == 38 || e.which == 40) {
if (key) {
key = false;
var newtop = $W.offset().top;
var dicrction = "";
if (e.which == 38 && curindex != 0) {
dicrction = "top";
config.onLeave(curindex, dicrction)
curindex--;
newtop += clientHeight;
} else if (e.which == 40 && curindex != $Section.size() - 1) {
dicrction = "bottom";
config.onLeave(curindex, dicrction)
curindex++;
newtop -= clientHeight;
}
$W.animate({ top: newtop }, 500, "swing", function () {
key = true;
$Section.eq(curindex).addClass("active");
if (dicrction == "top") {
$Section.eq(curindex + 1).removeClass("active");
} else {
$Section.eq(curindex - 1).removeClass("active")
}
config.afterLoad(curindex, dicrction)
})
}
}
//判断水平方向的键盘事件
//越界兼容,如果左右方向没有页面的话,则是没办法使用该事件的,如果有自动生成的WapperSilde的类名则可以使用该方法
if ($($Section[curindex]).find(".WapperSilde").hasClass("WapperSilde")) {
// 判断左右方向的键
if (e.which == 37 || e.which == 39) {
if (key) {
key = false;
// $S用于记住WapperSilde值,方便后续使用
var $S = $(".active").find(".WapperSilde");
//记录WapperSilde下面的容器方便后续使用
var curShowDom = $S.find(".inneractive");
//获取当前WapperSilde的定位左边距离
var newleft = $S.offset().left;
var dicrction = null;
//左键盘事件判定
//防止越界,curShowDom.index() 等于0的时候就不能再按左键盘触发事件了
if (e.which == 37 && curShowDom.index() != 0) {
newleft += clientWidth;
dicrction = "left";
//参数(计数索引,哪方向移动的)
config.onLeave(curindexLeft, dicrction);
curindexLeft--;
//防止越界,curShowDom.index() 等于0的时候就不能再按右键盘触发事件
} else if (e.which == 39 && curShowDom.index() != $S.find('.silde').size() - 1) {
newleft -= clientWidth;
dicrction = "right";
//参数(计数索引,哪方向移动的)
config.onLeave(curindexLeft, dicrction);
curindexLeft++;
}
//动画和加inneractive激活方法
$S.animate({ left: newleft }, 500, "swing", function () {
key = true;
// dicrction 如果移动了,就必定会等于left或者right,如果dicrtion等于null就返回""说明没有进入事件,如果能与null,就清除掉curShowDom的所有inneractive
dicrction != null ? curShowDom.removeClass('inneractive') : " ";
//如果dicrction等于left就是按的左按钮
if (dicrction == "left") {
//他的左边的,就是上一个兄弟添加inneractive
curShowDom.prev().addClass("inneractive")
//如果是右按钮
} else if (dicrction == "right") {
//他的右边的,下一个兄弟添加inneractive
curShowDom.next().addClass("inneractive")
}
//动画完成后,执行的回调函数,参数(当前索引位,方向)
config.afterLoad(curShowDom.index(), dicrction)
})
}
}
}
})
总结
是看的老师的课程边写边练的,基本上大体的运行原理都理解了,不过要自己什么都不翻阅手写一个fullpage还是蛮困难的,在老师原有的基础上,添加了防抖,添加了鼠标滚轮事件,对键盘左右按键的报错进行了兼容,对左右翻页的索引位进行了 调整
目前未解决的bug,左右翻页的时候会出现oCp的运动动画多次调用,导致容器已经显示了还要再执行一遍 animateOut和animateIn,有大佬知道怎么解决吗,不过上下页目前测试还是没什么Bug的