很感谢Imooc组织的这次结对编程活动,虽然我没找到合适的队友,不过我还是一个人坚持学了两周前端开发的课程,这两周里,主要学习的课程包括:《Web App下图片滑动组件的开发》《侧栏工具条开发》《阿当大话西游之WEB组件》。
这三门课程的核心知识点都是JavaScript的函数对象,思路都是:通过require.js将具有某个功能的函数对象封装为模块,通过在其他JS文件中引用这些模块达到简化代码,代码复用的好处。当然,本文的重点不是回顾require.js的知识点,对于require.js不清楚的童鞋可以仔细看看《阿当大话西游之WEB组件》这门课。写这篇学习感想杂文的目的是与大家分享,我学习完上述课程之后,根据工作中的需求对老师讲解的内容进行了一点小小扩展。虽然很简单,但是有了这个开头,以后写各种各样的组件会越来越轻松,越来越复杂。
分享的内容是对《Web App下图片滑动组件的开发》课程讲解的图片全屏滑动组件的功能扩展。如果你对手机端全屏图片滑动了解的很多,应该会知道目前这方面的开源组件有很多很多,imooc网站里也有这方面的课程,如《FullPage.js全屏滚动插件》《全屏切换效果》等。这两门课程,我之前也花了很长时间认真学习。不过那个时候的自己,JS水平不高,虽然自己也花了很多时间看书《JavaScript高级编程》,认真学习了JavaScript的原型链等等对象知识,但是看360团队的《全屏切换效果》课程还是让自己的头大大的,以至于照抄模仿人家的代码都是问题一大堆。后来看了FullPage.js课程,再后来找到了Swiper.js。我发现自己可以在完全不懂内部代码实现的基础上就能完成简单的工作。直到后来才发现,使用起来确实很方便,可一旦遇到问题或者想实现某个自定义功能却不能如愿时,才是真的头疼。上网查也很少能找到解决办法。所以最好还是自己懂代码,自己能够写出简单的满足自身需要的组件就很好。以上全是个人学习的背景描述。
通过这门课程的学习,对组件进行了一点小小的完善,加入了图片滑动的方向设置,屏幕转动时的处理等等。
define(["jquery"],function($){
function Slidebar(options){
this.datalist=options.list;
this.wrap=options.wrap; //传入的是包裹层的ID值
this.wrapper=$("#"+this.wrap);
this.count=this.datalist.length;
this.aniTime=1;
this.mode=options.mode;//vertical || horizontal //滑动方向
this.init();
this.render();
this.bind();
this._resize(); //屏幕转动事件的处理函数
}
Slidebar.prototype.init = function(){
this._width=$(window).width();
this._height=$(window).height();
this._index=0;
this._ratio=this._width/this._height;
};
Slidebar.prototype.render = function(){
that = this;
var flag;
if(that.mode=="horizontal"){
flag=false;
}else if(that.mode=="vertical"){
flag=true;
}
var _ul = $("<ul></ul>");
for (var i = 0; i < this.count; i++){
var _data = this.datalist[i];
var _li = $("<li></li>");
if(flag){//vertical
_li.css({
"height": this._height,
"width": this._width,
"transform": 'translate3d(0, '+this._height*i+'px, 0)'
});
}else{//horizontal
_li.css({
"height": this._height,
"width": this._width,
"transform": 'translate3d('+this._width*i+'px, 0, 0)'
});
}
var _img=$("<img>");
if(_data&&_data.width/_data.height>=this._ratio){
_img.css({
width: this._width
});
}else if(_data&&_data.width/_data.height<this._ratio){
_img.css({
height: this._height
});
}
_img.attr('src', '../images/'+_data.src);
_img.appendTo(_li);
_ul.append(_li);
}
if(flag){
_ul.css({
'width': this._width+"px",
'height': this._height*this.count+"px"
});
}else{
_ul.css({
'width': this._width*this.count+"px",
'height': this._height+"px"
});
}
// 后面会清空外部包裹层,所以这里还得再创建一个外部包裹层Jquery对象
this.wrapper=$("<div id='#"+this.wrap+"'></div>");
this.wrapper.append(_ul);
$("body").append(this.wrapper);
};
Slidebar.prototype.go = function(n){
that = this;
if(typeof n == "number"){
that._index = n;
}else if(typeof n == "string"){
that._index = that._index + n*1;
}
//设置索引超出的情况
if(that._index > that.arr_li.length-1){
that._index = that.arr_li.length-1;
}else if(that._index < 0){
that._index = 0;
}
// 根据滑动方向来加载CSS属性transform
// 有个地方需要优化,通过jquery提供的eq()方法是可以传入负数索引的。所以还是得对索引进行下额外的判断,这地方也没认真想解决办法,大家可以自己想想怎么处理。
if(that.mode=="vertical"){
if(that._index==0){
that.arr_li.eq(that._index).css({
transform : 'translate3d(0,0px,0)',
transition : 'transform '+that.aniTime+'s ease-in-out'
});
that.arr_li.eq(that._index+1) && that.arr_li.eq(that._index+1).css({
transform : 'translate3d(0,'+that._height+'px, 0)',
transition : 'transform '+that.aniTime+'s ease-in-out'
});
}else if(that._index==(that.arr_li.length-1)){
that.arr_li.eq(that._index).css({
transform : 'translate3d(0px,0,0)',
transition : 'transform '+that.aniTime+'s ease-in-out'
});
that.arr_li.eq(that._index-1) && that.arr_li.eq(that._index-1).css({
transform : 'translate3d(0, -'+that._height+'px, 0)',
transition : 'transform '+that.aniTime+'s ease-in-out'
});
}else{
that.arr_li.eq(that._index).css({
transform : 'translate3d(0,0px,0)',
transition : 'transform '+that.aniTime+'s ease-in-out'
});
that.arr_li.eq(that._index+1) && that.arr_li.eq(that._index+1).css({
transform : 'translate3d(0,'+that._height+'px, 0)',
transition : 'transform '+that.aniTime+'s ease-in-out'
});
that.arr_li.eq(that._index-1) && that.arr_li.eq(that._index-1).css({
transform : 'translate3d(0, -'+that._height+'px, 0)',
transition : 'transform '+that.aniTime+'s ease-in-out'
});
}
}else if(that.mode=="horizontal"){
if(that._index==0){
that.arr_li.eq(that._index).css({
transform : 'translate3d(0px,0,0)',
transition : 'transform '+that.aniTime+'s ease-in-out'
});
that.arr_li.eq(that._index+1) && that.arr_li.eq(that._index+1).css({
transform : 'translate3d('+that._width+'px,0,0)',
transition : 'transform '+that.aniTime+'s ease-in-out'
});
}else if(that._index==(that.arr_li.length-1)){
that.arr_li.eq(that._index).css({
transform : 'translate3d(0px,0,0)',
transition : 'transform '+that.aniTime+'s ease-in-out'
});
that.arr_li.eq(that._index-1) && that.arr_li.eq(that._index-1).css({
transform : 'translate3d(-'+that._width+'px,0,0)',
transition : 'transform '+that.aniTime+'s ease-in-out'
});
}else{
that.arr_li.eq(that._index).css({
transform : 'translate3d(0px,0,0)',
transition : 'transform '+that.aniTime+'s ease-in-out'
});
that.arr_li.eq(that._index+1) && that.arr_li.eq(that._index+1).css({
transform : 'translate3d('+that._width+'px,0,0)',
transition : 'transform '+that.aniTime+'s ease-in-out'
});
that.arr_li.eq(that._index-1) && that.arr_li.eq(that._index-1).css({
transform : 'translate3d(-'+that._width+'px,0,0)',
transition : 'transform '+that.aniTime+'s ease-in-out'
});
}
}
// 这行代码是为了解决图片不能撑满整个屏幕时将边上的留白部分的颜色调整为接近图片颜色
that.wrapper.css('background-color', that.datalist[that._index].color);
};
/**
* 绑定组件上的事件
*
*/
Slidebar.prototype.bind = function(){
that = this;
that.arr_li = that.wrapper.find('li');
that._touchstartHandle=function(e){
that.startX=e.touches[0].pageX;
that.offsetX=0;
that.startTime=new Date()*1;
that.startY=e.touches[0].pageY;
that.offsetY=0;
}
that._touchmoveHandle=function(e){
e.preventDefault();
that.offsetX=e.touches[0].pageX-that.startX;
that.offsetY=e.touches[0].pageY-that.startY;
var prev_index = that._index-1;
var next_index = that._index+1;
for (; prev_index <= next_index; prev_index++){
if(prev_index>= 0 && that.arr_li.eq(prev_index)){
if(that.mode==="horizontal"){
that.arr_li.eq(prev_index).css('transform', 'translate3d('+((prev_index-that._index)*that._width+that.offsetX)+'px,0,0)');
that.arr_li.eq(prev_index).css('transition', 'none');
}else if(that.mode==="vertical"){
that.arr_li.eq(prev_index).css('transform', 'translate3d(0,'+((prev_index-that._index)*that._height+that.offsetY)+'px,0)');
that.arr_li.eq(prev_index).css('transition', 'none');
}
}
}
}
that._touchendHandle=function(e){
var boundary;
var fastBoundary;
// 横向滑动和竖向滑动时的零界点不一样
if(that.mode==="horizontal"){
boundary = that._width/6;
fastBoundary = 50;
}else if(that.mode==="vertical"){
boundary = that._height/4;
fastBoundary = 80;
}
var endTime = new Date()*1;
if(endTime-that.startTime > 800){
if(that.mode==="horizontal"){
if(that.offsetX >= boundary){
//进入上一页
that.go("-1");
}else if(that.offsetX < -boundary){
// 进入下一页
that.go("+1");
}else{
//无动作
that.go("0");
}
}else if(that.mode==="vertical"){
if(that.offsetY >= boundary){
//进入上一页
that.go("-1");
}else if(that.offsetY < -boundary){
// 进入下一页
that.go("+1");
}else{
//无动作
that.go("0");
}
}
}else{
if(that.mode==="horizontal"){
if(that.offsetX > fastBoundary){
that.go("-1");
}else if(that.offsetX < -fastBoundary){
that.go("+1");
}else{
that.go("0");
}
}else if(that.mode==="vertical"){
if(that.offsetY > fastBoundary){
that.go("-1");
}else if(that.offsetY < -fastBoundary){
that.go("+1");
}else{
that.go("0");
}
}
}
}
that.wrapper[0].addEventListener("touchstart", that._touchstartHandle);
that.wrapper[0].addEventListener("touchmove", that._touchmoveHandle);
that.wrapper[0].addEventListener("touchend", that._touchendHandle);
//绑定屏幕转动事件
$(window).on('resize', function(event) {
that._resize();
});
};
Slidebar.prototype.destroy = function(){
that = this;
that.wrapper.children().remove();
};
Slidebar.prototype._resize = function(){
that = this;
if(screen.onmozorientationchange){
//火狐浏览器屏幕转动事件
}else if(window.addEventListener){
// 其他浏览器
window.addEventListener("orientationchange", function(event){
if(window.orientation == 180 || window.orientation == 0){//natural portrait
//从竖向转到横向后,继续进行DOM生成和事件绑定的代码
that.init();
that.render();
that.bind();
}else if(window.orientation == 90 || window.orientation == -90){//landscape
// 清空整个页面内容,提示用户不要竖着看页面
$("body").children("#"+this.wrap).remove();
}
})
}
};
return {
Slidebar: Slidebar
}
});
使用起来很方便,
new slidebar.Slidebar({
list: list,
wrap: "canvas",
mode: "vertical"
});
list是一个数组,数组中的对象是一张图片的信息描述,包括width,height, src,color等,其中color是为了填充因图片不能全屏撑满整个屏幕时的留白的背景颜色。
文笔不够好,大家凑合的看看吧。通过这三门课程的学习,我上周练习时对高德地图AMap的JS组件也进行了封装。使得AMap的服务插件和基础覆盖物的使用变得简单,可以省掉不少重复的代码。以后还是得认真学习JavaScript,特别是对象,原型等知识,这样在工作中才会运用的更灵活,也能提高自己的技术水平。
最后,慕女神,送我一个小礼品吧~~看我,看我,看我~~