文章标签 ‘前端’

1 条评论太NB了:Google Docs Ctrl + C 技术浅析

2010年7月27日

玉伯那里转来的,Goole非常NB
用 google docs 打开 pdf 文件,选中文本:

表面上没有任何有趣的地方。但仔细一看,会发现选区的颜色是浅蓝色,而不是默认蓝。第一直觉是是有什么特殊的 CSS 属性,立马 firebug:

不看不知道,一看真蹊跷。selection-highlight 是选区,选区下面是一张图片 page-image!
于是立刻发现一个非常牛逼的特性:Ctrl + C 可以复制图片中的文字!

google 太强悍了,好在前端代码都是开源的,下面简单分析下。

首先数据在哪呢,这个比较容易找到,在 firebug 里有一个请求返回的数据如下:

<?xml version="1.0" encoding="UTF-8"?>

<pdf2xml>
<meta name="Creator" content="Adobe Acrobat 8.1 Combine Files"/>
<meta name="Producer" content="Adobe Acrobat 8.1"/>
<meta name="CreationDate" content="20100316080708-04'00'"/>
<page t="0" l="0" w="612" h="773">
 <text l="188" t="754" w="237" h="11" p="188,24,214,15,232,37,271,
7,280,39,322,7,330,11,344,24,370,23,395,20,418,7">
Please post comments or corrections to the Author Online forum at</text>
...

有了这份数据,就可以根据选区得到对应的文本。

接下来的问题是,如何将文本放到剪贴板里?第一反应是用 flash 实现,但感觉 google 不会这么做。禁用掉 flash 插件后,功能正常,这说明是用 js 实现的。

通过 Profile 工具 + Fiddler + 肉眼识别 + 运气,终于定位到了关键代码:

n.am = function(a) {
    if (! (!this.k.Ca && Mr(this, a))) {
        ac && this.lf.focus();
        this.lf.select();
        Nr(this, a)
    }
};

只要注释掉上面的代码,Ctrl + C 复制功能就无效。focus 和 select 为我们提供了进一步线索,在 HTML 里,发现了秘密:

到此真相大白:当用户按下 Ctrl + C 时,js 会注入事件,首先根据坐标从数据里取出对应文本,然后将文本赋值给 textarea, 并将其激活和选中。这样,就和用户选中 textarea 的内容,再按下 Ctrl + C 的效果是一样了。

强悍的 google, 技术创新无处不在!

注意:利用 textarea 只能复制纯文本,如果想复制富文本,可以借鉴 google docs 编辑 Word 文档时的处理方式:采用 iframe 充当临时容器,有兴趣的可以进一步研究。

简单演示:goog-docs-copy-demo.html

发现这个秘密后,最近在疯狂搞编辑的牛人承玉(欢迎搞编辑器的其他牛人加盟)立刻想到了各大站长们非常喜爱的功能:附带警告信息的禁止copy. 据说,能成功复制的,都不是“人”。

我的尝试是:点击按钮,复制指定文本到 Clipboard 里。应用场景是点击按钮复制证件号码等。尝试代码大家可以看上面 demo 页面源码中的注释。事件可以正常模拟并分发出去,但复制操作惨兮兮地失败了。感觉原因在于浏览器安全限制,对于触发的异步 Ctrl + C, 浏览器会限制其功能。

Google 的产品里有很多秘密,真诱人,创意无限!

没有评论判断 iframe 是否加载完成的完美方法

2010年6月22日

今天正好需要判断iframe加载完成 正好找到怿飞同学的这篇文章 方法很完美

var iframe = document.createElement("iframe");
iframe.src = "http://www.planabc.net";

if (!/*@cc_on!@*/0) { //if not IE
    iframe.onload = function(){
        alert("Local iframe is now loaded.");
    };
} else {
    iframe.onreadystatechange = function(){
        if (iframe.readyState == "complete"){
            alert("Local iframe is now loaded.");
        }
    };
}

document.body.appendChild(iframe);

最近, Nicholas C. Zakas 文章《Iframes, onload, and document.domain》的评论中 Christopher 提供了一个新的判断方法(很完美):

var iframe = document.createElement("iframe");
iframe.src = "http://www.planabc.net";

if (iframe.attachEvent){
    iframe.attachEvent("onload", function(){
        alert("Local iframe is now loaded.");
    });
} else {
    iframe.onload = function(){
        alert("Local iframe is now loaded.");
    };
}

document.body.appendChild(iframe);

几点补充说明:

  1. IE 支持 iframe 的 onload 事件,不过是隐形的,需要通过 attachEvent 来注册。
  2. 第二种方法比第一种方法更完美,因为 readystatechange 事件相对于 load 事件有一些潜在的问题。

没有评论即拷即用动画函数:透明度渐变、位置移动、尺寸变化

2010年3月31日

首先感谢一下 51js的 abeet 同学 给我们提取出这么简洁的函数
和大家分享一下吧 查看Demo
这三个函数适用于以下情况
1、在做前端页面时,只需要简单的动画效果,不想引入整个动画类,使用本函数。
2、在写js类时,需要用到简单的动画,为了降低藕合性,使用本函数。

使用方法如下:

var fade = function(element, transparency, speed, callback){……}
透明度渐变:transparency:透明度 0(全透)-100(不透);speed:速度1-100,默认为1
例<input onclick="fade('testDiv', 40)" type="button" value="透明度变化" />

var move = function(element, position, speed, callback){……}
//移动到指定位置,position:移动到指定left及top 格式{left:120, top:340}或{left:120}或{top:340};speed:速度 1-100,默认为10
例<input onclick="move('testDiv', {top:400})" type="button" value="垂直移动" />

var resize = function(element, size, speed, callback){……}
//长宽渐变:size:要改变到的尺寸 格式 {width:400, height:250}或{width:400}或{height:250};speed:速度 1-100,默认为10
例<input onclick="resize('testDiv', {height:300})" type="button" value="改变高度" />

核心代码分析
1、获取一个元素的透明度

如果是IE浏览器,则攻取最终样式的滤镜filter的值,再通过正则表达式获取到透明度滤镜alpha的值,如果不存在透明度滤镜值,则透明度为100。
如果是非IE浏览器,那么可以获取最终样式的opacity属性,

function getOpacity(elem){
var alpha;
if(navigator.userAgent.toLowerCase().indexOf('msie') != -1){
alpha=elem.currentStyle.filter.indexOf("opacity=") &gt;= 0?(parseFloat( elem.currentStyle.filter.match(/opacity=([^)]*)/)[1] )) + '':
'100';
}else{
alpha=100*elem.ownerDocument.defaultView.getComputedStyle(elem,null)['opacity'];
}
return alpha;
};

2、设置透明度
这个就简单了,不用管浏览器,通通的设置opacity及filter,
element.style.opacity = start / 100;
element.style.filter = ‘alpha(opacity=’ + start + ‘)’;
实际上这儿我偷了个懒,真正无懈可击的写法,应该是判断一下是否IE浏览器,因为在一些情况下可能使用多个滤镜,这时应该用正则替换alpha滤镜的值,而不是直接设置style.filter = ‘alpha(opacity=’ + start + ‘)’;

3、element.offsetWidth、element.offsetHeight与element.style.width、element.style.height的关系
只有在IE的border-content式盒模型情况下,这两个值才是相等的,即elementoffsetWidth==element.style.width+element.style.paddingLeft+element.style.paddingRight+element.style.borderLeftWidth+element.style.borderRightWidth
而我认为border-content式盒模型是符合修改元素尺寸时的心理预期的,对非border-content式盒模型情况下要作一个尺寸的修正。
在其它情况下应该对该值加以修正

if(!(navigator.userAgent.toLowerCase().indexOf('msie') != -1&&document.compatMode == 'BackCompat')){
//除了ie下border-content式盒模型情况外,需要对size加以修正
var CStyle=document.defaultView?document.defaultView.getComputedStyle(element,null):element.currentStyle;
if(typeof(size.width)=='number'){
size.width=size.width-CStyle.paddingLeft.replace(/D/g,'')-CStyle.paddingRight.replace(/D/g,'');
}
if(typeof(size.height)=='number'){
size.height=size.height-CStyle.paddingTop.replace(/D/g,'')-CStyle.paddingBottom.replace(/D/g,'');
}
}

有人认为以上的修正中默认了padding值的单位是px并且为整数,是不对的,
实际上经由我在ie及firefox下的测试,引用最终样式的padding值,必然是整数,并以px为单位。

4、关于把三个函数合并成一个通用动画函数
以上三个函数的主要逻辑都是一样的:
通过setInterval每隔一定时间修改元素的style属性,以达到动画效果。
所以,把三个函数合并成一个函数是可以的
只是需要在修改特定的属性时出于兼容性,必须作些处理,
因为不同的属性其值类型及单位不一样,不同浏览器下也有区别
如透明度 在非ie下为小数,在ie下是一个特别的滤镜设置
如颜色 一般是用16进制,并有#号前缀
预计这个通用的动画函数的参数会有点多,接口类下
function animator(element, interval, start, end, style, speed, tmp, callback){……}
说明
function animator(元素或元素ID, 计时器句柄,起始值,目标值,需修改的属性, 步进值(增量),值转换过滤方法(用于修改非普通递增递减形的数据,比如16进制颜色递增、前缀符号后缀单位修正), 回调函数)
function animator(‘testdiv’,'bgcolor’,'#336699′,’#aabbcc’,'backgroundColor’,2,changeColor,callback)
颜色修改方法示例(仅供参考,未测试)

changeColor=function(start,end,speed){
var _10to16 = function(color){
function tmp(index){
var tmp = color[index].toString(16);
return tmp.length == 1 ? "0" + tmp : tmp;
};
return "#" + tmp(0) + tmp(1) + tmp(2);
};
var x16to10 = function(color){
if(!/^#[0-9A-Fa-f]{3,6}$/i.test(color))retun color;
function tmp(index){
return color.charAt(index);
};
color = color.substring(1);
if(color.length == 3)
color = tmp(0) + tmp(0) + tmp(1) + tmp(1) + tmp(2) + tmp(2);
return [parseInt(tmp(0) + tmp(1), 16), parseInt(tmp(2) + tmp(3), 16), parseInt(tmp(4) + tmp(5), 16)];
};
var color = x16to10(start),
var end = x16to10(end),
var index = 3;
while(index--)
color[index] = color[index] < end[index] ? min(color[index] + speed, end[index]) : max(color[index] - speed, end[index]);
reutn color;
}

原文见:http://bbs.51js.com/viewthread.php?tid=86901

6 条评论第六期WEB标准化交流会 会后总结 By 刘钢

2010年3月28日

今天去参加了第六期WEB标准化交流会,重复下话题:前端开发在研发流程中与其他岗位协作效率的提升 做个小总结 

先感谢一下北京腾讯给我们提供了场地,水,和公仔,今天听了很多“大虾”们的分享,感受颇深
就说一下小公司前端开发在研发中如何更好的协作吧 

今天会议上几个突出的词:“流程”,“沟通”,“专业“,“吃饭喝酒”:) 

那我就分别说一下自己的见解
1.“流程”,存在即是合理的,社会所必须承受的,就像高房价一样,很多时候“流程”被我们吹捧的就像一个神一样,貌似能解决一切问题,而实际上我认为,流程只是一个比较虚的东西,什么是流程?就是一种大家认可的协作方式,在中小企业里我认为无流程就是最好的流程 

2.“沟通”,为什么沟通?怎样沟通?今天腾讯的页面组leader说得好:“沟通就是情商,情商会从你的绩效考评里反映出来”,什么意思呢?也就是“强制沟通”,我认同这个观点,有效的沟通能够大大提升我们的效率,以及信息不对称等问题,我也希望所有的前端朋友们,一定要学会使用“沟通”这个武器,很多时候他能解决你技能所解决不了的问题 

3.“专业”,专业是什么?kejun兄补充的好-“专业就是饭碗”,我们要提升自身专业度,在研发流程中承担更多的职能,现在有多少公司里,后端不做一些“前端”的活呢?这也可能目前前端开发是“解耦”的最好途径 

4.“吃饭喝酒”,同事间朋友间,需要有一些私下的沟通与了解,适当的有些活动,能够在工作配合上更加的顺畅,当然了吃饭喝酒只是其中之一,更多的在轻松地环境下交流交流,增进一下友谊,本次讨论会后聚餐共16人哦:) 

kejun在最后公布了之前出的html面试题的答案 有兴趣的 移步这里
http://www.iamued.com/qianduan/1373.html

最后借用一张崔凯发的合影结尾吧:) 

第六期WEB标准化交流会合影{点击放大}

没有评论kejun的HTML面试题答案揭晓

2010年3月28日

有这么一段HTML,请挑毛病:

<P>&nbsp;&nbsp;哥写的不是HTML,是寂寞。<br><br>&nbsp;&nbsp;我说:<br>不要迷恋哥,哥只是一个传说

这是原来雅虎一道笔试题(文字变了变),用了很多年了,还没有一个人完全答对过。
下周(3.27)交流会上我会公布答案  点击查看第六期WEB标准化交流会 总结

============== 解答部分 ================

出这道题的动机是,太多人觉得HTML太简单,但它恰恰又是前端开发中最基础最重要的部分。HTML结构设计的合不合理,直接影响到代码易不易维护,灵不灵活,同时事关网页性能,协作效率。碰到不少人认为前端开发就是javascript开发,大错特错啊。javascript, html, css这三个前端开发的基础支柱,性质完全不同又紧密关联,对它们的正确理解,合理应用是专业与非专业的区别。有些后端工程师可以写出很漂亮的JS,但他们真的不懂怎么合理的把js, html, css结合起来应用。对html的准确把握,不像学一般的编程语言那样,而是建立在丰富实践经验和体会的基础上,是前端的工程师的基本功。

这不是一道较真题或是装逼题,正经一道“画鸡蛋”的题(引自http://twitter.com/RageCarrier/status/10712084993)考的是基本功。代码如其人,对一行代码的理解足以反映出他的前端开发素养。

言归正传。这道题的考点:

考点1:html和 xhtml的区别
这行代码在html 4.01 strict下是完全正确的,在xhtml 1.0 strict下是错误一堆的。所以明显是一个考点。在xhtml下所有标签是闭合的,p,br需要闭合, 标签不允许大写,P要小写。同时nbsp和br必须包含在容器里。html下这些都不是错。p在html里是可选闭合标签,是可以不用闭合的。

这个考点告诉你xhtml是多么苛刻。这是基本考点,答对,你能拿到60分。

考点2:考样式分离
用nbsp控制缩进是不合理的。应该用CSS干这事。所以应该删掉nbsp

考点3:合理使用标签
br是强制折行标签,p是段落。原题用连续的br制造两个段落的效果,效果是达到了,但显然用的不合理,段落间距后期无法再控制。正确的做法是用两个p表现两个段落。“我说”后面是正常的文字折行用br是合理的。

上面全答对,你就能拿到100分。

对原题改进的结果:
html 4.01:
<p>哥写的不是HTML,是寂寞。<p>我说:<br> 不要迷恋哥,哥只是一个传说

xhtml 1.0:
<p>哥写的不是HTML,是寂寞。</p><p>我说:<br /> 不要迷恋哥,哥只是一个传说</p>

加分:合理的用语义化标签
在前面的基础上合理的用语义化标签,对内容进行必要的标记,是加分的。但过度的使用标签,就画蛇添足了。如“我说”的话,可以用q标签标注。

<p>哥写的不是HTML,是寂寞。
<p>我说:<br> <q>不要迷恋哥,哥只是一个传说</q>

我觉得这就够了,如果再进一步,“我”用cite标注,“HTML” 用abbr或acronym标注(至于再讨论abbr和acronym的区别就太较真了),也OK。再复杂就没必要了。

<p> 哥写的不是<abbr title=”Hyper Text Markup Language”>HTML</abbr>,是寂寞。
<p><cite> 我</cite>说:<br> <q>不要迷恋哥,哥只是一个传说</q>

转自kejun的blog:http://hikejun.com/blog/?p=548