#
jQuery片段:
1(function(){
2 //这里忽略jQuery所有实现
3 })()
半年前初次接触jQuery的时候,我也像其他人一样很兴奋地想看看源码是什么样的。然而,在看到源码的第一眼,我就迷糊了。为什么只有一个匿名函数又没看到运行(当然是运行了……),就能有jQuery这么个函数库了?于是,我抱着疑问来到CSDN。结果相信现在很多人都很清楚了(因为在我之后也不乏来者,呵呵~)。当一个匿名函数被括起来,然后再在后面加一个括号,这个匿名函数就能立即运行起来!真神奇哦!
嘿嘿!胡闹到此为止。在这一节,我们碰到的jQuery片段是一组立即运行的匿名函数。而这种用法在论坛上也曾引起过激辩——这段代码究竟属不属于闭包呢?带着这个疑问,我们从基础开始,分析每个关键要素,寻找属于自己的答案。(没错,自己的答案!在我看来,所有理论只是形式,只要它有利于我们的应用实现,就是可取的——黑猫白猫,抓到老鼠的就是好猫!)
要说匿名函数,我们首先要由函数本身说起。函数的定义如下:
函数是将唯一的输出值赋予给每一输入的“法则”。
当然,这只是数学上的定义。但是,在计算机编程语言中,函数的定义也八九不离十。因为,我们都知道,计算机中的函数,也类似数学定义中的描述,它是将输入的若干数据,经过代码设定的逻辑操作处理后,返回唯一的输出的一组代码组合块。——当然,特例是,输入的数据为空或输出的数据为空,或者两者都为空。
下面,我们先初步了解一下和匿名函数相关的概念。
* 函数声明(function 语句)
要使用一个函数,我们就得首先声明它的存在。而我们最常用的方式就是使用function语句来定义一个函数,如:
1 function abc(){ // code to process }
当然,你的函数也可以是带参数的,甚至是带返回值的。
1 function abc(x,y){ return x+y; }
但是,无论你怎么去定义你的函数,JS解释器都会把它翻译成一个Function对象。例如,你在定义上面的其中一个例子的函数号,再输入如下代码:
1 alert(typeof abc);// "function"
你的浏览器就会弹出提示框,提示你abc是一个Function对象。那么Function对象究竟是什么呢?
* Function 对象
Function对象是JavaScript里面的固有对象,所有的函数实际上都是一个Function对象。关于这个方面的讨论,我们留到下一个专题节。我们先看看,Function对象能不能直接运用构造函数创建一个新的函数呢?答案是肯定的。例如:
1 var abc = new Function("x","y","return x*y;"); alert(abc(2,3)); // "6"
相信大家现在对如何声明一个函数应该是有所了解了。那么什么才是匿名函数呢?
* 声明匿名函数
顾名思义,匿名函数就是没有实际名字的函数。例如,我们把上面的例子中,函数的名字去掉,再判断一下他是不是一个函数:
1 alert(typeof function(){});// "function"
2 alert(typeof function(x,y){return x+y;});// "function"
3 alert(typeof new Function("x","y","return x*y;"))// "function"
我们可以很容易地看到,它们全都是Function对象,换言之,他们都是函数,但是他们都有一个特点——没有名字。所以我们把他们称作“匿名函数”。然而,正因为他们没有“名字”,我们也没有办法找到他们。这就引申了如何去调用一个匿名函数的问题了。
* 匿名函数的调用
要调用一个函数,我们必须要有方法定位它,引用它。所以,我们会需要帮它找一个名字。例如:
1 var abc=function(x,y){ return x+y; } alert(abc(2,3)); // "5"
上面的操作其实就等于换个方式去定义函数,这种用法是我们比较频繁遇到的。例如我们在设定一个DOM元素事件处理函数的时候,我们通常都不会为他们定名字,而是赋予它的对应事件引用一个匿名函数。
对匿名函数的调用其实还有一种做法,也就是我们看到的jQuery片段——使用()将匿名函数括起来,然后后面再加一对小括号(包含参数列表)。我们再看一下以下例子:
alert((function(x,y){return x+y;})(2,3));// "5"
alert((new Function("x","y","return x*y;"))(2,3));// "6"
很多人或许会奇怪,为什么这种方法能成功调用呢?觉得这个应用奇怪的人就看一下我以下这段解释吧。
大家知道小括号的作用吗?小括号能把我们的表达式组合分块,并且每一块,也就是每一对小括号,都有一个返回值。这个返回值实际上也就是小括号中表达式的返回值。所以,当我们用一对小括号把匿名函数括起来的时候,实际上小括号对返回的,就是一个匿名函数的Function对象。因此,小括号对加上匿名函数就如同有名字的函数般被我们取得它的引用位置了。所以如果在这个引用变量后面再加上参数列表,就会实现普通函数的调用形式。
不知道以上的文字表述大家能不能看明白,如果还是理解不了的话,再看一下以下的代码试试吧。
1 var abc=function(x,y){return x+y;};// 把匿名函数对象赋给abc
2 // abc的constructor就和匿名函数的 constructor一样了。也就是说,两个函数的实现是一样的。
3 alert((abc).constructor==(function(x,y){return x+y;}).constructor);
PS:constructor是指创建对象的函数。也就是函数对象所代表的函数体。
总之,将其(被小括号包含的匿名函数)理解为括号表达式返回的函数对象,然后就可以对这个函数对象作正常的参数列表调用了。(前面这里犯了个错误,只有函数表达式还是不能直接调用函数的,去掉匿名函数括号必须要伴随将表达式赋值。也就是(function(){alert(1)})()应该是与 a=function(){alert(1)}()等价,不能连a=都去掉。)
* 闭包
闭包是什么?闭包是指某种程序语言中的代码块允许一级函数存在并且在一级函数中所定义的自由变量能不被释放,直到一级函数被释放前,一级函数外也能应用这些未释放的自由变量。
怎样?看得一头冒汗吧……没事,我也是(虽然是我是了解的,只是表达能力的问题)。让我们换个更加简单的方法说明:闭包,其实是一种语言特性,它是指的是程序设计语言中,允许将函数看作对象,然后能像在对象中的操作搬在函数中定义实例(局部)变量,而这些变量能在函数中保存到函数的实例对象销毁为止,其它代码块能通过某种方式获取这些实例(局部)变量的值并进行应用扩展。
不知道这么再解释后会否更加清晰,如果还是不明白,那么我们再简化一下:闭包,其实就是指程序语言中能让代码调用已运行的函数中所定义的局部变量。
现在我们看一个例子:
var abc=function(y){
var x=y;// 这个是局部变量
return function(){
alert(x++);// 就是这里调用了闭包特性中的一级函数局部变量的x,并对它进行操作
alert(y--);// 引用的参数变量也是自由变量
}
}(5);// 初始化
abc();// "5" "5"
abc();// "6" "4"
abc();// "7" "3"
alert(x);// 报错!“x”未定义!
看到这里,你能判断究竟jQuery的那个代码片段是否闭包了吗?
以我的理解来说吧。是否应用了闭包特性,必须确定该段代码有没有最重要的要素:未销毁的局部变量。那么很显然,没有任何实现的匿名函数不可能应用了闭包特性。但如果匿名函数里面有实现呢?那也还得确定它的实现中有没有用到那些未销毁的局部变量。所以如果问你那个开篇中的jQuery代码片段是应用了JS里的什么特性?那么它只是匿名函数与匿名函数的调用而已。但是,它隐含了闭包的特性,并且随时可以实现闭包应用。因为JS天生就是有这个特性的!(这只是我的理解,我也想知道你的理解,欢迎交流!关于闭包,有机会还是独立再开一个专题吧!)
开发jQuery插件时总结的一些经验分享一下。
一、先看
jQuery(function(){ });
全写为
jQuery(document).ready(function(){ });
意义为在DOM加载完毕后执行了ready()方法。
二、再看
(function(){ })(jQuery);
其实际上是执行()(para)匿名方法,只不过是传递了jQuery对象。
三、总结
jQuery(function(){ });用于存放操作DOM对象的代码,执行其中代码时DOM对象已存在。不可用于存放开发插件的代码,因为jQuery对象没有得到传递,外部通过jQuery.method也调用不了其中的方法(函数)。
(function(){ })(jQuery);用于存放开发插件的代码,执行其中代码时DOM不一定存在,所以直接自动执行DOM操作的代码请小心使用。
1、扩展jQuery自身之全局函数
jQuery.logError={/*log error*/}
jQuery.logWarning ={/*log warning */}
jQuery.logDebug ={/*log debug */}
使用:jQuery.logError();
上面三个可以写成
jQuery.log= {
Error:function(){/*log error*/},
Warning: function(){/*log warning */},
Debug: function(){/*log debug*/}
}
使用:jQuery.log.Error();
jQuery.foobar={/*do foobar*/}
使用:jQuery.foobar();
以上的方法等同于使用 jQuery. extend ()
jQuery. extend = {
log: { Error:function(){/*log error*/},
Warning: function(){/*log warning */},
Debug: function(){/*log debug*/}
},
foobar:function(){/*do foobar*/}
}
使用:
jQuery.log.Error();
jQuery.foobar();
2、添加实例方法,扩展jQuery.fn
jQuery.fn=jQuery.prototype
如:jQuery.fn.showMessage=function(){
alert(“message!!”)}
使用:$(“#div1”).showMessage();
l this是对当前jQuery对象的引用
l 使用each迭代当前对象
l 插件方法必须返回一个jQuery对象
Plug me:制作自己的插件
写一个自己的jQuery插件是非常容易的,如果你按照下面的原则来做,可以让其他人也容易地结合使用你的插件.
为你的插件取一个名字,在这个例子里面我们叫它"foobar".
创建一个像这样的文件:jquery.[yourpluginname].js,比如我们创建一个jquery.foobar.js
创建一个或更多的插件方法,使用继承jQuery对象的方式,如:
jQuery.fn.foobar = function() {
// do something
};
可选的:创建一个用于帮助说明的函数,如:
jQuery.fooBar = {
height: 5,
calculateBar = function() { ... },
checkDependencies = function() { ... }
};
你现在可以在你的插件中使用这些帮助函数了:
jQuery.fn.foobar = function() {
// do something
jQuery.foobar.checkDependencies(value);
// do something else
};
可选的l:创建一个默认的初始参数配置,这些配置也可以由用户自行设定,如:
jQuery.fn.foobar = function(options) {
var settings = {
value: 5,
name: "pete",
bar: 655
};
if(options) {
jQuery.extend(settings, options);
}
};
现在可以无需做任何配置地使用插件了,默认的参数在此时生效:
$("...").foobar();
或者加入这些参数定义:
$("...").foobar({
value: 123,
bar: 9
});
如果你release你的插件, 你还应该提供一些例子和文档,大部分的插件都具备这些良好的参考文档.
现在你应该有了写一个插件的基础,让我们试着用这些知识写一个自己的插件.
很多人试着控制所有的radio或者checkbox是否被选中,比如:
$("input[@type='checkbox']").each(function() {
this.checked = true;
// or, to uncheck
this.checked = false;
// or, to toggle
this.checked = !this.checked;
});
无论何时候,当你的代码出现each时,你应该重写上面的代码来构造一个插件,很直接地:
$.fn.check = function() {
return this.each(function() {
this.checked = true;
});
};
这个插件现在可以这样用:
$("input[@type='checkbox']").check();
现在你应该还可以写出uncheck()和toggleCheck()了.但是先停一下,让我们的插件接收一些参数.
$.fn.check = function(mode) {
var mode = mode || 'on'; // if mode is undefined, use 'on' as default
return this.each(function() {
switch(mode) {
case 'on':
this.checked = true;
break;
case 'off':
this.checked = false;
break;
case 'toggle':
this.checked = !this.checked;
break;
}
});
};
这里我们设置了默认的参数,所以将"on"参数省略也是可以的,当然也可以加上"on","off", 或 "toggle",如:
$("input[@type='checkbox']").check();
$("input[@type='checkbox']").check('on');
$("input[@type='checkbox']").check('off');
$("input[@type='checkbox']").check('toggle');
如果有多于一个的参数设置会稍稍有点复杂,在使用时如果只想设置第二个参数,则要在第一个参数位置写入null.
从上一章的tablesorter插件用法我们可以看到,既可以省略所有参数来使用或者通过一个 key/value 对来重新设置每个参数.
作为一个练习,你可以试着将第四章的功能重写为一个插件.这个插件的骨架应该是像这样的:
$.fn.rateMe = function(options) {
var container = this; // instead of selecting a static container with $("#rating"), we now use the jQuery context
var settings = {
url: "rate.php"
// put more defaults here
// remember to put a comma (",") after each pair, but not after the last one!
};
if(options) { // check if options are present before extending the settings
$.extend(settings, options);
} // ...
// rest of the code
// ...
return this; // if possible, return "this" to not break the chain
});
我家里的ACER笔记本有个功能,就是在插入鼠标后,会自动停用触摸板的,这样可以防止打字时误碰面影响输入速度。这个功能相当好,但公司的HP电脑却没有这个功能,所以对比了两台电脑的触摸板,是同一个牌子的Synaptics,上其主页上也没有发现有类似功能的新的驱动。所以以为这是ACER自己开发的驱动,今天偶然在网上看到了说明,终于实现了这个功能。
将以下内容存为.reg文件导入注册表(操作方法见下),重启后就可以实现插入USB鼠标自动禁用触摸板,假如不出现下图中的选项,请升级到SynapticsPAD最新驱动(www.Synaptics.com)……,我确实在Compaq 的机器上发现老的驱动不成功的情况,但升级后就OK。
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Synaptics\SynTPEnh]
"DisableIntPDFeature"=dword:00000003
[HKEY_LOCAL_MACHINE\SOFTWARE\Synaptics\SynTPEnh]
"ShowDisableIcon"=dword:00000001
"DisableIntPDFeature"=dword:00000003
|
完成后会在鼠标属性中多出一个选项。连接外部USB指向装置时禁用内部指向装置。假如没有钩上,就钩上。
在你插入USB鼠标后会跳出下图的提示。
保存.reg文件的方法(新手阅读)。
先将上面方框中的内容复制下来,粘贴到记事本中。下图
然后先保存。将文件名中的 *.txt 改成 mouse.reg 按保存,就OK了。
这时在你保存的地方就多了个Mouse.reg的文件(下面图示的样子),双击会提示你是否要向注册表中添加信息,选【是】。
文件图标样子
重新起动电脑,完成操作。
感谢使用。
介绍:
TinyMCE是一个轻量级的基于浏览器的所见即所得编辑器,由JavaScript写成。它对IE6+和Firefox1.5+都有着非常良好的支持。功能方面虽然不能称得上是最强,但绝对能够满足大部分网站的需求,并且功能配置灵活简单。另一特点是加载速度非常快,如果你的服务器采用的脚本语言是PHP,那还可以进一步优化。最重要的是,TinyMCE是一个根据LGPL license发布的自由软件,你可以把它用于商业应用。
使用:
1、首先将TinyMCE解压缩,会建立如下的目录结构:
/tinymce/
/tinymce/docs/
/tinymce/docs/zh_cn/
/tinymce/examples/
/tinymce/examples/zh_cn/
/tinymce/jscripts/
/tinymce/jscripts/tiny_mce/
/tinymce/jscripts/tiny_mce/langs/
/tinymce/jscripts/tiny_mce/plugins/
/tinymce/jscripts/tiny_mce/plugins/
/tinymce/jscripts/tiny_mce/themes/
/tinymce/jscripts/tiny_mce/themes/advanced/
/tinymce/jscripts/tiny_mce/themes/default/
/tinymce/jscripts/tiny_mce/themes/simple/
其中docs/目录下是TinyMCE的说明文档,examples/目录下是4个实例页面,而jscripts/目录下则是真正的JS文件。实际使用时候只需要将jscripts/目录上传到服务器上即可。
2、然后在需要使用TinyMCE的页面里加入如下的JS代码:
<!-- tinyMCE -->
<script language="javascript" type="text/javascript"
src="jscripts/tiny_mce/tiny_mce.js"></script>
<script language="javascript" type="text/javascript">
tinyMCE.init({
mode : "textareas",
theme : "advanced",
language :"zh_cn"
});
</script>
<!-- /tinyMCE --> |
这里假设页面与jscripts/处于同一目录下,否则请修改代码里的路径。
现在页面里所有的textarea元素就会被渲染成TinyMCE实例。
3、初始化配置介绍:
tinyMCE.init({
mode : "exact",
elements : "example_textarea",
theme : "advanced",
language :"zh_cn",
plugins : "flash,emotions,paste",
theme_advanced_buttons1 : "bold,italic,underline,
strikethrough, separator, forecolor,backcolor,
fontselect,fontsizeselect",
theme_advanced_buttons2_add_before: "cut,copy,
pastetext,separator",
theme_advanced_buttons2 : "undo,redo,separator,hr,
link,unlink,image,flash,separator",
theme_advanced_buttons2_add :"code,emotions,charmap",
theme_advanced_buttons3 : "",
theme_advanced_toolbar_location : "bottom",
theme_advanced_toolbar_align : "center",
relative_urls : false,
remove_script_host : false
});
引用内容
mode与elements是搭配使用的,用来指定渲染name在elements中的HTML元素为TinyMCE编辑器(可以是DIV或者Textarea),比如:
mode : "exact",elements : "example_textarea"
也可以单独用 mode : "textareas",这样页面中所有的Textarea元素都会被渲染。
theme 可以是advanced或者simple(受功能限制),也可以自定义主题。
language 常用选择可以是:en,zh_cn,zh_cn_utf8,zh_tw,zh_tw_utf8(和语言包名字对应)
plugins 用来指定加载相应的插件,以提供特别功能
theme_advanced_buttons 后面的数字用来指定工具栏的第几行,前3行可以不写,系统会自动用默认图标填在前3个工具栏,如果你不想显示前3行,可以像例子里面一样这样写:theme_advanced_buttons3 : "",_add_before后缀指在默认工具栏前面加图标,_add后缀指在默认工具栏后面加图标,具体每个按钮资料可以查看文档(/doc目录)。
theme_advanced_toolbar_location和theme_advanced_toolbar_align很简单,一看就明白。
relative_urls : false,remove_script_host : false一般也配对使用,因为TinyMce会自动把本地链接改成相对链接的形式,比如会把绝对路径http://www.jacklam.cn /2006/03/abc.html改成相对路径/2006/03/abc.html。加了上面的代码后就不会自动改写了。
最近准备在自己的一个项目中使用开源的web编辑器TinyMce,遇到了程序获取设置TineMce编辑器内容的问题。用google搜索到了一些眉目,先总结如下。
1.先讲怎么设置TinyMce编辑器的内容
(1)如果在初始化编辑器之前,已经给编辑器所处的控件设置了内容,那么TinyMce在初始化的时候,会自动获取控件的内容。
(2)在客户端可以用下面的函数来随时获取内容:
<script language="javascript" type="text/javascript">
<!--
//功能:获取TinyMce编辑器的内容
//参数:editorId——编辑器的id
//返回:内容字符串;如果失败,返回空字符串
function GetTinyMceContent(editorId)
...{
return tinyMCE.getInstanceById(editorId).getBody().innerHTML;
}
//功能:设置TinyMce编辑器的内容
//参数:editorId——编辑器的id
// content——内容
//返回:(无)
function SetTinyMceContent(editorId,content)
...{
tinyMCE.getInstanceById(editorId).getBody().innerHTML=content;
}
//-->
</script>
2.我们再来看看如何获取TinyMce编辑器的内容
(1)在页面提交(即执行Submit())之后,TinyMce会自动将内容写入到控件中。
(2)在客户端还可以用下面的函数来随时获取编辑器的内容
<script language="javascript" type="text/javascript">
<!--
//功能:获取TinyMce编辑器的内容
//参数:editorId——编辑器的id
//返回:内容字符串;如果失败,返回空字符串
function GetTinyMceContent(editorId)
...{
return tinyMCE.getInstanceById(editorId).getBody().innerHTML;
}
//-->
</script>
3.下面是一个完整的asp.net例子:
为了使用该示例,您必须下载有TinyMce,并放置在目录“tiny_mce”中。
<%@ Page Language="C#" CodeFile="TinyMceTest.aspx.cs" Inherits="TinyMceTest" validateRequest=false %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>无标题页</title>
<!-- tinyMCE -->
<script language="javascript" type="text/javascript" src="tiny_mce/tiny_mce.js"></script>
<script language="javascript" type="text/javascript">
// Notice: The simple theme does not use all options some of them are limited to the advanced theme
tinyMCE.init({
mode : "textareas",
theme : "advanced",
plugins : "devkit,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template",
theme_advanced_buttons1_add_before : "save,newdocument,separator",
theme_advanced_buttons1_add : "fontselect,fontsizeselect",
theme_advanced_buttons2_add : "separator,insertdate,inserttime,preview,separator,forecolor,backcolor",
theme_advanced_buttons2_add_before: "cut,copy,paste,pastetext,pasteword,separator,search,replace,separator",
theme_advanced_buttons3_add_before : "tablecontrols,separator",
theme_advanced_buttons3_add : "emotions,iespell,media,advhr,separator,print,separator,ltr,rtl,separator,fullscreen",
theme_advanced_buttons4 : "insertlayer,moveforward,movebackward,absolute,|,styleprops,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,template,|,code",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_path_location : "bottom",
content_css : "example_full.css",
plugin_insertdate_dateFormat : "%Y-%m-%d",
plugin_insertdate_timeFormat : "%H:%M:%S",
extended_valid_elements : "hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]",
external_link_list_url : "example_link_list.js",
external_image_list_url : "example_image_list.js",
flash_external_list_url : "example_flash_list.js",
|