实现图片异步延迟加载技术

一条评论

2011 年 07 月 25 日 at 下午 10:57分类:JavaScript | jQuery

看到了淘宝产品介绍中,图片是在下拉滚动条时加载,这是一个很不错的用户体验。减少了页面加载的时间了,也减轻了服务器的压力,就查了下用JQuery..
什么是ImageLazyLoad技术
在页面上图片比较多的时候,打开一张页面必然引起与服务器大数据量的交互。尤其是对于高清晰的图片,占的几M的空间。ImageLazyLoad 技术就是,当前可见界面的图片是加载进来的,而不可见页面(通过滚动条下拉可见)中的图片是不加载的,这样势必会引起速度上质的提升。
怎么实现ImageLazyLoad
一、使用JQuery插件 ,插件名: jquery.lazyload(7kb大小),压缩后(3kb大小)
在线压缩js http://closure-compiler.appspot.com/home
虽然是很牛X的特效,不过用JQuery插件只需要短短几句代码,使用过程如下:
1.导入JS插件

<script src="http://banu.blog.163.com/blog/jquery.js" type="text/javascript"></script> 
<script src="http://banu.blog.163.com/blog/jquery.lazyload.js" type="text/javascript"></script> 

2.在你的页面中加入如下的javascript:

$("img").lazyload(); 

这将会使所有的图片都延迟加载。
当然插件还有几个配置项可供设置。
1.改变threshold

$(“img”).lazyload({ threshold : 200 }); 

把阀值设置成200 意思就是当图片没有看到之前先load 200像素。
2.当然了你也可以通过设置占位符图片和自定事件来触发加载图片事件
复制代码
代码如下:

$("img").lazyload({ 
placeholder : "img/grey.gif", 
event : "click" 
}); 

3.可以通过定义effect 参数来定义一些图片显示效果
复制代码
代码如下:

 
$("img").lazyload({ 
placeholder : "img/grey.gif", 
effect : "fadeIn" 
}); 

LazyLoad(延迟加载)技术不仅仅用在对网页中图片的延迟加载,对数据同样可以,Google Reader和Bing图片搜索就把
LazyLoad技术运用的淋漓尽致;
缺陷:
1.与Ajax技术的冲突;
2.图片的延迟加载,遇到高度特别高的图片,会出现停止加载的问题;
3.写代码不规范的同学要注意了,不管由于什么原因,如果您的页面中,img标签的height属性未定义,那么我建议您最好不要使用ImageLazyLoad
大家可以直接采用淘宝的延迟加载技术:(2kb大小)

http://a.tbcdn.cn/kissy/1.0.0/build/imglazyload/imglazyload-min.js 

调用方法也是很简单的:

<script src="http://a.tbcdn.cn/kissy/1.0.0/build/imglazyload/imglazyload-min.js" 
type="text/javascript"></script> <script type="text/javascript">// <![CDATA[KISSY.ImageLazyload();// ]]></script> 
注:该脚本依赖 yahoo-dom-event, 页面中需要加载 yui 2.x,你也可以直接引用下面的地址: 
<script src="http://kissy.googlecode.com/svn/trunk/third-party/yui2/yahoo-dom-event/yahoo-dom-event.js" type="text/javascript"></script> 

配置参数如下:
复制代码
代码如下:

<script type="text/javascript"> 
KISSY.ImageLazyload({ 
mod: "manual", // 延迟模式。默认为 auto 
diff: 200 // 当前屏幕下多远处的图片开始延迟加载。默认两屏外的图片才延迟加载 
}); 
</script> 

manual 模式时,需要手动将页面中需要延迟加载的图片的 src 属性名更改为 data-lazyload-src. 比如 SRP 页面,宝贝列表的后20个图片延迟加载。 输出时,html 代码为:

<img data-lazy-src="http://banu.blog.163.com/blog/path/to/img" alt="something" /> 

如果您是Jquery,Prototype等这些JS框架的粉丝,他们都有定制的LazyLoad Plugin提供;
可查看http://www.appelsiini.net/projects/lazyload.

简单的异步上传文件操作

没有评论

2011 年 07 月 25 日 at 下午 10:36分类:HTML | PHP

1、在页面中间有一个简单的<form…表单,表单只包含了<input type=”file” … >控件。这个表单的目标链接就是一个隐藏得IFRAME(通过 CSS的风格” display: none;”实现)并且表单里面唯一一个控件的OnChange事件用来触发JavaScript函数。这个函数的作用是检查用户提交的扩展名,然后提交表单。
2、在服务器端用PHP编写了一个处理过程(用FILEFRAME坐注释了)。这个处理过程用来把从客户端上传的文件进行检查后保存在服务器,并且通过Javascript代码的形式返回给用户。返回给用户的Javascript脚本通过”parent.window.document”更改了用户现在正在查看的页面,设置了文件的名称并启用了让用户提交表单的按钮。启用按钮的操作是通过getElementById函数实现的。
3、 在主页面还有一个表单,它包含了用户提交的描述和隐藏的文件名。用户可以在文件上传的同时填写文件的描述。当文件上传结束以后,用户点击按钮,就可以看上传以后返回给用户的文件信息了。(通过返回来的文件名和用户输入的描述构成文件信息)。例子如下: 
HTML:

<!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" lang="en_US" xml:lang="en_US">
<head>
  <title>图片异步上传</title>
</head>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/index.js"></script>
<link type="text/css" rel="stylesheet" href="css/index.css">
<body>
 <div class="frm">
  <form name="uploadFrom" id="uploadFrom" action="upload.php" method="post"  TARGET='TARFRAME' enctype="multipart/form-data">
   <input type="file" id="upload_file" name="upfile">
  </form>
  <iframe src=""  width="0" height="0" style="display:none;" NAME="TARFRAME"></iframe>
 </div>
 <div id="msg">
 </div>
</body>
</html>

index.js:

$(function(){
 $("#upload_file").change(function(){
   $("#uploadFrom").submit();
 });
});

function stopSend(str){
 var im="<img src='upload/images/"+str+"'>";
 $("#msg").append(im);
}}

upload.php:

<?php
 $file=$_FILES['upfile'];
 $name=rand(0,500000).dechex(rand(0,10000)).".jpg";
 move_uploaded_file($file['tmp_name'],"upload/images/".$name);
//调用iframe父窗口的js 函数
  echo "<script>window.parent.stopSend('$name')</script>";

php解析unicode代码

没有评论

2011 年 07 月 18 日 at 上午 8:54分类:PHP | WEB开发

function str_from_unicode($str, $out_charset = 'gbk'){
		$str = preg_replace_callback("|&#([0-9]{1,5});|", 'unicode2utf8_', $str);
		$str = iconv("UTF-8", $out_charset, $str);
		return $str;
	}
	
	function unicode2utf8_($c){
		return unicode2utf8($c[1]);
	}
	function unicode2utf8($c){
		$str="";
		if ($c < 0x80) {
			$str.=$c;
		} else if ($c < 0x800) {
			$str.=chr(0xC0 | $c>>6);
			$str.=chr(0x80 | $c & 0x3F);
		} else if ($c < 0x10000) {
			$str.=chr(0xE0 | $c>>12);
			$str.=chr(0x80 | $c>>6 & 0x3F);
			$str.=chr(0x80 | $c & 0x3F);
		} else if ($c < 0x200000) {
			$str.=chr(0xF0 | $c>>18);
			$str.=chr(0x80 | $c>>12 & 0x3F);
			$str.=chr(0x80 | $c>>6 & 0x3F);
			$str.=chr(0x80 | $c & 0x3F);
		}
		return $str;
	}

使用方法:

echo str_from_unicode('&#20854;&#23427;&#38498;&#31995;');

6个有用的MySQL语句

没有评论

2011 年 07 月 12 日 at 下午 11:23分类:MySQL

1. 计算年数
你想通过生日来计算这个人有几岁了。

SELECT DATE_FORMAT(FROM_DAYS(TO_DAYS(now()) - TO_DAYS(@dateofbirth)), '%Y') + 0; 

2. 两个时间的差
取得两个 datetime 值的差。假设 dt1 和 dt2 是 datetime 类型,其格式为 ‘yyyy-mm-dd hh:mm:ss’,那么它们之间所差的秒数为:

UNIX_TIMESTAMP( dt2 ) - UNIX_TIMESTAMP( dt1 )

除以60就是所差的分钟数,除以3600就是所差的小时数,再除以24就是所差的天数。

3. 显示某一列出现过N次的值

SELECT id
FROM tbl
GROUP BY id
HAVING COUNT(*) = N; 

4. 计算两个日子间的工作日
所谓工作日就是除出周六周日和节假日。

SELECT COUNT(*)
FROM calendar
WHERE d BETWEEN Start AND Stop
  AND DAYOFWEEK(d) NOT IN(1,7)
  AND holiday=0;

5. 查找表中的主键

 SELECT k.column_name
FROM information_schema.table_constraints t
JOIN information_schema.key_column_usage k
USING (constraint_name,table_schema,table_name)
WHERE t.constraint_type='PRIMARY KEY'
  AND t.table_schema='db'
  AND t.table_name=tbl'
 

6. 查看你的数库有多大

 SELECT
  table_schema AS 'Db Name',
  Round( Sum( data_length + index_length ) / 1024 / 1024, 3 ) AS 'Db Size (MB)',
  Round( Sum( data_free ) / 1024 / 1024, 3 ) AS 'Free Space (MB)'
FROM information_schema.tables
GROUP BY table_schema ;

CI配置smarty

10条评论

2011 年 07 月 12 日 at 上午 8:55分类:PHP

1、到相应站点下载Smarty的源码包;
2、将源码包里面的libs文件夹copy到CI的项目目录下面的libraries文件夹下,并重命名为Smarty;
3、在项目目录的libraries文件夹内新建文件Cismarty.php,里面的内容如下:

<?php
if(!defined('BASEPATH')) EXIT('No direct script asscess allowed');

require_once( APPPATH . 'libraries/Smarty/Smarty.class.php' );

class Cismarty extends Smarty {

	protected $ci;

	public function  __construct(){
				
		$this->ci = & get_instance();

		$this->ci->load->config('smarty');//加载smarty的配置文件
		
		//获取相关的配置项
		$this->template_dir   = $this->ci->config->item('template_dir');
		$this->complie_dir    = $this->ci->config->item('compile_dir');
		$this->cache_dir      = $this->ci->config->item('cache_dir');
		$this->config_dir     = $this->ci->config->item('config_dir');
		$this->template_ext   = $this->ci->config->item('template_ext');
		$this->caching        = $this->ci->config->item('caching');
		$this->cache_lifetime = $this->ci->config->item('lefttime');
	}
	
}

4、在项目目录的config文件夹内新建文件smarty.php文件,里面的内容如下:

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
$config['theme']        = 'default';
$config['template_dir'] = APPPATH . 'views';
$config['compile_dir']  = FCPATH . 'templates_c';
$config['cache_dir']    = FCPATH . 'cache';
$config['config_dir']   = FCPATH . 'configs';
$config['template_ext'] = '.html';
$config['caching']      = false;
$config['lefttime']     = 60;

5、在入口文件所在目录新建文件夹templates_c、cache、configs;

6、在项目目录下面的config目录中找到autoload.php文件
修改这项

:$autoload['libraries'] = array('Cismarty');//目的是:让系统运行时,自动加载,不用认为的在控制器中手动加载

7、在项目目录的core文件夹中新建文件MY_Controller.php 内容如下:

<?php if (!defined('BASEPATH')) exit('No direct access allowed.');

class Controller extends CI_Controller {	
    
	public function __construct() {
		
		parent::__construct();		
	    
    }

	public function assign($key,$val) {
		$this->cismarty->assign($key,$val);
	}


	public function display($html) {
		$this->cismarty->display($html);
	}
}

//================================================================
配置完毕
//================================================================
使用方法:
在控制器中如:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Welcome extends Controller {

	public function __construct(){
    	parent::__construct();	
    }

	public function index()
	{ 
		$data['title'] = '测试';
		$data['test'] = '123456789';
		$this->assign('test',$data);
		$this->assign('tmp','hello');
		$this->display('test.html');
	}
}

然后再视图中:试图文件夹位于项目目录的views之下:
新建文件test.html

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>{$test['title']}</title>

<style type="text/css">
</style>
</head>
<body>

{$test['test']|md5}
<br>
{$tmp}
123

</body>
</html>

CI路由剖析

没有评论

2011 年 07 月 10 日 at 下午 4:59分类:PHP | WEB开发

CI 的路由功能是在CodeIninter.PHP文件中开始执行的。
1:在核心文件CodeIninter.php中,加载完路由操作类Router之后,立刻就执行了$RTR->_set_routing();该方法主要的功能是:
a:在初始化路由类的时候加载了配置类Config,和URI操作类两个文件
b:首先判断是否开启了:enable_query_strings,如果是,那么执行以下:
(1):通过用$_GET['c']和$_GET['m']来获取当前的类和方法,并放到数组$segments中。
c:加载APPPATH/config/routes.php(路由配置文件),放到$this->routes中,然后释放routes.php中的$routes
d:获取默认的Controller($this->default_controller),转换成首字母大写
e:判断$segments数组是否为空(该变量的数据来源于可能的b步骤),如果执行了b步骤,显然不会为空,会调用方法$this->_validate_request($segments)来处理
f:方法_validate_request()的主要功能是:判断$segments中指定的控制器文件是否存在,存在,返回,不存在,判断是否存在子层目录,如果存在,进行相关处理。
g:调用URI中_fetch_uri_string方法:通过各种方法获取URI的内容(首先考虑的是 REQUEST_URI),将处理后的URI放到$this->uri_string中
h:判断$this->uri_string是否为空,若是:调用_set_default_controller();
1:设置默认的控制器,我们在路由配置文件中可以这么写:$route['default_controller'] = “Home/test”;,那么解析后,控制器为home,方法为test
2:然后调用方法_set_request():功能是先调用_validate_request(),判断控制器和方法是否存在,然后就是设置Router中class和method属性的值。
i:判断是否存在URL的后缀,如果有那么就调用URI中的_remove_url_suffix()方法来处理,
j:调用URI中的方法:_explode_segments()来将处理后的URI字符串转换成数组的形式存放到$this->segments[]数组中。
k:调用Router中的方法_parse_routes来解析用户自定义的路由。
1:该方法主要是判断用户是否自定义了路由,然后根据当前的URI信息来匹配用户自定义的路由,如果匹配上了的话,就调用_set_request()来设置当前操作类和方法,以实现路由的功能。代码:

                              //将URI参数数组用/重新组合
$uri = implode('/', $this->uri->segments);

// 判断当前的uri是否已被路由定义,
if (isset($this->routes[$uri]))
{
                      //直接设置路由中的类和方法还有参数
	return $this->_set_request(explode('/', $this->routes[$uri]));
}

// 遍历自定义的路由信息,以寻找和当前uri相匹配的数据
foreach ($this->routes as $key => $val)
{
	// 替换CI自定义的规则为正则
	$key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key));

	// 执行当期uri和路由匹配
	if (preg_match('#^'.$key.'$#', $uri))
	{
		// $route['category/(:any)'] = 'home/category/$1';
		if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE)
		{
			$val = preg_replace('#^'.$key.'$#', $val, $uri);
		}
                              //直接设置路由中的类和方法还有参数
		return $this->_set_request(explode('/', $val));
	}
}
              //设置默认的路由信息
$this->_set_request($this->uri->segments);

l:最后调用函数$this->uri->_reindex_segments();来重置索引,确保数组$segments是从1开始的。
//=======================================================================================================
上面的操作都是在CI核心文件CodeIninter.php调用$RTR->_set_routing()方法所执行的操作
简单的概括就是:
通过URI类和Router类的操作来获取当前控制器和操作方法,如果不存在,那么就调用默认的控制器方法,然后结合用户自定义的路由信息。将当前要操作的控制器和方法存起来,然后我们通过方法$class = $RTR->fetch_class();$method = $RTR->fetch_method();就可以获取要操作的对象了另外,还将URI中其他的参数放到URI类的变量$this->segments[]中,我们只要从这个变量当中取就OK了
所以CI只要这样子call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2));就可以驱动我们自己写代码和获取参数了。
那么整个项目也就跑起来了。
//================================================================================
PS:
CI提供了一个临时路由的方法:我们在CodeIninter.PHP文件中看到这么一行:

if (isset($routing))
{
	$RTR->_set_overrides($routing);
}

如果我们index.php文件中有设置这样子一个数组:

$routing['directory'] = '';//设置子控制器目录,一般为空
$routing['controller'] = 'Home';//控制器
$routing['function'] = ''; //方法

那么之前所有的路由解析将是作废的,系统会按照这个$routing数组定义的控制器和方法来运行你的程序。

CI执行过程剖析

没有评论

2011 年 07 月 09 日 at 下午 11:22分类:PHP

1、CI 中index.php文件的主要功能是:定义项目的相关路径常量,最后,加载CodeIninter.php文件,后面的事情交给他处理

2、在CodeIninter.php文件中,主要功能有:
a:加载CI核心的公共文件Common.php,内置的方法在系统全局中都会被用到,特别是:&load_class(),is_loaded(),&get_config(),config_item()函数,
b:加载文件读写属性的配置文件:constants.php
c:利用函数&load_class()加载获取某一段程序执行时间的类文件:Benchmark.php
d:利用函数&load_class()加载钩子类:Hooks.php
1:初始化时,加载了配置类Config,获取项目目录下config.php文件的配置项
2:判断在配置文件中是否开启了钩子,然后加载项目下面config/hooks.php钩子的配置文件
e:利用上一步实例化的钩子对象,来执行一个在系统执行之前执行的钩子”pre_system”,这个钩子的内容需要用户自己在hooks.php文件中配置,若不存在就不执行
f:用&load_class()加载配置类Config,做的工作是判断是否存在需要存入配置文件的变量,如果有,就存入,否则,不执行。
g:用&load_class()加载UTF8类,这个类主要是处理项目的编码的一些事情,比较简单。
h:用&load_class()加载URI类,主要是处理URI的,方便我们在项目中直接调用。
i:加载路由类Router,然后执行_set_routing()来设置路由。
j:加载输出类:Output
k:运行钩子:$EXT->_call_hook(‘cache_override’)
l:加载安全类:Security,主要是对数据进行消毒的。
m:加载输入类Input,设置获取get.post.cookie.server变量的函数,然后可以对他们进行消毒
n:加载语言类:Lang
o:加载核心控制器Controller类,通过引用方式(&)返回核心控制器的对象。
p:判断在项目的核心目录下面是否存在MY_Controller的拓展控制器,如果有,那就require_once();
q:根据路由类(Router)获取到的控制器($RTR->fetch_class()),来加载controlers下面的该控制器
///////////////////////////////////////////////////////////////////////////////////////////
到上面为止呢,系统当前执行的加载已经完毕了,既然刚刚加载我们项目的控制器,那么接下来就应该调用我们项目的控制器了
继续:
//////////////////////////////////////////////////////////////////////////////////////////
a:通过路由类来获取当前需要执行的控制器($RTR->fetch_class())和方法($RTR->fetch_method()),然后判断类和方法的合法性
b:运行钩子:$EXT->_call_hook(‘pre_controller’),在调用你的任何控制器之前调用
c:实例化项目当前路由捕获到的类,
d:运行钩子:$EXT->_call_hook(‘post_controller_constructor’);控制器实例化之后,任何方法调用之前调用.
e:判断当前的控制器中是否存在方法:_remap();,如果存在,那就直接调用该方法。否则,调用由路由捕获的方法;
f:运行钩子$EXT->_call_hook(‘post_controller’) 控制器完全运行之后调用.
g:运行钩子$EXT->_call_hook(‘post_system’);在最终着色页面发送到浏览器之后,浏览器接收完最终数据的系统执行末尾调用
h:判断是否打开数据库连接,关闭数据库连接。
//////////////////////////////////////////////////////////////////////////////
这样子,我们一个项目就运行完了。(PS:这个当然很多更加深入的就没有进行下去了,比如说路由是怎么实现的等。下次更新。。。)

架构分析查看:http://www.360doc.com/content/11/0320/21/6524307_102997671.shtml

CI中DB对象剖析

没有评论

2011 年 07 月 08 日 at 下午 5:01分类:MySQL

CI中使用DB类,只要你在你的控制器中使用了这句话:$this->load->database();那么你就可以在你的控制器中的任何地方或者是在模型的任何地方都可以使用$this->db->function()来操作数据库了。那么CI 是怎么样做到这一步的呢?下面一一道来:
首先,我做过测试,在$this->load->database()这句话之前你要是打印$this->db的话,是没有任何数据的,但是在这句话之后打印的话,那么会出现很多对象属性啊方法等信息。那么首先来看下Loader.php文件中的database方法:
该方法的主要功能有:1、通过get_instance()来获得一个CI对象,2、加载数据库初始化类文件database/DB.php,将初始化后的对象放置到$CI->db中,这样子,整个CI对象中就有了db对象了。在任何一个能获取CI对象的地方都可以使用db对象了。那么问题是:这个db对象到底是怎么了的呢?继续往下:
看下文件DB.php文件,里面就只有一个方法DB。这个方法的主要功能有:
1、加载config文件夹下面的数据库配置文件:config/database.php
2、判断当前选择的数据库,默认为$active_group = ‘default’
3、加载数据库驱动类文件/database/DB_driver.php
4、判断是否启动了Active Record 模式,如果是,那么就加载database/DB_active_rev.php文件,否则,不加载
5、判断类CI_DB是否存在,如果不存在,那么在AR模式下:class CI_DB extends CI_DB_active_record{};否则class CI_DB extends CI_DB_driver{}
6、加载指定数据库的驱动文件 如mysql的是:database/driver/mysql_driver.php
7、实例化database/driver/mysql_driver.php文件中类CI_DB_mysql_driver,这个实例化出来的对象就是我们平时用到的对象了。

类CI_DB_mysql_driver继承了CI_DB类,,然后CI_DB类 继承了CI_DB_active_record类,CI_DB_active_record类继承了CI_DB_driver类,
类CI_DB_driver是数据库的基类,
上面的继承都是在AR模式下面的
如果没有开启AR模式,那么继承方式是一样的;如下:
类CI_DB_mysql_driver继承了CI_DB类,,然后CI_DB类直接继承了CI_DB_driver类。
整个数据库的流程大致就是这样子。
//PS:
为什么我们在控制器和模型中都可以使用$this->db来操作数据库对象呢?
刚刚上面我们说了在控制器中的使用原理,那么在模型中为什么可以使用呢?
其实模型中的$this->db是完全靠控制器中的对象来实现的,主要是:
1、通过get_instance()来获取CI对象,
2、通过__get方法来获取db这个私有属性的值

function __get($key){
      return $CI->$key;
}