Category Archives: 业界杂谈

Hello World 业界杂谈 他山石

[转]来自浏览器创造者的web优化技巧

Jatinder Mann是微软Internet Explorer产品的一名项目经理,在BUILD 2012大会上,他做了题为“提高HTML5应用和网站性能的50条秘技(50 performance tricks to make your HTML5 apps and sites faster)”的演讲,介绍了很多为Web应用提速的技巧。

Mann的建议是按照下面六个原则组织的。

1. 快速响应网络请求

  • 避免重定向。排名前1000的网站中,63%使用了重定向。如果不执行重定向的话,页面速度可以提高10%。
  • 避免Meta-refresh。世界上14%的URL使用了Meta-refresh。
  • 尽可能通过CDN定位用户,使服务器响应时间最小化。
  • 从不同的域下载资源,使并发连接的应用最大化。
  • 复用连接。不要在响应请求时关闭连接。
  • 确保页面加载不会因合作伙伴网站提供的数据而延迟。
  • 了解耗时的网络组件,如重定向、缓存、DNS、请求和响应等。在IE 9和10中可以使用Navigation Timing API来测量浏览器花在每个操作上的时间。

2. 最小化下载的字节数

  • 加载页面时,要尽量减少下载的数据量。平均而言,每个页面要下载的数据量达777KB,其中有474KB的图片、128KB的脚本和84KB的Flash。
  • 请求gzip压缩的内容。
  • 将资源保存在本地的包中,比如为Windows商店应用生成的包资源索引(Package Resource Index)文件。这样当需要这些资源时就可以很容易地获取到。
  • 使用HTML5 App Cache缓存动态资源。App Cache会只下载一次资源,从而避免多次网络行程。当应用的版本号发生变化时,它会自动重新下载相应资源。
  • 尽量在响应中使用“Expires”字段来提供可缓存的内容。
  • 通过设定请求的If-Modified-Since字段来使用条件请求。
  • 缓存数据请求,如HTTP、XML和JSON等,因为大约95-96%的请求不会整天变化。虽然这个想法很合理,但实际缓存接收到的请求的网站所占比重还不到1%。
  • 用大写将文件命名标准化。虽然服务器可能把Icon.jpg当作 icon.jpg,但是对于Web平台而言,它们是不同的资源,对应不同的网络请求。

3. 高效地组织标记

  • 对于IE而言,请使用最新的标记标准,因为它速度最快。IE 10也能识别早期的IE6-IE9标记风格,但是其速度不如新的标记风格。
  • 特定的业务Web应用可能需要强制IE运行于传统模式,请使用HTTP头字段“X-UA-Compatible: IE=EmulateIE7”来代替HTML标签 ,这样速度会快一些。
  • 为了平滑地渲染,样式表应该链接在页面顶部的<head>之中的<title>后面。
  • 绝对不要在页面底部链接样式表。否则加载页面时可能会出现闪烁。
  • 对于分层样式,不要使用“@import”,因为它是同步的,会阻塞CSS数据结构的创建和屏幕绘制。
  • 避免样式的嵌入和内联,因为它会强制浏览器在HTML和CSS解析器之间进行上下文切换。
  • 仅包含必要的样式。不要下载和解析用不到的样式。
  • 仅在页面底部链接JavaScript。这可以确保脚本执行时图片和CSS等资源已经加载,无需等待,也避免了上下文切换。
  • 不要在页面开头链接JavaScript。如果某些脚本必须在开始处加载的话,请使用“defer”属性。
  • 不要内联JavaScript,这样可以避免上下文切换。
  • 使用“async”属性加载JavaScript,这样整个脚本就可以异步加载和执行。
  • 避免冗余代码。世界上52%的网页包含100行甚至更多的冗余代码,比如一个JavaScript文件被链接了两次。
  • 将一个JS框架标准化,无论是jQuery,Dojo,Prototype.js还是其他框架。浏览器没有必要加载多个功能基本相同的框架。
  • 不要加载FB和Twitter等网站的脚本,只是看起来很酷而已,它们会争用资源。

4. 优化多媒体资源的使用

  • 图片是最常用的资源,每个页面平均会下载58张图片。
  • 尽量避免下载太多图片,根据页面加载时间将图片最大数量控制在20-30之间。
  • 使用Image Sprites将多个图片组合成一个。该技术可以减少网络连接数,也会减少下载的字节数并节省GPU处理周期。
  • 手动创建Image Sprites,因为工具创建的可能会留下较大的空洞,这会加大需要下载的数据量,也需要更多的GPU 处理周期。
  • 使用PNG格式的图片,该格式在下载大小、解码时间、兼容性和压缩率之间实现了完美的折中。JPEG格式可以用于照片。
  • 使用原始的图像分辨率,这样可以避免下载不必要的数据以及缩放所需的CPU 处理。
  • 尽可能使用CSS3 Gradient替代图片。
  • 尽可能使用CSS3 border radius替代图片。
  • 使用CSS3 Transform来创建移动、旋转和倾斜效果。
  • 对于小型的单个图片,可以使用Data URI。这样可以节省一张图片的下载量。
  • 避免复杂的SVG,因为它们会延长下载和处理时间。
  • 当包含HTML5时,指定一个预览图片。这样浏览器就不必下载整个视频文件来确定预览图片了。
  • 使用HTML5来代替Flash、Silverlight或QuickTime。HTML5速度更快,而且其他几种形式的运行时插件会消耗系统资源。
  • 主动地以异步方式下载富媒体资源并将其保存在App Cache中。

5. 编写快速的JavaScript

  • 在JavaScript中进行数学运算时尽量使用整型。JavaScript的浮点运算比相应的整型运算耗费的时间要多得多。在进行数学运算,特别是计算密集型运算时,请使用Math.floor和Math.ceil将浮点数转换为整型数。
  • 降低JavaScript代码量,这样不但可以减少下载的数据量,而且能够提供更好的运行时性能。
  • 按需初始化JS。当需要时动态加载JS。
  • 通过缓存变量(如document和body等)使DOM交互减到最少。
  • 使用内置的DOM代码,如element.firstChild或node.nextSibling等。这些代码都是高度优化的,相对于第三方库能提供更好的性能。
  • 访问大量DOM元素时,使用querySelectorAll。
  • 使用.innerHTML来构建动态页面。
  • 批量标记更改。
  • 维护小巧而健壮的DOM——将其元素数目控制在1000以内。.
  • JSON快于XML。
  • 使用浏览器的JSON原生方法。
  • 不要滥用正则表达式。

6. 知道你的应用在做什么

  • 理解JavaScript定时器,了解setTimeout和clearInterval。除非确定要使用定时器完成一些功能,否则不要启动定时器。组合定时器也是如此。
  • 如果监视器的刷新率是60Hz,请将显式帧的定时器调整为16.7 ms。
  • 在IE 10、Chrome和Firefox中,图形处理请使用requestAnimationFrame动画函数。其绘制通过回调实现,因此不需要定时器。
  • 使用可见性API(document.hidden和 Visibilityhange)来确定应用程序的可见状态,如果页面是隐藏的,就关闭该活动。这样可以节省CPU和电池寿命。
  • Mann建议在IE中使用Windows Performance Tools来测试Web页面的性能, 并以减少CPU时间和增加并发性为目标进行优化

—————-
转自:http://www.searchsoa.com.cn/showcontent_68434.htm

Hello World 业界杂谈

微信二维码登录功能的实现

微信的二维码登录是个很酷的功能:客户端登录后,通过扫描web端的二维码,实现统一用在web端的登录

下面要讲的就是如何这一个功能:

实现思路:
web:访问web页面时,如果未登陆,会根据随机字符串生成二维码,显示到页面上,同时将该字符串保存起来,然后页面会通过ajax轮询方式访问web端,查看这个二维码是否可以登录,如果可以登录,则将用户名/id写入session,然后将页面跳转到登录状态
客户端:扫描页面的二维码后,通过http方式访问web端,将二维码源字符串,以及客户端登录用户的用户名/id发送过去,告诉web端这个用户可以登录

思路很简单,实现起来也不麻烦,下面会列一些核心代码,详细的,请看这个demo,代码可以到这里下载

web端:
二维码生成,使用qrcode库:

/*
 * $source  二维码源字符串
 * $temp  图片缓存目录
 * $errorCorrectionLevel, $matrixPointSize 错误等级、图片大小
 */
function getQRCodeImg($source, $temp, $errorCorrectionLevel, $matrixPointSize){
	$date = date('Ymd');
	$PNG_WEB_DIR = DIRECTORY_SEPARATOR.$temp.DIRECTORY_SEPARATOR.$date.DIRECTORY_SEPARATOR;
	$PNG_TEMP_DIR = dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'webroot'.DIRECTORY_SEPARATOR.$temp.DIRECTORY_SEPARATOR.$date.DIRECTORY_SEPARATOR;
	include_once '../lib/qrcode/qrlib.php';
	if (!file_exists($PNG_TEMP_DIR))
		mkdir($PNG_TEMP_DIR);
 
	if (!in_array($errorCorrectionLevel, array('L','M','Q','H')))
		$errorCorrectionLevel = 'M';    
 
	$matrixPointSize = min(max((int)$matrixPointSize, 1), 10);
 
	$filename = md5($source.'|'.$errorCorrectionLevel.'|'.$matrixPointSize).'.png';
 
	QRcode::png($source, $PNG_TEMP_DIR.$filename, $errorCorrectionLevel, $matrixPointSize, 2); 
 
	return $PNG_WEB_DIR.$filename;
}

页面的ajax相当简单:

//ajax轮询时间间隔,通过服务器配置得到
var ASK_TIME = <?php echo conf('ajax.time');?>;
var i = 0;
$(function(){
	setInterval(function(){
		$.get('page_ask.php?source=<?php echo $source;?>', function(d){
			//登录成功,跳转页面
			if(d && d.login){
				window.location = '';
			}
			//测试信息的显示
			$('div.test').html(i++ + '---' + JSON.stringify(d));
		}, 'json');
	}, ASK_TIME * 1000);
});

page_ask.php的核心代码,服务端存储使用mongodb

//ajax轮询检查是否登录		登录成功返回user,否则为false 
function checkSource($source){
	$collection = getDBCollection(conf('mongo.collection'));
	$sou = $collection->findone(array('_id' => $source));
	if($sou && $sou['login'] === 1){
		return $sou['user'];
	}
	return false;
}

客户端通过访问“/client_login.php?source=xxx&user=张三”实现登录,当然,实际的系统应该是传userId

//取记录  返回  1 登录成功  10 source有误  11 此source已使用过  21 无此user(暂无此项)
function checkSource4Login($source, $user){
	$collection = getDBCollection(conf('mongo.collection'));
	$sou = $collection->findone(array('_id' => $source));
	$r = 10;
	if($sou && isset($sou['login'])){
		if($sou['login'] === 0){
			$r = 1;//校验正确
		}else{
			$r = 11;
		}
	}
	//保存登录状态
	if($r == 1){
		//保存登录状态
		$collection->update(
			array('_id' => $source), 
			array('$set' => array('login' => 1, 'user' => $user)), 
			array('safe'=>true)
		);
	}
	return $r;
}

下面是客户端的几个片段,这里使用的是ios
二维码扫描使用的库是ZBar,注意,需要添加一坨frameworks

-(IBAction)startScan:(id)sender
{
    ZBarReaderViewController *reader = [ZBarReaderViewController new];
    reader.readerDelegate = self;
    ZBarImageScanner *scanner = reader.scanner;
    [scanner setSymbology:ZBAR_I25 config:ZBAR_CFG_ENABLE to:0];
    [self presentModalViewController:reader animated:YES];
    [reader release];
}
//将上面这个方法注册给“开始扫描”按钮:
[QRBut addTarget:self action:@selector(startScan:) forControlEvents:UIControlEventTouchUpInside];
//扫描成功后,会自动调用此方法
- (void) imagePickerController: (UIImagePickerController*) picker didFinishPickingMediaWithInfo: (NSDictionary*) info
{
    UIImage *image = [info objectForKey: UIImagePickerControllerOriginalImage];    
    id<NSFastEnumeration> results = [info objectForKey: ZBarReaderControllerResults];
    ZBarSymbol *symbol = nil;    
    for(symbol in results){
        break;
    }    
    if(!symbol || !image){
        return;
    }    
    NSLog(@"symbol.data = %@", symbol.data);  
    [self sendRQcode:symbol.data];  
    [picker dismissModalViewControllerAnimated: YES];
} //imagePickerController

//取得二维码后,通过http方式发送,然后解析返回的json数据

- (void) sendRQcode:(NSString*)code
{
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:0];
    NSTimeInterval a=[dat timeIntervalSince1970];
    NSString *timeString = [NSString stringWithFormat:@"%f", a];
    NSHTTPURLResponse* urlResponse = nil;
    NSError *error = [[NSError alloc] init];
    NSLog(@"-------loginClick------user:%@", timeString);
    NSString *url = [[[[[@"http://xxxxxx/client_login.php?user=" stringByAppendingString:user]                     
            stringByAppendingString:@"&source="] stringByAppendingString:code]
            stringByAppendingString:@"&time="] stringByAppendingString:timeString];
    [request setURL:[NSURL URLWithString:url]];
    [request setHTTPMethod:@"GET"];
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];  
    //发送请求  
    NSData *returnData = [NSURLConnection sendSynchronousRequest:request 
            returningResponse:&urlResponse error:&error];
    NSLog(@"-------sendRQcode--status:------%d", [urlResponse statusCode]);
    NSString *login = @"0";
    if(returnData != NULL && [urlResponse statusCode] == 200) {
        //解析json
        NSDictionary *data = [returnData objectFromJSONData];
        NSLog(@"-------sendRQcode----returnData:------%@", data);
        login = [data objectForKey:@"login"];
    }
    NSLog(@"-------sendRQcode----login:------%@", login);
    msg = @"";
    if([login isEqual: @"1"]){
        msg = @"登录成功!";
    }else if([login isEqual:@"0"]){
        msg = @"网络连接错误,请检查网络设置后重试!";
    }else{
        msg = [[@"未知错误(login:" stringByAppendingString:login] stringByAppendingString:@"),请检查网络设置后重试!"];
    }
    NSLog(@"-------sendRQcode----msg:------%@", msg);
    [self alertWithMessage:msg];
}//sendRQcode

———–
代码就展示这么多,具体的,请访问github:https://github.com/jklgithub/qrcode_login
本文为本人原创,转载请注明地址:http://www.jiangkl.com/2012/10/%E4%BA%8C%E7%BB%B4%E7%A0%81%E7%99%BB%E5%BD%95_qrcode_zbar/
演示地址:dev.jiangkl.com (mongo不太稳定,测试不通的话可以给我留言)

业界杂谈 他山石

[转]提升CakePHP网页应用速度的八大方法

原文标题:8 Ways to Speed Up the Performance of CakePHP Apps

引言

CakePHP 有些慢已经不是什么公开的秘密了。但不为众人所知的是这是一个大大的阴谋。而我会因揭露这个阴谋惹上不少麻烦。不过我愿意冒险一搏。我手头有大量的记录和文档线索表明CakePHP开发团队的成员手头持有戴尔,IBM,思科以及其他服务器厂商的公司股票。想必你已经听说过这类的措辞像“硬件白菜价,而程序员太金贵了。”Cake的开发团队从中嗅到了商机,他们便制作出了这款易于上手和开发,但是却跑得很慢的框架来。他们希望你在硬件方面多砸点钱来。这点子太有才了吧,对不?好了,闲扯就此结束。作为一个CakePHP的开发者,每当你学会使用本文中的一个技巧,套在你脖子上的这枷锁就少了一层。

注意:

本文认为你已经在使用ContainableBehavior并且已经对你的SQL查询进行优化和索引了
我使用ab(ApacheBench是Apache自带的HTTP性能测试工具)对所有改动后的性能进行了测试,并与基准值做了对比。这里的基准值是 debug级别为0时的简单应用程序的性能。我并没有把实际基准数字贴出来。因为这类数字会因应用程序和机器性能而波动。不过我将以百分比的形式将大概的 性能提升数据附在了文中。
另外,你想看看我测试所用的应用程序内容?门儿都没有。

一、 将debug级别设置为0

这技巧很没技术含量,是吧?在Google小组中有 大量的帖子在扯其他方法。想都不用想,先把你CakePHP应用程序的debug级别设置为0在说。

将此值设0和不设0是有区别的,原因就在Cake引 擎生成两部分缓存内容

第一部分是/tmp /cache/models中的缓存内容。在这里,你会看到每个模型都有一个对应的文件,这些文件中包含的是数据库的表模式(table schema)。想必你已经看到过数据库查询记录中包含一些”DESC table;” 这类的查询内容,这些缓存文件就是做着这个用的。当debug级别设置为0时,这些数据库查询就不会进行。

第二部分的缓存是在/tmp /cache/persistent中。当你运行你的Cake网页应用时,CakePHP会用到其中几种不同的文件。而通常拖慢CakePHP运行速度最 厉害的当属cake_core_file_map。这个文件保存了到各个不同类的路径信息。为了创建这个文件,CakePHP会做一个必须但是也是非常耗 费时间的搜索,以便在你的目录结构中找到对应的文件。

那么,debug级别是0和debug级别大于0时有什么区别呢?呵,他们两者之间相差的是2.73517104年。当debug级别大于0时,这些缓存文件的时间周期是10秒钟。而把debug级别设置为0时,这些文件的缓存时间周期则是999 天。(译者:这就是前面 2.73517104年差距的来历)

实 际上我这里有这样一个疑问:既然这种事情是非常“脑残”的技巧,那么连这种“脑残”的技巧都不采用的人是不是比“脑残”好“脑残”呢?如果连“脑残”的人 都能弄明白这种技巧,那么那些不会的人的脑子是不是被狗吃了。既然这些人的脑子被狗吃了,那么我对这钟人讲这种技巧岂不是肉包子打狗——有去无回?(译 者:囧)

性能大致提升数字为:80%到100%左右

二、缓存拖慢速度的查询/网络服务请求等等

对于缓存你应用程序中的单个部件而 言,CakePHP的缓存库(cache lib)是一个非常不错的工具。它会处理所有“脏重累的活儿”,比如向缓存引擎中的文件或者内存中写入内容。你所需要做的就是想清楚哪些东西需要缓存。

打个比方说,你有一个已经索引并已经优化了的数据库 查询,但是查询速度还是比较慢。CakePHP的烹饪手册上(link)就提供了一个例子,教你 如何将缓存库应用起来,缓存后,CakePHP就不会对每一个请求都进行这种拖慢速度的数据库查询。

如 果你网站的部分内容是来自其他网络服务的的,比如一个显示最新推文的区域(这个例子并不恰当,因为大多数Twitter挂件都是用JavaScript写 成的,这里读者就将就一下吧。)我们完全没必要对每个发来的请求都调用这个网络服务。只需像上面一样,用缓存功能将其缓存起来即可

性能提升:+0% 到 1000000%,这取决于你的应用程序,以及你所缓存的内容。

三、缓存视图

你可将这视作整个页面的缓存。CakePHP的烹饪手册提供了一些基本的知识(link),因为页面创建依然是通过PHP进 行,所以对于保持页面的部分动态内容还是有些灵活方法的。比如,如果你运营着一个网店时,你可以将产品页面进行缓存,但是页面上还是可以有一块区域来显示 用户的购物车内容,

注意:在CakePHP的烹饪手册中有一个专门的小节来介绍CakePHP支持的各种缓存引擎(link)。 但是,目前的版本(1.2.1.8004),视图缓存所使用的是基于文件的缓存引擎,并不依赖于上面第二部分所说的缓存库( cache library)
速度大致提升:+130% 到 160%

四、HTML网页页面缓存

这个是我们自己的想出来的(link)。 它的原理跟WordPress上的Super Cache插件一样。它会将CakePHP的 页面以HTML文档的形式直接写入网站的根目录。下次,当用户点击这个页面时,你的服务器会直接将这个HTML文件传输给用户,而无需运行PHP。

这种方法也有其明显的局限性,比如缓存的页面上完全 没有动态内容,缓存的内容也不会自动清除。但是,对于RSS的订阅源或者其他像popurls 这种所有浏览者所看到的都是同样内容的页面而言,这种方法就非常不错。

速度提升:~60000%——这绝非夸张,这才是真正的速度提 升

五、 APC

维基百科是这样描述APC的,“它是一种自由的开源框架,它可以优化PHP的中间 代码,并在共享内存中缓存PHP字节码编译器(Bytecode compiler)中的数据和编译好的代码。”(维基百科链接)。总的来说,速度真TMD的 快,并且你还无需改动你的代码。很爽,是吧?

速度提升:+25% 到 100%

六、持久性模型

CakePHP的烹饪手册并没有提及这个技巧,这个 功能的开启很简单,你只需在你的控制器(或者父控制器中)中添加如下属性即可

var $persistModel = true;

在页面刷新后,你会注意到 /tmp/cache/persistent 目录下会出现两个新的文件,它对应控制器所包含的每个模型。一个文件是模型的缓存,另一个缓存的是类注册器(ClassRegistry)中的对象。跟上 面所提到的视图的缓存一样,这种缓存只会保存在文件系统中。

速度提升:+0%到200%

这种方法效果怎么样取决于你的应用程序。如果你的控制器只有一个模型,并且并没有与其他任何模型关联,那么你不会看到有多大的速度提升。在我们的测试应用程 序中,它带来的速度提升大约在100%左右。其中测试用的控制器中有一个模型,该模型关联其他三个模型,这些关联的模型又有各自关联的模型。

七、在APC中存储持久性缓存内容

要使用这个,你需要开启APC,将CakePHP的 核心缓存模式设置为APC。在core.php文件中,添加如下代码。

Cache::config(‘_cake_core_’, array(‘engine’ => ‘Apc’,
‘duration’=> 3600,
‘probability’=> 100,
));
这会将通常缓存在/tmp/cache/persistent 中的缓存文件(不包括持久性模型)保存到内存中去。

速度提升:~25%

这带来的速度提升很难衡量。我试着启用不带指令缓存 (opcode caching)的APC,以便衡量所带来的速度提升,但是却找不到如何设置。

八、加速反向网址路径的寻找

目前有两种方法可以达到此目的。第一种是Debuggable.com网站上Tim同学在一篇文章中所提及的。Tim的方法只对某种链接类型有效,而且还会破坏反向网址路径的寻找功能,而我的方法使用的是缓存功能(link) (译者:具体内容见这个链接。),CakePHP开发团队的Nate同学也称这种方法非常“高明”(link)

速度提升:~50%

正如这里的所有技巧一样,实际的速度提升取决于你的 应用程序。如果你并不使用大量的自定义网址路径,而且页面的链接也不多,那么这个技巧不会带来多大的速度提升

——
转自:http://21haolou.com/articles/show/46

业界杂谈 日志

一年又一年

间总是过的很快,前几天忙着“优化“自己一年前写做的东西~~忍不住有点感慨。

每看到一段写的很烂的代码,或者找不到要改的逻辑在哪儿时,总会怀疑:这是我写的吗?真的是我写的吗~~(不是你还有谁!!)如果时间允许,真想再重构一次~~可惜时间不允许呀。

去年做这一版时,正是刚开始专js的时候,当时一知半解,又自以为是,很多做法现在看来不仅效率低下,开发麻烦,而且用户体验也不好~~如果当时身边有个js牛人指点指点可能会好很多。

而这一版之前的一版,大约也是在再上一年写的。那时对js的理解还仅停留在jquery和最初级的面向对象的层次,所以那一版虽然功能比较简单,不过两三千行代码,但页面执行已经相当之慢,逻辑乱的改一个小地方也要找半小时。

看过一个微薄说人身体的细胞每7年就会更换一遍,从这层意义上说,7年以后的你就是另外一个人了。可是看自己的代码,似乎一年以后就是另外一个自己了,作为每时每刻都会诞生新东西的行业,程序员需要不间断的学习充实自己,然后不停的去否定,去更新以前的自己,然后就慢慢变成更好的另一个自己。

希望自己可以克服惰性,继续保持谦卑的学习心态~~~~

Hello World 业界杂谈

IE出没,当心!!

有多少前端攻城湿,就有多少IE受害者~~~ →_→

    这段时间开始搞webview,html5~~~~本来以为总算可以暂时逃离IE的魔咒了,可是没想到的是,除了iphone和android,还有个wp7,wp7里还有个IE9,之前听说IE9支持html5,所以开始并没有把它放在心上,可是真正要用它的时候,问题来了

    开始的时候是习惯的拿alert测试,没反应,把页面内容删光,只剩一个alert也不行,google一下,以为是客户端对webview功能做了限制,去找客户端同事,人家很委屈的说,没做任何限制~~~好吧,不能alert,换其他方法测试

    然后是发觉click绑定有时不成功,开始以为绑定方法不对,试遍了jquery的的live、click、bind,和DOM的onclick,都不行,将同样的页面直接用wp7的IE9打开,于是又去找客户端,这次同事认真查了wp7的手册,回复给我一段文档,大意是说:wp7的webview只支持简单的html显示。可是其他很多js功能是可以用的~~~嗯,也就是说具体支持哪些js功能~~没准~~~~这便是悲剧之源

    后来,死马当活马医,将链接的“href=javascript:void(0)”,改成“href=#”,click绑定居然起效了~~~~尼玛的微软,连最屎的IE6都支持“void(0)”

    做技术的有句话:发现了问题就等于解决了问题~~~~可是对于眼下这种薛定谔的猫的问题,真的没办法了,除非有时间一个一个试去~~~~可惜没时间~~~~无奈,降格,把你当wap用总可以吧!!!

蒙娜丽莎