创建简单的 jQuery 插件
本文演示了使用示例 Map Scroller 创建简单 jQuery 插件的步骤。
引言
我们看到了许多 JavaScript 库。JavaScript 库通过避免开发者直接处理浏览器兼容性问题的麻烦,使开发者的生活更加轻松。它们允许程序员编写他们想要实现的代码,而不必担心浏览器,从而节省了大量时间。
jQuery 是我喜欢的库之一。它轻量级、易于使用、美观等。jQuery 的一个有趣特性是插件;它们是可以在需要时插入的 JavaScript 文件。
在本文中,我们将看到如何创建一个名为 Map Scroller 的简单插件,该插件可以使任何溢出的 HTML 元素像 Google Maps 中的一样滚动。
让我们深入文章 :)
要求
- jQuery v1.4.2
- jquery.DisableTextSelect.js
jQuery 技巧
$
是 jQuery 中的主要对象。jQuery 的一切都基于它,或以某种方式使用它。$
包装了一个名为fn
的对象。要向 jQuery 添加插件,我们必须将我们的方法添加到此对象中。
$.fn.Method1 = function(){
};
$("div").Method1();
bind()
允许您将方法绑定到事件。$("input[type=button]").bind("mouseover mouseenter", function(){
alert('hi');
});
data()
允许您将任何自定义数据存储为键值对。$(this).data("mouseposition", {x:200, y:300});
addClass()
允许您动态添加 CSS 类。$("p").addClass("class1 class2");
removeClass()
允许您删除 CSS 类。$("p").removeClass("class1");
scrollTop()
垂直滚动元素。$("myDiv").scrollTop(20);
//scrolls the element down to 20 pixels from the top position.
scrollLeft()
水平滚动元素。$("myDiv").scrollLeft(20);
//scrolls the element right to 20 pixels from the left position.
地图滚动器
高层计划
- 创建一个名为
mapScroll(direction)
的方法。 - 输入参数
direction
可以是以下任何值:“vertical”、“horizontal”或“both”。它表示滚动发生的が。如果您不传递任何参数,则默认为“both”。 - 将此方法添加到 jQuery 的
fn
对象中,这样任何溢出的 HTML 元素都可以通过以下方式实现滚动:
$("#OverflowingDiv").mapScroll("vertical");
低层计划
- 要实现此滚动,我们必须禁用该元素的文本选择。一个名为
DisableTextSelect
的插件可以帮助我们做到这一点。 - 将事件处理程序绑定到元素的
mousedown
、mousemove
和mouseup
事件。 - 在
mousedown
事件处理程序中启用滚动。 - 在
mouseup
事件处理程序中禁用滚动。 - 在
mousemove
事件处理程序中计算鼠标移动的距离(从旧鼠标位置到新鼠标位置),并滚动元素。
代码
让我们先创建骨架
$.fn.mapScroll = function(direction){
//implementation starts
};
直接调用 $
在全局范围内是不安全的,因为可能存在其他库有自己的 $
实现。因此,为了避免全局变量冲突,我们需要创建一个私有空间。
(function($){
$.fn.mapScroll = function(direction){
//implementation starts
};
})(jQuery); //$ and jQuery both are same.
现在,大括号之间的所有变量都不会被外部干扰。我们使用闭包来创建私有空间。
下面是一个典型的闭包
var x = 25;
/*Closure starts*/
(function(){
var x = 35;
alert(x);
})();
/*Closure ends*/
alert(x);
当浏览器处理完上述代码后,它会先弹出 35,然后弹出 25。闭包有助于创建私有作用域,等等。
我们将在插件中使用一些私有方法;让我们将它们放入私有空间。
(function($){
//private space
//Add your private members here
$.fn.mapScroll = function(direction){
//implementation starts
};
})(jQuery);
为 mouseup
、mousedown
和 mousemove
事件创建事件处理程序,并将它们包装在一个名为 eventHandlers
的私有对象中。
(function($){
//private methods
var eventHandlers = {
mousemove: function(e){
//calculate the distance moved and scroll
},
mouseup: function(e){
//reset the flag
},
mousedown: function(e){
//capture the mouse position at initial time
//set a flag
}
};
$.fn.mapScroll = function(direction){
//hook the event handlers
};
})(jQuery);
我们的骨架已经基本准备好了。让我们先完成公共方法 mapScroll
。
$.fn.mapScroll = function(direction){
return this.each(function(){
//disable text selection using the plugin jquery.DisableTextSelect.js
$(this).disableTextSelect();
....
});
};
等等!上面的 return
和 each()
是做什么的?$()
返回一个 HTML 元素数组,因此我们必须迭代所有这些元素,为此,我们使用 each()
方法。return
使我们的插件可链式调用。jQuery 以链式调用而闻名。链式调用允许我们在一个对象上调用一组方法,如下所示:
$("p").show().addClass("paragraphstyle").mapScroll("both"); //a chain
如果没有链式调用,我们就必须单独调用方法:
$("p").show();
$("p").addClass("paragraphstyle");
$("p").mapScroll("both");
我们正在使用链式调用,因此我们可以执行 $("scrollDiv").mapScroll().show()
。应用链式调用非常简单,只需返回对象而不是什么都不返回。
回到 mapScroll()
!绑定事件处理程序
$.fn.mapScroll = function(direction){
return this.each(function(){
//disable text selection
$(this).disableTextSelect();
//binding event-handlers
$(this).bind("mousemove", eventHandlers.mousemove)
.bind("mouseup", eventHandlers.mouseup)
.bind("mousedown", eventHandlers.mousedown);
...
});
};
我们现在需要在这里讨论鼠标移动事件处理程序。在鼠标移动事件中,我们需要知道方向。如果方向是“vertical”,那么我们应该只在垂直方向上滚动。同样,如果它是“horizontal”,则只在水平方向上滚动,否则两者都滚动。
如果我们以某种方式将 direction
参数传递给鼠标移动处理程序,那么通过编写一组 if-else 语句,我们可以做到这一点。但我对此方法不太满意,因为每次鼠标移动时,条件都会被评估。如果它只发生一次,那将是很好的。
我考虑将滚动逻辑放在一个名为 scrollFn
的单独方法中。诀窍在于,scrollFn
的实现是根据 direction
参数动态确定的。有点令人困惑?请看下面的代码:
var scrollFn = (function(){
switch(direction || "both")
{
case "vertical":
return function($this,x,y){
$this.scrollTop( $this.scrollTop() + y );
};
case "horizontal":
return function($this,x,y){
$this.scrollLeft( $this.scrollLeft() + x );
};
case "both":
return function($this,x,y){
$this.scrollTop( $this.scrollTop() + y).scrollLeft($this.scrollLeft() + x );
};
}
})();
同样的闭包概念!但这一次,与私有作用域不同。这种方法称为记忆化。函数 scrollFn
的主体部分在初始化时动态创建。
所以,如果 direction 的值为“vertical”,那么 scrollFn
是:
var scrollFn = function($this,x,y){
//scrolls only in vertical direction
$this.scrollTop( $this.scrollTop() + y );
}
同样,如果它是“both”,那么:
var scrollFn = function($this,x,y){
//scrolls in both directions
$this.scrollTop( $this.scrollTop() + y).scrollLeft($this.scrollLeft() + x );
}
其中 $this
是对象,而 x
和 y
是对象必须水平和垂直滚动的像素距离。我们必须找到一种方法在鼠标移动处理程序中获取此方法。这非常简单!我们只需使用 data()
方法将其存储起来:
$(this).data("scrollFn", scrollFn);
//"scrollFn" is the key, scrollFn is the value.
现在我们可以通过以下方式在插件的任何地方获取 scrollFn
:
var scrollFn = $(this).data("scrollFn");
这是 mapScroll
方法的完整实现:
$.fn.mapScroll = function(direction){
var scrollFn = (function(){
switch(direction || "both")
{
case "vertical":
return function($this,x,y){
$this.scrollTop( $this.scrollTop() + y );
};
case "horizontal":
return function($this,x,y){
$this.scrollLeft( $this.scrollLeft() + x );
};
case "both":
return function($this,x,y){
$this.scrollTop( $this.scrollTop() + y).scrollLeft(
$this.scrollLeft() + x );
};
}
})();
return this.each(function(){
//disabling text selection
$(this).disableTextSelect();
//binding event-handlers
$(this).bind("mousemove", eventHandlers.mousemove)
.bind("mouseup", eventHandlers.mouseup)
.bind("mousedown", eventHandlers.mousedown);
//adding a css class to set custom cursor
$(this).addClass("openhand");
//storing the scroll function.
$(this).data("scrollFn", scrollFn)
});
};
现在让我们看看事件处理程序。
mousedown: function(e){
$(this).data("scroll", true)
.data("position", {x : e.pageX, y : e.pageY});
$(this).removeClass("openhand")
.addClass("closedhand");
}
在 mousedown
事件处理程序中,我们通过将标志 scroll
设置为 true
来启用滚动。标志和初始鼠标位置使用 data()
存储。此外,我们交换 CSS 类以更改光标。
mouseup: function(e){
$(this).data("scroll", false);
$(this).removeClass("closedhand")
.addClass("openhand");
}
在 mouseup
事件处理程序中,我们通过将标志 scroll
设置为 false
并恢复光标 CSS 类来禁用滚动。
mousemove: function(e){
var $this = $(this),
scroll = $this.data("scroll"),
prevPos = $this.data("position"),
scrollFn = $this.data("scrollFn");
if(scroll){
var diffX = prevPos.x - e.pageX,
diffY = prevPos.y - e.pageY;
scrollFn($this, diffX, diffY);
$this.data("position", {x:e.pageX, y:e.pageY});
}
}
在 mousemove
事件处理程序中,我们计算旧鼠标位置和新鼠标位置之间的差值,并使用存储的 scrollFn
方法滚动内容。最后,我们用新位置覆盖旧鼠标位置。
在查看完整代码之前,我发现了一个鼠标移出时的错误,这是我们没有监听的事件……所以,我做了与鼠标抬起时相同的事情,即当用户将鼠标移出元素时禁用滚动。
//both mouseup & mouseout binded to same handler
$(this).bind("mouseup mouseout", eventHandlers.mouseupout);
这是我们的完整代码:
(function($){
var eventHandlers = {
mousemove: function(e){
var $this = $(this),
scroll = $this.data("scroll"),
prevPos = $this.data("position"),
scrollFn = $this.data("scrollFn");
if(scroll){
var diffX = prevPos.x - e.pageX,
diffY = prevPos.y - e.pageY;
scrollFn($this, diffX, diffY);
$this.data("position", {x:e.pageX, y:e.pageY});
}
},
mouseupout: function(e){
$(this).removeClass("closedhand")
.addClass("openhand");
$(this).data("scroll", false);
},
mousedown: function(e){
$(this).removeClass("openhand")
.addClass("closedhand");
$(this).data("scroll", true)
.data("position", {x : e.pageX, y : e.pageY});
}
};
$.fn.mapScroll = function(direction){
//assigning scroll function
var scrollFn = (function(){
switch(direction || "both")
{
case "vertical":
return function($this,x,y){
$this.scrollTop( $this.scrollTop() + y );
};
case "horizontal":
return function($this,x,y){
$this.scrollLeft( $this.scrollLeft() + x );
};
case "both":
return function($this,x,y){
$this.scrollTop( $this.scrollTop() + y).scrollLeft(
$this.scrollLeft() + x );
};
}
})();
return this.each(function(){
//disabling text selection
$(this).disableTextSelect();
//binding event-handlers
$(this).bind("mousemove", eventHandlers.mousemove)
.bind("mouseup mouseout", eventHandlers.mouseupout)
.bind("mousedown", eventHandlers.mousedown);
//adding class
$(this).addClass("openhand");s
//caching the scroll function.
$(this).data("scrollFn", scrollFn);
});
};
})(jQuery);
就是这样!
演示
在 IIS 中配置附加的代码,然后运行 MapScroller.html 页面,即可看到我们的插件生效。
如果您认为本文有用,请不要忘记投票。
**编程即诗歌**