Jquery中的this与$(this)

没有评论

2011 年 04 月 21 日 at 下午 4:15分类:JavaScript | jQuery

$(this)生成的是什么

$()生成的是什么呢?实际上$()=jquery(),那么也就是说返回的是一个jquery的对象。
题外话:通常我们为了简便直接使用$(),实际上,该函数省略了一个参数context,即$(selector)=$(selector,document).如果指定context,可以指定context为一个dom元素集或者jquery对象。
那么依照,$()返回的是jquery对象这一结论,我们可以得出$(this)得到的是一个jquery对象.我们可以使用万能的alert()方法打印出一个对象:
alert($(‘#btn’));显示的结果:是一个object,不用考虑,该object自然是jquery的对象咯。也即是说我们用通过$(‘#btn’)来调用jquery的方法和属性等。

this代表什么?

this,编程的人都知道this表示上下文所处的这个对象,这个自然是不错的,可是这个对象到底是个什么对象呢?加入js里面也有getType的话返回的值会是什么呢?其实js里面不需要使用getType,因为我们有万能的alert.请看看下面的代码:

$('#btn').bind("click",function(){
alert(this);
alert($(this));
});

根据我们的经验(因为$()生成的是jquery的对象嘛),this自然是一个jquery的对象咯。可是我们看看返回的结果:
返回的是什么?【object HTMLInputElement】——伟大的html对象,嘿嘿。所以我们通常在直接使用this.val()或者直接通过this来调用jquery所特有的方法或属性的时候会报错误: 为什么呢?明知故问!html对象当然“不包含属性或方法”了。那么为什么在一个jquery对象的上下文中调用this返回的是一个html对象而不是jquery对象 呢?翻遍jquery的api文档,貌似jquery中并未对this这一关键字进行过特殊“处理”,也就是说这里this是js中的,而不是jquery重新定义了的。so…当然这仅仅是我自己的想法,如果有对此更了解的朋友可以留言更正。而我们再看一下以上代码中alert($(this));的返回,自然是jquery的对象了,在此调用jquery特有的方法和属性,完全没有问题。
结论:
this,表示当前的上下文对象是一个html对象,可以调用html对象所拥有的属性,方法
$(this),代表的上下文对象是一个jquery的上下文对象,可以调用jquery的方法和属性值。

能说明你的Javascript技术很烂的五个原因

没有评论

2011 年 04 月 19 日 at 下午 4:42分类:JavaScript

Javascript在互联网上名声很臭,但你又很难再找到一个像它这样如此动态、如此被广泛使用、如此根植于我们的生活中的另外一种语言。它的低学习门槛让很多人都称它为学前脚本语言,它另外一个让人嘲笑的东西是动态语言的概念是偏偏使用了高标准的静态数据类型。其实,你和Javascript都站错了立场,而现在,你让Javascript很生气。这里有五个原因能说明你的Javascript技术很烂。

1.你没有使用命名空间
是否还记得在大学里老师告诉你不要在家庭作业里使用全局变量?Javascript里的全局变量的使用方法也不例外。Web网页稍不留神就会变的混乱不堪、到处都是从互联网上各个角落里找来的乱糟糟的相互侵犯的脚本和脚本库。如果你把一个变量命名成loader(),那你是成心自找麻烦。如果你在无意识的情况下重载了一个函数,Javascript根本不会提醒你。你还把它叫做一种学前教育编程语言,还记得吧?我要说的是,你需要知道在做了这些后发生什么情况。

function derp() { alert(“one”); }  
function derp() { alert(“two”); }  
derp();   
 

“two”,答案是“two”。并不是一定会这样,它也可能是“one”。所以,把你所有的代码都放在自己的命名空间里,这很容易。下面是定义自己的命名空间的一个简单做法。

var foospace={};  
foospace.derp=function() { alert(“one”); }  
function derp() { alert(“two”); }  
foospace.derp();   
 

2.你在变戏法,你把变量定义的东一个西一个
你使用莫名其妙的数字字母组合作为变量名是一个双输的结局。在40行的代码块了中寻找一个不带任何表意的字符变量,对于维护工作来说简直是场噩梦。把对变量的第一次声明混合到一个40行的代码块里同样也是一场噩梦。即使你自己遇到这样的变量时,你也要不由的问自己:“这是在哪里定义的?”,然后迅速的使用Ctrl+F组合在源代码里寻找这个变量最初定义的位置。不,不要这样,相反,这是对Javascript的滥用,是一种愚蠢的做法。你应该始终把变量定义在它的使用范围的顶部。并不能说因为这不是必须的,你就可以不这样做。

function() {  
var a, //description  
b; //description  
//process…  
}   
 

3.你没有理解Javascript的变量范围
你是个天才的程序员,你吃的是C++、拉的是List。你知道什么是变量范围,你对你的变量有完全的控制,你就像太上皇似的的注视着它们。然而,Javascript却在你的咖啡里拉了一泡屎,并且大笑不止。

var herp=”one”;  
{  
var herp=”two”;  
}  
alert(herp);   
 

在这种情况下你得到的herp不是“one”,而是“two”。Javascript的变量有效范围并不是跟其它语言一样依赖于代码块。Javascript的变量范围是以函数为基础的。每个函数都有它自己的变量范围,Javascript这一点上表现的很酷,根本不理睬这毫无意义的花括弧包起来的范围。事实上,Javascript是如此的酷,以至于你甚至可以将变量范围像命名空间或变量那样进行传递。

4.你以为Javascript的面向对象特征只是嫁接而来的
Javascript,自从呱呱落地起,它就是一个面向对象的语言。所有的东西在Javascript里都是对象,所有的!甚至数字和字符这样的文字符号都可以通过它自身固有的构造器转化成对象。跟其它面向对象的语言比起来,Javascript的不同之处在于,它没有类(class)。Javascript对象像函数那样定义,甚至函数自己也是对象。Javascript有个属性叫做prototype,所有对象里都内置了这个属性,你可以通过它来改变对象的构造,修改对象、添加更多的变量、更多的功能。

var derp; // will hold a Herp instance  
var Herp= function() {  
this.opinion=”Javascript is cooler than BASIC.”;  
}  
Herp.prototype.speak=function() { alert(this.opinion); }  
var derp= new Herp();  
derp.speak();   
 

如果这个看起来跟你毫不相干,我愿意介绍我的好朋友Google给你,Google擅长于帮助人们学习知识。面向对象对于我这篇简短的、低姿态的文章来说实在是个太大的话题。

5.你使用“new”关键字时就像是盲人瞎马
Javascript肯定是你的初恋女友,因为你显得无所适从。如果你想像真人那样取悦Javascript,你需要去了解对象符号。除了在需要实例化一个对象,或罕见的需要延时加载数据的情况外,你基本上不需要使用new关键字。在Javascript里分配大量的new变量地址是一项很慢的操作,为了效率起见,你应该始终使用对象符号。

var rightway= [1, 2, 3];  
var wrongway= new Array(1, 2, 3);   
 

是否还记得我说过Javascript的变量范围是以函数为基础的?是否还记得有人说Javascript的对象像函数那样定义?如果你不使用new关键字来声明一个对象,你将会使这个对象成为全局范围内的对象。所以,永远使用new关键字来声明对象是一个好习惯。

var derp=”one”;  
var Herp=function() {  
this.derp=”two”;  
}  
var foo=Herp();  
alert(derp);   
 

如果你这样写,Javascript并不会在意,而你真正弹出的答案是“two”!有很多方法可以防止对象做出这样的行为,可以以使用instanceOf,但更好的方法是正确的使用new关键字,这样显得更专业。
现在你知道你的Javascript代码写的很烂了吧,如果你记住了上面所说的东西,你的代码就会有所改善。我喜欢用3个tab键来缩进代码,我喜欢用下划线来连接单词,我喜欢把函数名首字母大写来表示它是对象。当然,这个是另外一场讨论了。有很多原因会导致你的Javascript代码写的很烂,就像我有很多技术很烂一样,所以,尽情的在评论里表达你的意见,支持,反对,不吝赐教

jquery表单验证插件 jquery.form.js

没有评论

2011 年 04 月 19 日 at 下午 2:05分类:JavaScript | jQuery

使用查看:http://www.cnblogs.com/xcj26/archive/2009/12/04/1616697.html
插件下载jquery.form.js

jquery的timer插件使用方法

没有评论

2011 年 04 月 19 日 at 下午 2:00分类:JavaScript | jQuery

jQuery Timers插件地址:

http://plugins.jquery.com/project/timers

JQuery Timers应用知识
提供了三个函式
1. everyTime(时间间隔, [计时器名称], 函式名称, [次数限制], [等待函式程序完成])
2. oneTime(时间间隔, [计时器名称], 呼叫的函式)
3. stopTime ([计时器名称], [函式名称])
/*************************************************************
* everyTime(时间间隔, [计时器名称], 函式名称, [次数限制], [等待函式程序完成])
*************************************************************/

//每1秒执行函式test()
function test(){
   //do something...
}
$('body').everyTime('1s',test);
//每1秒执行
$('body').everyTime('1s',function(){
//do something...
});
//每1秒执行,并命名计时器名称为A
$('body').everyTime('1s','A',function(){
//do something...
});
//每20秒执行,最多5次,并命名计时器名称为B
$('body').everyTime('2das','B',function(){
//do something...
},5);
//每20秒执行,无限次,并命名计时器名称为C
//若时间间隔抵到,但函式程序仍未完成则需等待执行函式完成后再继续计时
$('body').everyTime('2das','C',function(){
    //执行一个会超过20秒以上的程式
},0,true);

/***********************************************************
* oneTime(时间间隔, [计时器名称], 呼叫的函式)
***********************************************************/

//倒数10秒后执行
$('body').oneTime('1das',function(){
//do something...
});
//倒数100秒后执行,并命名计时器名称为D
$('body').oneTime('1hs','D',function(){
//do something...
});

/************************************************************
* stopTime ([计时器名称], [函式名称])
************************************************************/

//停止所有的在$('body')上计时器
$('body').stopTime ();
//停止$('body')上名称为A的计时器
$('body').stopTime ('A');
//停止$('body')上所有呼叫test()的计时器
$('body').stopTime (test);
自定义时间单位
打开源代码
找到
powers: {
   // Yeah this is major overkill...
   'ms': 1,
   'cs': 10,
   'ds': 100,
   's': 1000,
   'das': 10000,
   'hs': 100000,
   'ks': 1000000
  }
 

示例:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js" type="text/javascript"></script>
<script src="http://files.cnblogs.com/dachie/jquery.timers-1.2.js" type="text/javascript"></script>
<script>
        function check() {
            $("#Button1").attr("disabled", true);
            $("#Button1").val("正在提交,请稍等3秒.....");
            $('body').oneTime('3s', function() {
                $("#Button1").attr("disabled", false);
                $("#Button1").val("测试提交");
            });
        }
    </script>
<input id="Button1" onclick="check();return false;" value="测试提交" type="submit" name="Button1">

跨域AJAX请求的解决方案

没有评论

2011 年 04 月 19 日 at 上午 10:00分类:JavaScript | jQuery

出于安全的考虑,如果你要从www.a.com通过Ajax来请求另外一个网站www.b.com的内容,浏览器是不允许你这样做的(不理解这里的 安全是指什么?想想如果没有这个限制的话,黑客可以做些什么)。那什么样的情况下算是跨域?域名不同那当然算是跨域了,例如a.com向b.com发送请 求,这当然就是跨域了,不允许的。不过子域名不同(例如sub.a.com向www.a.com 发送请求)甚至是同域名不同端口(例如 a.com:80 向a.com:8080 )也算是跨域的。
下面演示一个跨域的例子:

 &lt; script type = " text/javascript "   &gt;
// jQuery代码
$( " # btnCrossDomainRequest " ).click( function (){
$.get( ' http://dudu.cnblogs.com ' , function (data){
alert( ' success ' );
});
});
&lt; / script&gt;

(在IE8下提示没有权限,在FF3.5.5和Google浏览器下都没有提示,汗~我记得FF以前的版本是有提示的。。IE6下应该会弹窗提示 (没记错
的话))

跨域AJAX请求的解决方案:

在AJAX应用环境中,由于安全的原因,浏览器不允许XMLHttpRequest组件请求跨域资源。在很多情况下,这个限制给我来带来的诸多不 便。很多同行,研究了各种各样的解决方案:
1. 通过修改document.domain和隐藏的IFrame来实现跨域请求。这种方案可能是最简单的一种跨域请求的方案,但是它同样是一种限制最大的方 案。首先,它只能实现在同一个顶级域名下的跨域请求;另外,当在一个页面中还包含有其它的IFrame时,可能还会产生安全性异常,拒绝访问。
2.通过请求当前域 的代理,由服务器 代理去访问另一个域的资源。XMLHttpRequest通过请求本域内的一个服务器资源 ,将要访问的目标资源提供给服务器,交由服务器 去代理访问目标资源。这种方案,可以实现完全的跨域访问,但是开发,请求过程的消费会比较大。
3. 通过HTML中可以请求跨域资源的标签引用来达到目的,比如Image,Script,LINK这些标签。在这些标签中,Script无疑是最合适的。在 请求每一个脚本资源时,浏览器都会去解析并运行脚本文件内定义的函数,或需要马上执行的JavaScript代码,我们可以通过服务器返回一段脚本或 JSON对象,在浏览器解析执行,从而达到跨域请求的目的。使用script标签来实现跨域请求,只能使用get方法请求服务器资源。

第一个解决方案需要根域名是相同的,例如 a .domain.com 和 b .domain.com 。 整个解决方案大概如下图所示:

第二个解决方案就是在服务器端通过WebClient(或者其他)的类来请求跨域的内容,这里需要注意的一点是,如果你要将cookies信息也包 含在WebClient的请求中的话,你需要手动的去将Cookies信息加到WebClient中去。
第三个解决方案就和我们下面需要说道的JSONP有关的。
JSONP
JSONP全称应该是“JSON with padding”吧,它正是利用了script标签
可以跨域请求的特性。简单来说JSONP就是在客户端将要用来处理请求结果的函数名作为参数传递给服务器端,然服务器端将请求结果数据作为参数包装在这个函数中 并返回给客户端执行。有点抽象? 那么直接看图吧:

下面来个实例讲解一下。这个实例就是为我们的博文自动生成一个短址的url,为了墙内的朋友方便,我们就直接使用国内的http://s8.hk 提供的短址服务(API地址 )。
我们试下

&lt; script type = " text/javascript " &gt;
$( " #shortIt " ).click( function (){
c_url =   ' http://s8.hk:8088/s8/s?format=text&amp;amp;longUrl= ' ;
c_url += document.location.href;
$.get(c_url, function (data){
alert(data);
})
});
&lt; / script&gt;

测试下,什么?不可以?肯定不可以啦,因为是跨域嘛,所以我们需要利用script标签
标签可以跨域请求的特性:

&lt; script type = " text/javascript " &gt;
function alertShortUrl(url){
alert(url);
}

$(
" #shortItByJSONP " ).click( function (){
c_url =   ' http://s8.hk:8088/s8/s?format=text&amp;amp;longUrl= ' ;
c_url += document.location.href;
// 注意下面将函数名‘alertShortUrl’传进去咯
c_url +=   ' &amp;amp;jsonp=alertShortUrl '
// 生成一个&lt;script /&gt;标签并添加到&lt;head /&gt;中
script = $( ' &lt;script type="text/javascript" /&gt; ' )
.attr( ' src ' , c_url);
// 这里为什么要用appendChild?
// 因为jQuery的append方法对&lt;script/&gt;已经做了处理
// 你也可以用$('head').append(script);
// 这里不用只是为了让你看得更清楚点而已。
$( ' head ' )[ 0 ].appendChild(script[ 0 ]);
});
&lt; / script&gt;

哈哈,再点点测试按钮看看?很好,成功了。
其实不用这么麻烦,因为jQuery自从1.2版以后就已经添加了对JSONP的支持,你只需要给一个问号作为占位符就可以了,所以我们上面的代码 可以写成:

&lt; script type = " text/javascript " &gt;
$( " #shortItByjQueryJSONP " ).click( function (){
c_url =   ' http://s8.hk:8088/s8/s?format=text&amp;amp;longUrl= ' ;
c_url += document.location.href;
// 注意下面只需一个问号,不用具体的函数名
c_url +=   ' &amp;amp;jsonp=? '
// 注意是getJSON 哦
$.getJSON(c_url, function (data){
alert(data);
});
});
&lt; / script&gt;

哈哈,是不是很简便呢?下面就用这个实现为我们的文章添加自动缩短网址的功能吧:

&lt; script type = " text/javascript " &gt;
$( function (){
c_url =   ' http://s8.hk:8088/s8/s?format=text&amp;amp;longUrl= ' ;
c_url += document.location.href;
// 注意下面只需一个问号,不用具体的函数名
c_url +=   ' &amp;amp;jsonp=? '
$.getJSON(c_url, function (data){
// 这里要这么处理、放到哪里就看你自己喜欢咯.而且这还和你博客使用的模板有关的哦
$( " &lt;div&gt;本文短址:&lt;/div&gt; " ).css( " font-weight " , " normal " )
.css( " font-size " , " 12px " )
.append($( " &lt;a&gt; " + data + " &lt;/a&gt; " ).attr( " href " , data))
.appendTo( " .post .postTitle " );
});
});
&lt; / script&gt;

// ]]>

phpcms V9 整合 Discuz! X1.5

2011 年 04 月 12 日 at 上午 11:45分类:PHP | PHPCMS | Ucenter | WEB开发

首先把原理大致的描述一下,我们把phpsso作为uc的一个应用来处理。UCenter 作服务端;phpsso 与 Discuz! 分别作 UCenter 的客户端应用;phpsso 与 Discuz! 通过 UCenter 发生交互。phpcms 通过 phpsso 与 Discuz! 发生交互。
从 phpcms 注册后,同步注册到 UCenter (这个过程需要在后台开启uc,并且保证通信成功才行),这是因为 phpcms 实际上是与 UCenter 进行通信。用该帐号从 Discuz! 登录,实际上是从 UCenter 登录。而在 Discuz! 中,是没有这个帐号的,所以要把 UCenter 中的这个帐号信息注册到 Discuz! 中(即所谓的“激活”)。这是康盛创想设计的 UCenter 与 Discuz! 帐号转移机制,我们是无法改变的(除非把 Discuz! 从 UCenter 中分离!)反之,从 Discuz! 注册后,同步注册到 phpsso 。但 phpsso 同时注册到 phpcms ,所以就不需要“激活”了。

第一步:安装 phpcms V9 。全新安装 Discuz! X1.5 (同时安装 UCenter)。

第二步:在 UCenter 中添加“phpsso 应用”。
1、管理员登录 Discuz! X1.5 管理中心,进入“UCenter”,点击“应用管理”。
2、点击“添加新应用”按钮,选择安装方式为”自定义安装“。在展开的”添加新应用“参数配置表中,各项参数配置如下:
应用名称:phpsso
应用的主 URL:http://localhost/phpcms/phpsso_server (必填,最后不要带斜线)
应用 IP:(选填,正常情况下留空即可。如果由于域名解析问题导致 UCenter 与该应用通信失败,请尝试设置为该应用所在服务器的 IP 地址。)
通信密钥:(必填,phpcms 的通信密钥必须与此设置保持一致,否则 phpsso 将无法与 UCenter 正常通信。)
应用类型:其它(必选)
应用的物理路径:(选填,默认留空)
查看个人资料页面地址:(选填,URL中域名后面的部分,如:/space.php?uid=%s 这里的 %s 代表uid)
应用接口文件名称:(选填,默认为uc.php)
标签单条显示模板:(选填,默认留空)
标签模板标记说明:(选填,默认留空)
是否开启同步登录:是(可选,开启同步登录后,当用户在登录 Discuz! 时,同时也会登录 phpcms 。)
是否接受通知:是(可选)

3、提交后,生成新的应用ID。(记住这个应用ID,在”第三步“中将用到它。)

第三步:配置 phpsso 。
1、管理员登录 phpcms V9 后台管理中心,进入“phpsso”,点击“系统设置”。
2、在“系统设置”下的“UCenter配置”一栏中,各项参数配置如下:
是否启用:是
Ucenter api 地址:http://localhost/ucenter (必填,最后不要带斜线)
Ucenter api IP:(选填,一般不用填写,遇到无法同步时,请填写 UCenter 主机的IP地址)
Ucenter 数据库主机名:localhost (必填,视实际情况而定)
Ucenter 数据库用户名:root (必填,视实际情况而定)
Ucenter 数据库密码:root (视实际情况而定)
Ucenter 数据库名:discuz (必填,视实际情况而定)
Ucenter 数据库表前缀:dz_ucenter_ (必填,视实际情况而定。如果此项填写错误,将导致 phpcms 无法注册新会员!)
Ucenter 数据库字符集:UTF-8 (必选,视实际情况而定)
应用id(APP ID):(必填,该值来在“第二步”中 UCenter 创建的 phpsso 应用时自动生成。)
Ucenter 通信密钥:(必填,一定确保该值与在“第二步”中 UCenter 创建的 phpsso 应用密钥相同。)
3、提交。

第四步:查看通信状态。
查看在 UCenter 中创建的 phpsso 应用与 UCenter 通信是否成功。
如果通信成功,则进行下一步。
如果通信失败,请检查“第二步”与“第三步”中的各项参数配置是否正确。

第五步:修改 Discuz! 会员登录相关
1、修改 template\default\member\login.htm 第 51 行,删除
ajaxpost(‘loginform_$loginhash’, ‘returnmessage_$loginhash’, ‘returnmessage_$loginhash’, ‘onerror’);return false;
2、修改 source\function\function_core.php 第 1458 行,查找
$param['header'] = true;
替换为:
$param['header'] = false;
3、修改 template\default\member\login_s imple.htm 第 2 行,删除
onsubmit=”return lsSubmit()”

常见问题解答:
1、phpsso 整合 UCenter 后,Discuz! 注册会员在 phpcms 中为什么不显示昵称?
答:这是因为 Discuz! 只有“用户名”,没有“昵称”的概念。要解决这个问题,可以把 Discuz! 的“用户名”做为 phpcms 的“昵称”来使用。
打开 api/phpsso.php ,在第 41 行(代码为:$userinfo['password'] = isset($arr['password']) ? $arr['password'] : exit(’0′);)的下面添加如下语句:
$userinfo['nickname'] = isset($arr['username']) ? $arr['username'] : exit(’0′);
这样修改以后,在 Discuz! 新注册的会员,在 phpcms 中就可以显示昵称了。
但修改以前的会员仍然是没有“昵称”的。这就需要在数据库中修改了。

div层遇到flash不显示的问题

没有评论

2011 年 04 月 07 日 at 下午 6:02分类:HTML | WEB开发

经常遇到 Flash 插入到网页 Div 层后就不显示了。解决方法是将插入到网页中的 Flash 设置为透明 flash,将 wmode 赋值为 transparent,以下为旧式插入方式:

<object classid=clsid:D27CDB6E-AE6D-11cf-96B8-444553540000 codebase=http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0 width=550 height=400> 
<param name=movie value=test.swf> 
<param name=quality value=high> 
<param name=wmode value=transparent> 
<embed src=http://www.59bj.com/test.swf width=550 height=400 quality=high pluginspage=http://www.macromedia.com/go/getflashplayer type=application/x-shockwave-flash wmode=transparent></embed> 
</object>

UCENTER和PHPSSO的异同点

没有评论

2011 年 04 月 03 日 at 下午 9:18分类:PHP | PHPCMS | Ucenter

之前研究过ucenter,感觉写的很不错。里面的很多的东西我们可以直接拿来用,可以在我们建站的时候直接拿来用。但是今天我看了phpcms的phpsso之后,感觉UC和PS都还不错。phpcms的phpsso和ucenter的功能是一样的也是一个用户处理中心,只是phpsso现在的功能还没有ucneter那么多。在这里就两者的一些异同进行简单的分析下:
我们都知道,在要处理类似与同步登录和同步退出时,都会用到UC这样子的东西(当然这也不一定)。UC在处理同步登录和同步退出的过程在本博客已经讲解过了,这里就不解说了。简单说下,就是客户端向用用户名(或者其他)和密码还有加密密钥组成的加密字符通过套接字发送给服务器端,然后服务器获取这些加密字段后,进行解密,然后在处理相关的操作,之后返回的是一串JS串。其实PS(phpsso)在处理同步登录和同步退出时和UC采用的方法是一样的。都是通过用户名和密码(当然还有操作信息)加密之后组成的字符串通过套接字发送到服务器端,然后返回的也是JS串。在同步方面这两个采用的方法原理是完全一样的。只是实现的过程或者是方法有点不同罢了。
当我们向UC发送一些非同步方面的消息时,比如修改积分时,那么UC 是怎么处理的呢?
当我们客户端向用户发送这个信息时,服务端会调用文件credit.php文件里面的onrequest方法来处理。这里的处理大致是这样子的:方法一:如果$toapp['extra']['apppath'](应用物理路径,就是相对应UC的路径)这个变量为false的话,首先通过传递过来的数据处理本地(服务器段的)数据库里面的数据,然后通过include加载,记住这里使用的是加载客户端的文件(api/uc.php),这样子来处理客户端方面数据库中需要处理的信息。方法二:如果$toapp['extra']['apppath']为true的话,那么会通过model下面的note.php文件的get_url_code方法组建URL,然后通过model下面的misc.php文件中的dfopen方法,该方法是通过套接字将数据传输到客户端,然后有客户端自己处理自己需要处理的数据。
PS中采用同样的方法获取到传输过来的数据,然后经过处理之后,但是PS只是采用了一种方法。首先对本地的一些需要处理的数据库进行处理,然后会调用messagequeue.class.php中的notice方法,而该方法调用函数ps_send()来处理,这个函数最终使用的套接字来将数据又传送到客户端的api/下面的文件中,还是通过客户端来处理客户端需要修改的的数据。
以上都是个人的观点,还望各位大侠提意见。。。

PHPCMS V9 自定义字段原理分析

2011 年 04 月 02 日 at 上午 11:32分类:PHPCMS

这段时间一直在研究phpcms的自定义字段功能。之前听坛里面的朋友说这个功能很强大,很多插件都是基于这个做的,与花了点时间,把这块的功能分析了下,网上关于这方面的资料实在是太少了,都是说在后台怎么操作的,这个我相信用了phpcms的都会操作,但是我要说明的是只在后台简简单单的添加个字段,这是很平常的,并不能显示其中最精髓的部分。这里就大致的分析下。
首先就对原先存在的字段进行分析:就拿modules/content/fields/images这个字段来说明。这个字段文件夹(images)下面的一些文件在这里做简要的说明:
1、config.inc.php:这个文件里面主要是一些初始化的控制信息。对表单中的一些控件设置初始值的;
2、form.inc.php:这个文件主要对该字段在表单中如何显示,以及设置相应的属性和值等的设置;(必)
3、input.inc.php:这个文件主要是对该字段的值在插入数据库之前要进行那些处理的一个函数;(选)
4、ouput.inc.php:这个文件主要是对该字段从数据库取出数据之后,经过这个文件内定义的函数处理之后再显示到页面上;(选)
5、field_add_form.inc.php:这个文件主要是一些html代码,当我们在后台添加字段时,会有选择字段类型的一个下拉框。这个框里面的数据都是通过{mocule}/fields/fields.inc.php文件中获得的。这个里面的数组包括了当前自定义的所有字段值。而每一个字段值都有一个文件夹。这个文件就如同我们上面讲的images,这个下面有很多处理该字段的文件。当我们选择某一个字段类型的时候,会通过json来取这个类型所对应的文件夹下面的field_add_form.inc.php,一次来设置该字段的属性。(必)
6、field_edit_form.inc.php:这个文件的功能和上面的功能基本上是一样的。这个是在编辑字段的时候通过json获取。(必)
在后台添加字段的时候,会根据你的选择,判断是将该字段的值添加到主表(如:news)还是添加到从表(如:news_data),看如下代码(sitemodel_field.php):

//判断添加的字段是选择在主表还是在从表
$tablename = $_POST['issystem'] ? $this->db->db_tablepre.$model_table : $this->db->db_tablepre.$model_table.'_data';

然后按照格式修改那个模型表的字段(添加一个字段,调用add.sql.php文件),之后后现将该字段的所有信息插入到数据表pc_model_field中;
我们先来看下下面这段代码(content.php)

//加载自定义的字段值输出控制类库(对自定义的字段的值的输出进行处理)
require_once CACHE_MODEL_PATH.'content_output.class.php';
$content_output = new content_output($modelid,$catid,$CATEGORYS);
$data = $content_output->get($rs);//对每个字段的值都按需要进行处理,然后在返回进行显示

(content_model.php)

//加载自定义的字段值输入控制类库(对自定义的字段的值的存入DB进行处理)
		require_once CACHE_MODEL_PATH.'content_input.class.php';

(content.php)

$modelid = $category['modelid'];
//取模型ID,依模型ID来生成对应的表单
require CACHE_MODEL_PATH.'content_form.class.php';
$content_form = new content_form($modelid,$catid,$this->categorys);
$forminfos = $content_form->get();

上面的这些都是调用相关处理类的代码;那么这些文件都是怎么得来的呢?里面的内容又是什么呢?这里就要从更新后台缓存说起了。
后台更新缓存(admin/cache_all.php文件)这个文件会调用缓存操作类文件cache_api.class.php文件。我们这里主要来看sitemodel()方法里面的部分代码。

require MODEL_PATH.'fields.inc.php';//返回$fields数组
//更新内容模型类:表单生成、入库、更新、输出
$classtypes = array('form','input','update','output');
//一次从自定义字段文件夹中获取form.inc.php,input.inc.php,update.inc.php,output.inc.php,放到cache_model/**.class.php文件中
foreach($classtypes as $classtype) {
	$cache_data = file_get_contents(MODEL_PATH.'content_'.$classtype.'.class.php');
	$cache_data = str_replace('}?>','',$cache_data);
	//对字段的相关文件夹里面的数据进行处理
	foreach($fields as $field=>$fieldvalue) {
		if(file_exists(MODEL_PATH.$field.DIRECTORY_SEPARATOR.$classtype.'.inc.php')) {
			$cache_data .= file_get_contents(MODEL_PATH.$field.DIRECTORY_SEPARATOR.$classtype.'.inc.php');
		}
	}
	$cache_data .= "\r\n } \r\n?>";
	file_put_contents(CACHE_MODEL_PATH.'content_'.$classtype.'.class.php',$cache_data);
	chmod(CACHE_MODEL_PATH.'content_'.$classtype.'.class.php',0777);
}

这里通过遍历fields.inc.php文件中字段来遍历获取每个字段文件夹下面的orm.inc.php,input.inc.php,update.inc.php,output.inc.php的内容,然后将这些文件中的函数写到content_{classtype}.class.php文件中,这里就解释了刚刚调用的那些cache_model/下面的那些文件的由来。主要就是将每个自定义文件夹下面的操作函数添加到{modules}/fields/content_{classtype}.class.php文件中,然后把文件的内容写到缓存中去,方便我们在后期的直接加载该文件进行调用。
content_form.class.php文件的使用情况:
当我们要为一个模型添加数据的时候,这个时候就需要利用很传统的表单了。那么这个为模型添加数据的表单在PC中不是固定的。而是根据字段的情况来显示的。那么这里就要用到这个文件里。当要添加数据时,会调用这个文件来显示相关的表单控件

$modelid = $category['modelid'];
//取模型ID,依模型ID来生成对应的表单
require CACHE_MODEL_PATH.'content_form.class.php';
$content_form = new content_form($modelid,$catid,$this->categorys);
$forminfos = $content_form->get();

这段代码来自content控制器中add时间中,也就是当我们在后台点击添加新闻或者其他是会处理的一段代码,这里根据模型ID以及栏目ID来显示表单控件,来看下content_form.class.php文件中的get方法的部分代码

if(!method_exists($this, $func)) continue;
	$form = $this->$func($field, $value, $v);//调用相关字段(相当于表单的控件)的处理函数

这里的$func变量就是我们在添加字段的时候要选择的字段类型,这些字段类型肯定就是fields下面的某一个文件夹,这里通过调用该方法,来获取该该字段在添加内容的表单中如何显示。如果不存在也就是说在该字段文件夹下面没有form.inc.php这个文件。那么这个字段的值就不现实在添加内容的表单中。这里的这个方法我刚刚说过了 是在系统更新缓存的时候从每个自定义字段中获取然后写进去的。
这里就解释了我们在自定义字段的时候如果要想使用自己自定义的类型的话,那么就必须存在form.inc.ph文件。
content_input.class.php文件的使用情况:
原理和上面的文件是一样的。当我们使用自定义的类型时,如果没有input.inc.php文件,那么系统在获取数据的时候,判断在content_input.class.php文件中是否存在该方法,如果不存在,那么就不处理该字段的数据,直接按照获取的原型写入数据库中。所以要是我们想在我们自定义的字段类型中,想把获取的数据经过处理在写入DB那么就必须存在input.inc.php文件中的字段处理方法。
content_onput.class.php文件的使用情况:
他的情况恰好跟前者是相反的,这里不再多说了。
总之:用户要想添加一个字段,并且这个字段使用自己定义的类型的话,那么:
1、要想能够使用该字段,就必须把该字段的名称和信息添加到fields.inc.php文件中,使之生效,因为我们在后台添加字段的时候的那个选择字段类型就是从这个文件中读取的。如果你不添加的话,那么你就只能使用系统的那些格式。
2、要想自定义的类型能够出现在添加内容的表单中,那么form.inc.php这个文件中处理函数也是必不可少的。
3、要想自定义字段的数据在插入DB之前被处理下,那么input.inc.php文件中的处理函数也是必不可少的。
4、要想自定义的字段的数据在输出到页面是钱通过处理在显示的话,那么output.inc.php文件中处理函数也是必不可少的。
这样,自定义字段的大致功能就说完了,可能有不完整或不对的地方,请大家多多指教。。。