<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet href='http://feed.feedsky.com/styles/feedsky8.xsl' type='text/xsl' ?><!--这是一个由Feedsy提供技术支持的Feed，为了提高读者阅读的体验，以及满足用户美化自己Feed的需要，我们设计了多种精美的Feed模板，提供给大家选择，所有最终呈现出来的样式，皆由用户自愿选择使用，未经许可，任何团体和个人，请不要擅自修改样式或者盗用，这是对于用户选择权的尊重。--><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fs="http://www.feedsky.com/namespace/feed" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link href="http://feed.pmme.cn" type="application/rss+xml" rel="self"></atom:link><fs:self_link href="http://feed.feedsky.com/berg" type="application/rss+xml"></fs:self_link><lastBuildDate>Sun, 20 Jun 2010 13:17:43 GMT</lastBuildDate><title>冰山一角</title><description>关注技术、世界上各种新奇的事物、思想以及记录自己</description><link>http://www.pmme.cn</link><sy:updatePeriod>hourly</sy:updatePeriod><sy:updateFrequency>1</sy:updateFrequency><language>en</language><pubDate>Sun, 20 Jun 2010 13:19:36 GMT</pubDate><item><title>l2tp vpn搭建总结(linode ubuntu)</title><link>http://www.pmme.cn/archive/how-i-install-l2tp-on-linode-ubunt/</link><content:encoded>&lt;p&gt;前段时间开始，公司的vpn开始不太好用了，因此我也逐步感觉到墙的力量。&lt;/p&gt;
&lt;p&gt;恰好&lt;a href=&quot;http://www.twitter.com/chzealot&quot;&gt;@Zealot&lt;/a&gt;有一个linode的vps，之前他搭了一个pptp的vpn，但是联通3g又不能使用pptp vpn，于是尝试自己捣鼓一个l2tp的vpn，断断续续尝试了几次，终于在今天成功了。&lt;/p&gt;
&lt;p&gt;参考了很多网上的文章，发现网上的文章都没有涵盖到我碰到的种种问题，因此在这里针对我的案例，写一篇总结性的文章。&lt;/p&gt;
&lt;p&gt;首先，按照&lt;a href=&quot;https://apple4.us/2010/05/setting-up-l2tp-vpn-on-debian-ubuntu.html&quot;&gt;apple4us的文章&lt;/a&gt;，安装一系列软件，写配置：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;
sudo aptitude install openswan&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;vim /etc/ipsec.conf
&lt;/p&gt;&lt;/blockquote&gt;
&lt;pre&gt;
config setup
    nat_traversal=yes
    virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12
    oe=off
    protostack=netkey

conn L2TP-PSK-NAT
    rightsubnet=vhost:%priv
    also=L2TP-PSK-noNAT

conn L2TP-PSK-noNAT
    authby=secret
    pfs=no
    auto=add
    keyingtries=3
    rekey=no
    ikelifetime=8h
    keylife=1h
    type=transport
    left=222.222.222.222
    leftprotoport=17/1701
    right=%any
    rightprotoport=17/%any&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;注意，ipsec.conf对格式要求很严格，缩进一定要有。&lt;br /&gt;
&lt;/strong&gt;&lt;br /&gt;
&lt;blockquote&gt;vim  /etc/ipsec.secrets&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;222.222.222.222   %any:  PSK &amp;#8220;fan1qiang&amp;#8221;
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;这里的psk要解释一下，这个是你在连接l2tp vpn时，需要填写的secret。&lt;br /&gt;
此外，&lt;strong&gt;别忘记把222.222.222.222替换成你自己服务器的ip&lt;/strong&gt;（一共两处）。继续：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;for each in /proc/sys/net/ipv4/conf/*&lt;br /&gt;
do&lt;br /&gt;
    echo 0 &amp;gt; $each/accept_redirects&lt;br /&gt;
    echo 0 &amp;gt; $each/send_redirects&lt;br /&gt;
done
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;然后检查ipsec是否ok了&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;sudo ipsec verify
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;下面是我最终的结果：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Version check and ipsec on-path                                 [OK]&lt;br /&gt;
Linux Openswan U2.4.12/K2.6.18.8-linode22 (netkey)&lt;br /&gt;
Checking for IPsec support in kernel                            [OK]&lt;br /&gt;
NETKEY detected, testing for disabled ICMP send_redirects       [OK]&lt;br /&gt;
NETKEY detected, testing for disabled ICMP accept_redirects     [OK]&lt;br /&gt;
Checking for RSA private key (/etc/ipsec.secrets)               [DISABLED]&lt;br /&gt;
  ipsec showhostkey: no default key in &amp;#8220;/etc/ipsec.secrets&amp;#8221;&lt;br /&gt;
Checking that pluto is running                                  [OK]&lt;br /&gt;
Two or more interfaces found, checking IP forwarding            [OK]&lt;br /&gt;
Checking NAT and MASQUERADEing&lt;br /&gt;
Checking for &amp;#8216;ip&amp;#8217; command                                       [OK]&lt;br /&gt;
Checking for &amp;#8216;iptables&amp;#8217; command                                 [OK]&lt;br /&gt;
Opportunistic Encryption Support                                [DISABLED]&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;其中需要注意两项：Checking for RSA private key和Opportunistic Encryption Support，第一项其实你大可不必管他，disable或者ok都行。如果你实在要解决，可以：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;ipsec newhostkey &amp;#8211;file /root/tmpkey&lt;br /&gt;
cat /root/tmpkey &amp;gt;&amp;gt; /etc/ipsec.secrets&lt;br /&gt;
rm /root/tmpkey
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;第二项DISABLED是正常状态。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;出了问题不要被这两项迷惑，不是他们导致的。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;接下来启动：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;sudo /etc/init.d/ipsec restart
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;如果出现错误，按照他指出的行数自己看看。接下来是l2tpd。&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;sudo aptitude install xl2tpd
&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;vim /etc/xl2tpd/xl2tpd.conf
&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;[global]&lt;br /&gt;
ipsec saref = yes&lt;/p&gt;
&lt;p&gt;[lns default]&lt;br /&gt;
ip range = 10.1.2.2-10.1.2.255&lt;br /&gt;
local ip = 10.1.2.1&lt;br /&gt;
;require chap = yes&lt;br /&gt;
refuse chap = yes&lt;br /&gt;
refuse pap = yes&lt;br /&gt;
require authentication = yes&lt;br /&gt;
ppp debug = yes&lt;br /&gt;
pppoptfile = /etc/ppp/options.xl2tpd&lt;br /&gt;
length bit = yes
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;然后安装、配置ppp：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;sudo aptitude install ppp
&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;vim  /etc/ppp/options.xl2tpd&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;require-mschap-v2&lt;br /&gt;
ms-dns 208.67.222.222&lt;br /&gt;
ms-dns 208.67.220.220&lt;br /&gt;
asyncmap 0&lt;br /&gt;
auth&lt;br /&gt;
crtscts&lt;br /&gt;
lock&lt;br /&gt;
hide-password&lt;br /&gt;
modem&lt;br /&gt;
debug&lt;br /&gt;
name l2tpd&lt;br /&gt;
proxyarp&lt;br /&gt;
lcp-echo-interval 30&lt;br /&gt;
lcp-echo-failure 4
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;添加一个vpn用户：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;vim /etc/ppp/chap-secrets&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;test        l2tpd       testpassword        *
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;启动l2tpd：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;sudo /etc/init.d/xl2tpd restart
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;设置iptables转发：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;iptables &amp;#8211;table nat &amp;#8211;append POSTROUTING &amp;#8211;jump MASQUERADE&lt;br /&gt;
echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;修改包转发设置&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;for each in /proc/sys/net/ipv4/conf/*&lt;br /&gt;
do&lt;br /&gt;
    echo 0 &amp;gt; $each/accept_redirects&lt;br /&gt;
    echo 0 &amp;gt; $each/send_redirects&lt;br /&gt;
done&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;vi /etc/sysctl.conf&lt;br /&gt;
修改 net.ipv4.ip_forward = 1&lt;br /&gt;
sysctl –p
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;好了，如果一切顺利，你的l2tp应该装好了，尝试用iphone或者android连接一下。如果还有问题，请继续。&lt;/p&gt;
&lt;p&gt;第一个问题是执行sudo /etc/init.d/xl2tpd restart时，无法看到执行状态，因此很多时候其实服务没有起来。你可以用ps aux | grep l2tp确认一下，如果发现的确没有这个进程，请使用&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;xl2tpd -D   &lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;开启debug模式启动。&lt;/p&gt;
&lt;p&gt;如果你碰见了一些很莫名其妙的配置文件错误提示，比如：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;parse_config: line 13: data &amp;#8216;n parameters:&amp;#8217; occurs with no context
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;而实际上你这一行并没有错误，请检查一下/etc/xl2tpd/xl2tpd.conf 里面是不是有一行很长的注释，把这些注释分成多行或者删除。&lt;/p&gt;
&lt;p&gt;第二个问题，如果你启动了xl2tpd，但是一连接iphone就提示“l2tp-vpn server did not respond”，或者android提示&amp;#8221;challenge failed&amp;#8221;，那请看看你的openswan 是不是 2.6.22或2.4.12：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;
dpkg -l | grep openswan
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;如果是，请重新编译安装：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;sudo aptitude install libgmp3-dev gawk flex bison&lt;br /&gt;
wget http://www.openswan.org/download/openswan-2.6.24.tar.gz&lt;br /&gt;
tar xf openswan-2.6.24.tar.gz&lt;br /&gt;
cd openswan-2.6.24&lt;br /&gt;
make programs&lt;br /&gt;
sudo make install
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;如果你还有其他问题，欢迎在下面留言，我会尝试帮你解决。&lt;/p&gt;
&lt;p&gt;参考文章：&lt;br /&gt;
&lt;a href=&quot;https://apple4.us/2010/05/setting-up-l2tp-vpn-on-debian-ubuntu.html&quot;&gt;https://apple4.us/2010/05/setting-up-l2tp-vpn-on-debian-ubuntu.html &lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://b.gkp.cc/posts/setup-ipsec-l2tp-on-centos-55.html&quot;&gt;http://b.gkp.cc/posts/setup-ipsec-l2tp-on-centos-55.html &lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://suoluo.org/2010/04/4/&quot;&gt;http://suoluo.org/2010/04/4/&lt;/a&gt; （上面三篇文章是全面介绍安装过程的）&lt;br /&gt;
&lt;a href=&quot;http://lists.openswan.org/pipermail/users/2006-November/011029.html&quot;&gt;http://lists.openswan.org/pipermail/users/2006-November/011029.html&lt;/a&gt; （介绍如何fix Checking for RSA private key）&lt;br /&gt;
&lt;a href=&quot;http://lifegoo.pluskid.org/?p=65&quot;&gt;http://lifegoo.pluskid.org/?p=65&lt;/a&gt; （指出xl2tpd.conf的注释问题）&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/381376217/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/how-i-install-l2tp-on-linode-ubunt/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376217/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376217/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://www.pmme.cn/archive/how-i-install-l2tp-on-linode-ubunt/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>前段时间开始，公司的vpn开始不太好用了，因此我也逐步感觉到墙的力量。
恰好@Zealot有一个linode的vps，之前他搭了一个pptp的vpn，但是联通3g又不能使用pptp vpn，于是尝试自己捣鼓一个l2tp的vpn，...&lt;img src=&quot;http://www1.feedsky.com/t1/381376217/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/how-i-install-l2tp-on-linode-ubunt/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376217/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376217/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>Experience</category><category>ubuntu</category><category>linux</category><category>Linux</category><category>l2tp</category><category>iphone</category><pubDate>Sun, 20 Jun 2010 21:17:43 +0800</pubDate><author>berg</author><comments>http://www.pmme.cn/archive/how-i-install-l2tp-on-linode-ubunt/#comments</comments><guid isPermaLink="false">http://www.pmme.cn/?p=1420</guid><dc:creator>berg</dc:creator><fs:srclink>http://www.pmme.cn/archive/how-i-install-l2tp-on-linode-ubunt/</fs:srclink><fs:srcfeed>http://www.pmme.cn/?feed=rss2</fs:srcfeed><fs:itemid>feedsky/berg/~1230757/381376217/1233376</fs:itemid></item><item><title>iphone上的网游：we rule</title><link>http://www.pmme.cn/archive/we-rule/</link><content:encoded>&lt;p&gt;最近一直在玩&lt;a href=&quot;http://werule.ngmoco.com/&quot; target=&quot;_blank&quot;&gt;we rule&lt;/a&gt;，一个iphone上的网络游戏，&lt;a href=&quot;http://itunes.apple.com/app/we-rule/id339274852?mt=8&quot; target=&quot;_blank&quot;&gt;app store&lt;/a&gt;中可以免费下载。&lt;/p&gt;
&lt;h4&gt;基本介绍&lt;/h4&gt;
&lt;p&gt;简单的说，这是一个让玩家建设和发展自己的王国，同时能和其他玩家进行互动的网游。&lt;/p&gt;
&lt;p&gt;一开始的时候，玩家只有一个城堡和一点金钱，游戏有一个简单的任务系统，引导玩家开始建造农田，通过生产农作物赚钱、发展，建设民居获取税收，建设矿山等来生产物品获得收益。&lt;/p&gt;
&lt;p&gt;王国是有等级的，可以通过建造店铺或者生产物品来获得经验值，然后升级。级别越高，王国能建造的东西越多，不但包括更多农作物，更多可以给王国带来收入的店铺，还包括各种装饰物，如树木、河流、雕像等等。&lt;/p&gt;
&lt;p&gt;玩家可以按照自己的设想，打造属于自己的王国，比如我围着城堡建了一圈护城河，护城河内部有一些民居，护城河左边是农田，右边是很多裁缝店。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.pmme.cn/upload/we_rule1.jpg&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;操作时间设定&lt;/h4&gt;
&lt;p&gt;不管是生产，还是建造，都是需要时间的。比如农作物，最短的是小麦，45秒就可以成熟，而也有成熟时间长达1天的豆子。因此玩家可以灵活按照自己的时间安排来种作物，因为不及时收获的农作物是会腐烂在农田里面的，这样就没有任何收入了。&lt;/p&gt;
&lt;p&gt;时间设定是这样的小型网游最基本的要素，这样玩家的一次游戏过程不会太长，不容易厌烦，同时有一个时间限定后，玩家心理上不由自主的会想着这件事情，到时间回来看看。&lt;/p&gt;
&lt;h4&gt;巧妙的玩家共赢&lt;/h4&gt;
&lt;p&gt;稍微升几级，玩家将可以建造矿山、裁缝店这样的设施，这些东西本身是可以赚钱的，但是速度很慢，让收益最大化的方法是和其他好友进行交易，这样双方都能得到更大的利益：&lt;/p&gt;
&lt;p&gt;某玩家的王国中有一个空闲的的店铺，他的follower就能在这里下订单，订单能给店铺的所有者一定的金币和经验，同时，下订单的玩家能得到店铺的产出物，他能用这些产出物“愉悦自己的子民”或者“建设城市”，也能得到一些经验值和金币。&lt;/p&gt;
&lt;p&gt;因此，互相交易是一个只赚不亏的事情！相比开心农场的“偷菜”而言，这一招要高明的多了，玩家不会因为自己的店被人占用而有半点损失，他们会很乐意地添加好友，在论坛和blog上宣传自己。因为好友越多，自己王国里面的店铺的空闲率越低，收益也就越大。&lt;/p&gt;
&lt;p&gt;看看一个订单完成的流程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A玩家来到B玩家王国中，下订单&lt;/li&gt;
&lt;li&gt;B玩家接受订单&lt;/li&gt;
&lt;li&gt;若干小时后，物品生产完毕&lt;/li&gt;
&lt;li&gt;B玩家将物品交给A玩家（如果订单完毕一段时间后，B玩家仍然没有进行此操作，这个订单将失效。）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;很明显的可以看到，订单的完成需要两个玩家操作三次，这样也就增加了游戏的黏性，玩家会不时的上来看看，家里是否有新的订单，是否有物品已经生产完毕。&lt;/p&gt;
&lt;p&gt;下面的图可以看到，我的裁缝店有一些订单已经生产完毕，还有一些新来的订单。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.pmme.cn/upload/we_rule2.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这时候，可能你想到了，我加很多很多好友，然后到他们家里去下订单，我就可以很快的升级了。但是其实we rule有个限制，如果一个玩家在外面下的订单过多，那他自己王国里的店铺将不能接受其他人的订单。让自己王国里的店铺空着显然不是什么好事，因此玩家在下订单的时候就会尽可能选择一些性价比高的店铺。&lt;/p&gt;
&lt;p&gt;我的ID是 cnberg，如果你也玩这个游戏，欢迎加我为好友哦。&lt;/p&gt;
&lt;h4&gt;一些问题&lt;/h4&gt;
&lt;p&gt;最大的问题是游戏速度太慢，不排除有网络连接的因素，但是如果能减少一些不必要的loading或者能压缩传输数据，游戏体验将更流畅。很多时候我需要等上好几分钟才能进入游戏，甚至就直接放弃了。游戏稳定性也存在一些问题，经常出现服务器无法连接或者数据混乱的bug。&lt;/p&gt;
&lt;p&gt;其次，游戏到25级以后就没有任何盼头了，因为那个时候将无法升级，没有更多建筑物可供建造。而事实上，我达到20级以后，就觉得游戏性大大降低了。&lt;/p&gt;
&lt;p&gt;此外，在游戏的设定上也有一些问题，比如说税收在游戏中的作用太小，一个民居只能每三小时提供4个金币。&lt;/p&gt;
&lt;h4&gt;总结&lt;/h4&gt;
&lt;p&gt;现在iphone上类似&lt;a href=&quot;http://www.playspymaster.com&quot; target=&quot;_blank&quot;&gt;spymaster&lt;/a&gt;和开心农场类的网络游戏激增。在移动设备上进行这类操作简单的游戏实在很方便，用户不需要一直打开游戏，因为服务器的消息能及时被用户收到（push服务或者后台进程），而且由于设备一直在身边，玩家也可以随时掏出设备玩几分钟，不像PC游戏需要开机、上网等一系列麻烦的操作，同时还能和手机特性结合达到PC上无法实现的效果，如重力感应操作，基于位置的玩法等等。&lt;/p&gt;
&lt;p&gt;摩根斯坦利最近发布的报告称&lt;a href=&quot;http://news.csdn.net/a/20100414/217924.html&quot; target=&quot;_blank&quot;&gt;2015手机互联网将超过桌面&lt;/a&gt;，手机上的游戏一定也会在最近飞速发展，颠覆传统的游戏方式。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/381376218/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/we-rule/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376218/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376218/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://www.pmme.cn/archive/we-rule/feed/</wfw:commentRss><slash:comments>1</slash:comments><description>最近一直在玩we rule，一个iphone上的网络游戏，app store中可以免费下载。
基本介绍
简单的说，这是一个让玩家建设和发展自己的王国，同时能和其他玩家进行互动的网游。
一开始的时候，玩家...&lt;img src=&quot;http://www1.feedsky.com/t1/381376218/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/we-rule/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376218/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376218/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>Experience</category><category>we rule</category><category>iphone</category><category>Web</category><pubDate>Fri, 16 Apr 2010 11:19:12 +0800</pubDate><author>berg</author><comments>http://www.pmme.cn/archive/we-rule/#comments</comments><guid isPermaLink="false">http://www.pmme.cn/?p=1418</guid><dc:creator>berg</dc:creator><fs:srclink>http://www.pmme.cn/archive/we-rule/</fs:srclink><fs:srcfeed>http://www.pmme.cn/?feed=rss2</fs:srcfeed><fs:itemid>feedsky/berg/~1230757/381376218/1233376</fs:itemid></item><item><title>opera下的onload、onunload事件无法正确处理？</title><link>http://www.pmme.cn/archive/why-opera-cannot-dispatch-onload-and-onunload/</link><content:encoded>&lt;p&gt;今天，QA在测试JS框架的时候发现了一个问题：opera下不能绑定onunload事件，最新的opera 10.51也不行。&lt;/p&gt;
&lt;p&gt;网上的解释千奇百怪，有说opera不支持unload事件的，有说使用beforeunload事件代替unload事件，还有的人说把通过js修改opera的history.navigationMode为&amp;#8217;compatible&amp;#8217;后就能正常支持这个事件了。&lt;/p&gt;
&lt;p&gt;而按照我的测试，不管是按照window.unload绑定还是用addEventListener绑定的事件都无法在刷新、前进、后退，页面关闭，浏览器关闭时被执行。beforeunload事件表现相同。正在我怀疑opera彻底不支持unload事件时，恰好找到了bytes.com上的这篇&lt;a href=&quot;http://bytes.com/topic/javascript/insights/799229-browser-quirk-onload-onunload-do-not-fire-back-forward-refresh-opera&quot; target=&quot;_blank&quot;&gt;文章&lt;/a&gt;。上面说的很清楚：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;There is no solution because according to Opera developers and users this is not a bug. Opera maintains the runstate of scripts, so it&amp;#8217;s as if we never left the page when we return back to it. According to Opera, onload should only fire when loading the page for the first time and onunload should fire when unloading the page completely, not when just leaving the page by pressing the back, forward or refresh button. Refresh is considered to be a reload, not an unload.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;大意是说，opera开发人员和用户不认为这是一个bug，因此没有解决方案。opera会维护脚本的运行状态，因此当用户回到某页面的时候，页面会和离开的状态相同。onload只会在第一次打开页面的时候触发，而onunload只会在这个页面完全被unload时触发。而在用户使用后退，前进，刷新按钮重新打开这个页面时不会被触发。刷新是reload，而不是unload。&lt;/p&gt;
&lt;p&gt;上面解释了unload为何不会被触发的原因。&lt;/p&gt;
&lt;p&gt;继续测试，发现点击页面上的链接时，onunload事件会被正常触发。在加载一个其他页面的时候，这个页面会被unload掉（可以明显的看到进度条在加载），而使用前进后退切换页面时，在瞬间就被加载完毕，页面这是从内存中取得的。&lt;/p&gt;
&lt;p&gt;最后，找到了opera官网上的&lt;a href=&quot;http://dev.opera.com/articles/view/efficient-javascript/?page=4&quot; target=&quot;_blank&quot;&gt;这篇文章&lt;/a&gt;，上面有一段解释了opera对Fast history navigation的处理方法，对理解opera出现这样的结果也有帮助。&lt;/p&gt;
&lt;p&gt;后来和&lt;a href=&quot;http://twitter.com/catchen&quot; target=&quot;_blank&quot;&gt;CatChen&lt;/a&gt;讨论时，他提到了firefox有onpageshow和onpagehide事件，在firefox中可以用这个来专门处理前进后退的事件。&lt;/p&gt;
&lt;p&gt;我找到了MDC上面关于&lt;a href=&quot;https://developer.mozilla.org/En/Using_Firefox_1.5_caching&quot; target=&quot;_blank&quot;&gt;firefox页面缓存的介绍&lt;/a&gt;，里面有关于onpageshow和onpagehide事件的解释，可惜这对事件不是DOM2标准定义的事件。在现代浏览器都逐渐开始做页面前进后退加速，保存表单和JS执行状态的时候，有这样一对事件对Web开发人员来说是很必要的。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/381376219/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/why-opera-cannot-dispatch-onload-and-onunload/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376219/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376219/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://www.pmme.cn/archive/why-opera-cannot-dispatch-onload-and-onunload/feed/</wfw:commentRss><slash:comments>1</slash:comments><description>今天，QA在测试JS框架的时候发现了一个问题：opera下不能绑定onunload事件，最新的opera 10.51也不行。
网上的解释千奇百怪，有说opera不支持unload事件的，有说使用beforeunload事件代替unload事件，还...&lt;img src=&quot;http://www1.feedsky.com/t1/381376219/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/why-opera-cannot-dispatch-onload-and-onunload/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376219/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376219/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>Experience</category><category>firefox</category><category>dom</category><category>events</category><category>Front-End Development</category><category>opera</category><category>javascript</category><pubDate>Tue, 13 Apr 2010 11:24:22 +0800</pubDate><author>berg</author><comments>http://www.pmme.cn/archive/why-opera-cannot-dispatch-onload-and-onunload/#comments</comments><guid isPermaLink="false">http://www.pmme.cn/?p=1414</guid><dc:creator>berg</dc:creator><fs:srclink>http://www.pmme.cn/archive/why-opera-cannot-dispatch-onload-and-onunload/</fs:srclink><fs:srcfeed>http://www.pmme.cn/?feed=rss2</fs:srcfeed><fs:itemid>feedsky/berg/~1230757/381376219/1233376</fs:itemid></item><item><title>博客迁移到nginx</title><link>http://www.pmme.cn/archive/my-blog-powerby-nginx-now/</link><content:encoded>&lt;p&gt;&lt;a href=&quot;http://nginx.org/&quot; target=&quot;_blank&quot;&gt;Nginx&lt;/a&gt;是一个高性能的HTTP服务器，也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的。nginx采用epoll模型来进行网络IO，效率比apache的select模型高出很多。&lt;/p&gt;
&lt;p&gt;一年前，服务器就使用Nginx做为最前端的webserver，主要是用来做静态文件的缓存，而php还是通过apache在运行。&lt;a href=&quot;http://www.pmme.cn/archive/use-awstats-to-analytics-nginxs-log/&quot; target=&quot;_blank&quot;&gt;有文为证&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;打算在近期逐步脱离apache，完全使用nginx，上周末参照张宴的&lt;a href=&quot;http://blog.s135.com/nginx_php_v6/&quot; target=&quot;_blank&quot;&gt;文章&lt;/a&gt;搭建好了环境。&lt;/p&gt;
&lt;p&gt;今天花了一点时间，把整个&lt;a href=&quot;http://hitidea.org/&quot;&gt;撞击思想博客&lt;/a&gt;的后端改成了Nginx+php-fpm，过程还算顺利。配置文件参考了wordpress mu论坛中的这篇&lt;a href=&quot;http://mu.wordpress.org/forums/topic/16161&quot; target=&quot;_blank&quot;&gt;帖子&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;By the way，最近一周使用&lt;a href=&quot;http://www.tornadoweb.org/&quot; target=&quot;_blank&quot;&gt;tornado&lt;/a&gt;+&lt;a href=&quot;http://www.mongodb.org/&quot; target=&quot;_blank&quot;&gt;mongodb&lt;/a&gt;开发了部门内部的一个小系统，感觉好极了，一路编码很顺畅，学习成本也很低。而由于NOSQL的存在，数据库也可以很方便的应对变化。&lt;/p&gt;
&lt;p&gt;嗯，我手里有多了几把锤子。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/381376220/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/my-blog-powerby-nginx-now/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376220/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376220/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://www.pmme.cn/archive/my-blog-powerby-nginx-now/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>Nginx是一个高性能的HTTP服务器，也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的。nginx采用epoll模型来进行网络IO，效率比apache的select模型高出...&lt;img src=&quot;http://www1.feedsky.com/t1/381376220/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/my-blog-powerby-nginx-now/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376220/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376220/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>Experience</category><category>博客</category><category>hitidea</category><category>nginx</category><category>撞击思想</category><category>Web</category><pubDate>Fri, 02 Apr 2010 00:10:56 +0800</pubDate><author>berg</author><comments>http://www.pmme.cn/archive/my-blog-powerby-nginx-now/#comments</comments><guid isPermaLink="false">http://www.pmme.cn/?p=1411</guid><dc:creator>berg</dc:creator><fs:srclink>http://www.pmme.cn/archive/my-blog-powerby-nginx-now/</fs:srclink><fs:srcfeed>http://www.pmme.cn/?feed=rss2</fs:srcfeed><fs:itemid>feedsky/berg/~1230757/381376220/1233376</fs:itemid></item><item><title>傲游、世界之窗下的getBoundingClientRect问题</title><link>http://www.pmme.cn/archive/getboundingclientrect-issue-in-maxthon-etc/</link><content:encoded>&lt;h2&gt;问题&lt;/h2&gt;
&lt;p&gt;今天，同事爆料suggeestion在傲游、世界之窗下，使用滚轮缩放后，suggestion的框和input不能对齐，会出现类似下面的效果（示意图）：&lt;br /&gt;
&lt;img src=&quot;http://hitidea.org/files/2010/03/suggestion_wrong.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;页面是quirk模式，如果换用standard模式，就不会有问题。&lt;/p&gt;
&lt;h2&gt;追踪&lt;/h2&gt;
&lt;p&gt;追查发现，发现计算input位置一个库函数得到的结果不准确。对比&lt;a href=&quot;http://developer.yahoo.com/yui/3/&quot;&gt;yui&lt;/a&gt;和&lt;a href=&quot;http://code.jquery.com/jquery-1.4.2.js&quot;&gt;jquery&lt;/a&gt;的代码后，发现处理逻辑完全一致：如果是IE系列，直接使用getBoundingClientRect得到元素的top和left，之后再看是否为qurik模式，决定是否要减去两个像素。&lt;/p&gt;
&lt;p&gt;问题就很明确了，是getBoundingClientRect()返回值与实际值不一致。此外，发现一个现象，如果放大屏幕，那结果偏小，缩小屏幕，结果偏大。于是尝试使用getBoundingClientRect()的返回值除以放大比率，果然这样就匹配了。&lt;/p&gt;
&lt;h2&gt;解决&lt;/h2&gt;
&lt;p&gt;首先，建议页面全部使用standard模式。&lt;/p&gt;
&lt;p&gt;由于不知道如何使用傲游或者世界之窗的方法来直接获得缩放比率，同时担心在不同的IE外壳下会有兼容性问题，于是写了下面这个函数，很trick，实在不行的时候可以考虑用用：&lt;/p&gt;
&lt;p&gt;&lt;code&gt; function getIEShellZoomRate (){&lt;br /&gt;
var div = document.createElement(&quot;DIV&quot;);&lt;br /&gt;
div.style.position = &quot;absolute&quot;;&lt;br /&gt;
div.style.top = &quot;100px&quot;;&lt;br /&gt;
document.body.appendChild(div);&lt;br /&gt;
var divBox = (div.getBoundingClientRect()).top;&lt;br /&gt;
if(!browser.isStrict){ //fix 2px in IE while in quirksmode&lt;br /&gt;
divBox -= 2;&lt;br /&gt;
}&lt;br /&gt;
document.body.removeChild(div);&lt;br /&gt;
return parseFloat(divBox/100);&lt;br /&gt;
}&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;其他&lt;/h2&gt;
&lt;p&gt;初步判断，原因应该是getBoundingClientRect()返回值是真实肉眼看到的像素值，而如果把这个像素值设置到元素的top和left属性后，实际值会随着缩放效果放大或缩小，造成两者不一致。&lt;/p&gt;
&lt;p&gt;此外，在傲游中，页面加载完毕后，需要闪烁一下才能到缩放后的效果，傲游可能是在获得IE的渲染结果以后，再自行放大，如果使用了standard模式，重新绘制的区域是没有缩放效果的。&lt;/p&gt;
&lt;p&gt;IE外壳的确方便了最终用户使用浏览器，但是也无形中让用户更依赖一个本来就很破旧的浏览器，不愿意升级到浏览器的更新版本。&lt;/p&gt;
&lt;p&gt;珍爱生命，远离IE；拒绝毒品，抵抗浏览器外壳。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/381376221/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/getboundingclientrect-issue-in-maxthon-etc/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376221/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376221/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://www.pmme.cn/archive/getboundingclientrect-issue-in-maxthon-etc/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>问题
今天，同事爆料suggeestion在傲游、世界之窗下，使用滚轮缩放后，suggestion的框和input不能对齐，会出现类似下面的效果（示意图）：

页面是quirk模式，如果换用standard模式，就不会有问题...&lt;img src=&quot;http://www1.feedsky.com/t1/381376221/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/getboundingclientrect-issue-in-maxthon-etc/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376221/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376221/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>Experience</category><category>dom</category><category>Front-End Development</category><category>maxthon</category><category>傲游</category><category>ie</category><pubDate>Fri, 12 Mar 2010 02:28:31 +0800</pubDate><author>berg</author><comments>http://www.pmme.cn/archive/getboundingclientrect-issue-in-maxthon-etc/#comments</comments><guid isPermaLink="false">http://www.pmme.cn/?p=1406</guid><dc:creator>berg</dc:creator><fs:srclink>http://www.pmme.cn/archive/getboundingclientrect-issue-in-maxthon-etc/</fs:srclink><fs:srcfeed>http://www.pmme.cn/?feed=rss2</fs:srcfeed><fs:itemid>feedsky/berg/~1230757/381376221/1233376</fs:itemid></item><item><title>添加第一个功能按钮 – 在线编辑器(3)</title><link>http://www.pmme.cn/archive/first-functio/</link><content:encoded>&lt;p&gt;在实现了在网页中插入一个可编辑区域以后，用户已经可以在这个区域中操作富文本内容。但是做为一个真正的编辑器是要有工具栏的，用户能通过工具栏上的按钮方便的对选中的文本进行操作。本文将介绍如何添加编辑器功能按钮。&lt;/p&gt;
&lt;h3&gt;加粗按钮&lt;/h3&gt;
&lt;p&gt;首先，我们在页面中添加工具条的HTML代码：&lt;/p&gt;
&lt;pre&gt;&amp;lt;div id=&quot;editor_toolbar&quot;&amp;gt;
    &amp;lt;input id=&quot;editor_toolbar_bold&quot; type=&quot;button&quot; value=&quot;B&quot;
style=&quot;font-weight:bold;&quot; onclick=&quot;editorInstance.bold()&quot; /&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;
&lt;p&gt;工具条中包含一个按钮，在按钮被按下时，调用editorInstance的bold()方法。期望的结果是：在编辑框内，选中的区域将被加粗。&lt;/p&gt;
&lt;h3&gt;加粗操作&lt;/h3&gt;
&lt;p&gt;接下来需要实现加粗功能，在此之前，需要对execCommand()有一定了解&lt;/p&gt;
&lt;h4&gt;execCommand&lt;/h4&gt;
&lt;p&gt;execCommand浏览器自带的一个接口，通过它，我们可以对document、selection、或者一个给定的range进行操作。如加粗、斜体等。&lt;/p&gt;
&lt;p&gt;语法：&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;javascript&quot; style=&quot;font-family:monospace;&quot;&gt;bSuccess &lt;span style=&quot;color: #339933;&quot;&gt;=&lt;/span&gt; object.&lt;span style=&quot;color: #660066;&quot;&gt;execCommand&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;sCommand &lt;span style=&quot;color: #009900;&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; bUserInterface&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#93;&lt;/span&gt; &lt;span style=&quot;color: #009900;&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; vValue&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
sCommand
    String，指定需要执行的命令，如Bold
&amp;nbsp;
bUserInterface
    Boolean，可选，决定是否显示用户界面，如弹出一个提示框让用户输入，默认为&lt;span style=&quot;color: #003366; font-weight: bold;&quot;&gt;false&lt;/span&gt;。
&amp;nbsp;
vValue
    Variant，可选，一个字符串、数字、或者其他需要assign的值&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;一般来说，第二个参数会传入false，因为编辑器本身会接管用户界面，第三个参数按照实际需要传入。这样就可以实现对选区的加粗：&lt;/p&gt;
&lt;div&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;javascript&quot; style=&quot;font-family:monospace;&quot;&gt;document.&lt;span style=&quot;color: #660066;&quot;&gt;execCommand&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;Bold&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #003366; font-weight: bold;&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; &lt;span style=&quot;color: #003366; font-weight: bold;&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;h4&gt;代码实现&lt;/h4&gt;
&lt;p&gt;只需调用浏览器的execCommand方法，选区就被加粗了。&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;javascript&quot; style=&quot;font-family:monospace;&quot;&gt;editor.&lt;span style=&quot;color: #660066;&quot;&gt;Editor&lt;/span&gt;.&lt;span style=&quot;color: #660066;&quot;&gt;prototype&lt;/span&gt;.&lt;span style=&quot;color: #660066;&quot;&gt;bold&lt;/span&gt; &lt;span style=&quot;color: #339933;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #003366; font-weight: bold;&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span style=&quot;color: #000066; font-weight: bold;&quot;&gt;this&lt;/span&gt;.&lt;span style=&quot;color: #660066;&quot;&gt;document&lt;/span&gt;.&lt;span style=&quot;color: #660066;&quot;&gt;execCommand&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;Bold&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #003366; font-weight: bold;&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #003366; font-weight: bold;&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;简单极了！但是总觉得少了什么？是的，没有状态反射。不论用户选中的是否一段加粗的文本，按钮只有一个状态，用户无法感知当前选中文本的状态。&lt;/p&gt;
&lt;h3&gt;状态反射&lt;/h3&gt;
&lt;p&gt;添加状态反射的思路是：在选区发生变化的时候，编辑器核心派发一个事件，在此事件发生时判断此时选区的状态，根据状态设置按钮样式。&lt;/p&gt;
&lt;p&gt;为何不由编辑器核心直接设置按钮样式呢？这是因为通过事件通讯能最大程度的降低模块和核心之间的耦合，也是模块可插拔的基础。&lt;/p&gt;
&lt;h4&gt;监听选区变化&lt;/h4&gt;
&lt;p&gt;造成选区发生变化的根源是鼠标点击或者键盘击键。因此，通过监听onkeydown和onmouseup事件就可以较粗略的得知选区变化。其实，此处将成为编辑器复杂后的第一个性能瓶颈，具体优化办法今后将具体描述。&lt;/p&gt;
&lt;h4&gt;事件机制&lt;/h4&gt;
&lt;p&gt;在本示例中，我实现了一个很简单的事件机制，外部模块通过 addEventListener 方法绑定方法到指定的事件，编辑器可以通过 dispatchEvent 方法派发指定的事件。具体代码见文末示例，不再赘述。&lt;/p&gt;
&lt;h4&gt;queryCommandState&lt;/h4&gt;
&lt;p&gt;在获得选区变化信息，并且能成功派发事件后，就需要使用浏览器提供的queryCommandState方法来获知选区状态了。&lt;/p&gt;
&lt;p&gt;语法：&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;javascript&quot; style=&quot;font-family:monospace;&quot;&gt;bDone &lt;span style=&quot;color: #339933;&quot;&gt;=&lt;/span&gt; object.&lt;span style=&quot;color: #660066;&quot;&gt;queryCommandState&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;sCmdID&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;其中的sCmdID是命令标识符，和execCommand接受的第一个参数是相同的。&lt;/p&gt;
&lt;p&gt;于是，只需使用：&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;javascript&quot; style=&quot;font-family:monospace;&quot;&gt;editor.&lt;span style=&quot;color: #660066;&quot;&gt;document&lt;/span&gt;.&lt;span style=&quot;color: #660066;&quot;&gt;queryCommandState&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;Bold&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;就可以获得当前选区是否处于加粗状态了。&lt;/p&gt;
&lt;p&gt;好了，加粗按钮到此就完成了，大家可以看看&lt;a href=&quot;/files/demo/editor/editor-2.html&quot; target=&quot;_blank&quot;&gt;示例&lt;/a&gt;，只在上次示例的基础上新增了60行代码。&lt;/p&gt;
&lt;h3&gt;浏览器差异&lt;/h3&gt;
&lt;p&gt;最后不得不提的是浏览器差异。&lt;/p&gt;
&lt;p&gt;execCommand和queryCommandState各个浏览器支持的程度相去甚远，ppk大神有一个execCommand浏览器支持程度的详细表格：&lt;a href=&quot;http://www.quirksmode.org/dom/execCommand.html&quot; target=&quot;_blank&quot;&gt;execCommand Compatibility&lt;/a&gt;。正是由于这些浏览器的差异，可能会造成一些在A浏览器下编辑好的内容，在B浏览器下无法修改，或者状态无法反射。&lt;/p&gt;
&lt;p&gt;因此，一些成熟的编辑器都会重写这些命令和查询方法，以达到浏览器之间表现一致的目的。做的最好的当属&lt;a href=&quot;http://ckeditor.com/&quot; target=&quot;_blank&quot;&gt;ckeditor&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;小结&lt;/h3&gt;
&lt;p&gt;本文完成了加粗按钮，一个按钮一般包括两个部分，设置选区状态，反射选区状态。可以使用浏览器的接口 execCommand 和 queryCommandState 来简单实现。&lt;/p&gt;
&lt;p&gt;通过前几篇文章，大家应该对编辑器的基本知识有了一定了解了，下一篇文章开始，我将和大家一起分析编辑器的需求，首先会从功能层面开始。本文是在线编辑器系列文章的第三篇，在这个系列文章中，我会逐步深入和大家分享编辑器开发过程中的奥妙和各种奇怪的问题。如果你对我的文章感兴趣，欢迎&lt;a href=&quot;http://feed.pmme.cn/&quot; target=&quot;_blank&quot;&gt;订阅&lt;/a&gt;我的博客及时收到更新。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/381376222/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/first-functio/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376222/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376222/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://www.pmme.cn/archive/first-functio/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>在实现了在网页中插入一个可编辑区域以后，用户已经可以在这个区域中操作富文本内容。但是做为一个真正的编辑器是要有工具栏的，用户能通过工具栏上的按钮方便的对选中的文本进行操...&lt;img src=&quot;http://www1.feedsky.com/t1/381376222/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/first-functio/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376222/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376222/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>Experience</category><category>Front-End Development</category><pubDate>Tue, 29 Dec 2009 21:49:53 +0800</pubDate><author>berg</author><comments>http://www.pmme.cn/archive/first-functio/#comments</comments><guid isPermaLink="false">http://www.pmme.cn/?p=1391</guid><dc:creator>berg</dc:creator><fs:srclink>http://www.pmme.cn/archive/first-functio/</fs:srclink><fs:srcfeed>http://www.pmme.cn/?feed=rss2</fs:srcfeed><fs:itemid>feedsky/berg/~1230757/381376222/1233376</fs:itemid></item><item><title>得到一个可编辑区域 – 在线编辑器(2)</title><link>http://www.pmme.cn/archive/get-a-editable-area/</link><content:encoded>&lt;p&gt;让一个区域可编辑是实现编辑器最基础的内容之一。&lt;/p&gt;
&lt;p&gt;在应用场景中，编辑器的初始状态，要么是从一个空的编辑器（新建文档），要么是从一个已经有内容的编辑器（编辑文档），因此设计这样一个接口：&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;javascript&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span style=&quot;color: #003366; font-weight: bold;&quot;&gt;var&lt;/span&gt; editorInstance &lt;span style=&quot;color: #339933;&quot;&gt;=&lt;/span&gt; editor.&lt;span style=&quot;color: #660066;&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;document.&lt;span style=&quot;color: #660066;&quot;&gt;getElementById&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;editor_source&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;;&lt;/span&gt;
document.&lt;span style=&quot;color: #660066;&quot;&gt;getElementById&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;editor_wrapper&amp;quot;&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;.&lt;span style=&quot;color: #660066;&quot;&gt;innerHTML&lt;/span&gt; &lt;span style=&quot;color: #339933;&quot;&gt;=&lt;/span&gt; editorInstance.&lt;span style=&quot;color: #660066;&quot;&gt;render&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;对应的HTML：&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;html&quot; style=&quot;font-family:monospace;&quot;&gt;&amp;lt;div id=&amp;quot;editor_source&amp;quot;&amp;gt;
    &amp;lt;h2&amp;gt;在线编辑器&amp;lt;/h2&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;editor_wrapper&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;调用者创建编辑器，然后将编辑器放在自己希望的位置上，这样的实现对调用者的限制最小，而create方法内部，可以通过实例化一个Editor类来实现多例。此时，页面的加载流程是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;调用render()方法返回编辑器的html代码&lt;/li&gt;
&lt;li&gt;将html代码插入指定位置&lt;/li&gt;
&lt;li&gt;让编辑器的iframe可编辑&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;render()&lt;/span&gt;方法很简单，返回一段拼接好的HTML字符串，供用户插入到任何需要的地方。唯一要做的是在返回之前调用&lt;span style=&quot;color: #0000ff&quot;&gt;checkIframeAvailable()&lt;/span&gt;方法.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;checkIframeAvailable()&lt;/span&gt;使用setTimeout轮询iframe是否被用户加入到dom中，一旦被加入，通过&lt;span style=&quot;color: #0000ff&quot;&gt;makeEditable()&lt;/span&gt;方法令其中的iframe进入编辑状态。&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #0000ff&quot;&gt;makeEditable()&lt;/span&gt;中，需要对IE和非IE进行分别处理，在IE通过&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;javascript&quot; style=&quot;font-family:monospace;&quot;&gt;document.&lt;span style=&quot;color: #660066;&quot;&gt;body&lt;/span&gt;.&lt;span style=&quot;color: #660066;&quot;&gt;contentEditable&lt;/span&gt; &lt;span style=&quot;color: #339933;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #003366; font-weight: bold;&quot;&gt;true&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;进入编辑状态，其他w3c标准兼容的浏览器则是&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;javascript&quot; style=&quot;font-family:monospace;&quot;&gt;document.&lt;span style=&quot;color: #660066;&quot;&gt;designMode&lt;/span&gt; &lt;span style=&quot;color: #339933;&quot;&gt;=&lt;/span&gt; &lt;span style=&quot;color: #3366CC;&quot;&gt;&amp;quot;on&amp;quot;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;进入编辑状态之后，还有一些其他的事情要做，为了在firefox和webkit浏览器下和IE通过execCommand()产生的代码尽量一样，需要设置styleWithCSS或者useCSS两个command的值为false。另外，在firefox 2下，在创建iframe后，无法立即读取editor.document.body，需要使用setTimeout在下一个时间片读取。&lt;/p&gt;
&lt;p&gt;这样，通过寥寥几十行代码，一个最基础的编辑器框就完成了，请看&lt;a href=&quot;http://www.pmme.cn/files/demo/editor/editor-1.html&quot; target=&quot;_blank&quot;&gt;最终示例&lt;/a&gt;。你可以从外面粘贴一些带有格式的文本进入编辑器看看效果。&lt;/p&gt;
&lt;p&gt;本文是在线编辑器系列文章的第二篇，在这个系列文章中，我会逐步深入和大家分享编辑器开发过程中的奥妙和各种奇怪的问题。下一篇文章将介绍如何给编辑器添加按钮操作，如果你对我的文章感兴趣，欢迎从页面右边&lt;a href=&quot;http://feed.pmme.cn/&quot; target=&quot;_blank&quot;&gt;订阅&lt;/a&gt;我的博客及时收到更新。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/381376223/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/get-a-editable-area/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376223/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376223/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://www.pmme.cn/archive/get-a-editable-area/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>让一个区域可编辑是实现编辑器最基础的内容之一。
在应用场景中，编辑器的初始状态，要么是从一个空的编辑器（新建文档），要么是从一个已经有内容的编辑器（编辑文档），因此设计这...&lt;img src=&quot;http://www1.feedsky.com/t1/381376223/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/get-a-editable-area/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376223/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376223/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>Uncategorized</category><pubDate>Fri, 25 Dec 2009 17:57:44 +0800</pubDate><author>berg</author><comments>http://www.pmme.cn/archive/get-a-editable-area/#comments</comments><guid isPermaLink="false">http://www.pmme.cn/?p=1387</guid><dc:creator>berg</dc:creator><fs:srclink>http://www.pmme.cn/archive/get-a-editable-area/</fs:srclink><fs:srcfeed>http://www.pmme.cn/?feed=rss2</fs:srcfeed><fs:itemid>feedsky/berg/~1230757/381376223/1233376</fs:itemid></item><item><title>历史、现状和目标 – 在线编辑器(1)</title><link>http://www.pmme.cn/archive/get-a-editable-area-editor-chapter/</link><content:encoded>&lt;h2&gt;关于本系列文章&lt;/h2&gt;
&lt;p&gt;计划暂时是这样，首先介绍一些历史、知识背景，然后详细分析现状和需求，开始设计一个可扩展，低耦合的编辑器，最后针对一些难点问题进行单个分析。&lt;/p&gt;
&lt;h2&gt;历史、现状&lt;/h2&gt;
&lt;p&gt;起初，世界上的浏览器本没有编辑器功能。到了IE4.0 (1997年)，微软提供了&lt;span style=&quot;color: #0000ff&quot;&gt;document.selection&lt;/span&gt;，利用这个对象，前端开发人员可以让一个iframe进入编辑状态，里面可以输入富文本内容，并且能通过程序添加复杂的编辑操作。那个时候还没有W3C的相关规范，这个selection对象以及两种选区类型（textRange和controlRange）都是微软自己实现的。&lt;/p&gt;
&lt;p&gt;三年后，有了W3C的相关规范(2000年)，&lt;strong&gt;这个规范和IE的实现完全不同&lt;/strong&gt;，firefox等一干浏览器陆续根据规范实现了自己的selection和Range对象。&lt;/p&gt;
&lt;p&gt;前端工程师的悲剧就这样酿成了，有两套截然不同的方式来处理选区(selection)，不仅仅如此，对execCommand()方法的支持也大相径庭，一个相同的命令在不同的浏览器下执行会出现不同的效果。最要命的，浏览器还经常会有一些诡异的问题，比如在某些时候对选区的不当操作会导致IE直接崩溃等。&lt;/p&gt;
&lt;p&gt;但是在线编辑器的使用场景相当广泛：写blog、论坛发帖、淘宝卖东西、在线聊天等应用场景都需要使用编辑器，他们对编辑器的要求各不相同。编辑器已经成为了一个基础件，几乎所有的互联网公司都需要用到。&lt;/p&gt;
&lt;p&gt;后来出现了一些开源编辑器，比较出名的有：&lt;a href=&quot;http://ckeditor.com/&quot; target=&quot;_blank&quot;&gt;ckeditor&lt;/a&gt;（原来叫fckeditor）， &lt;a href=&quot;http://tinymce.moxiecode.com/&quot; target=&quot;_blank&quot;&gt;tinymce&lt;/a&gt;，&lt;a href=&quot;http://www.ewebeditor.com/&quot; target=&quot;_blank&quot;&gt;eWebEditor&lt;/a&gt;等，最近，淘宝也开源了他们的&lt;a href=&quot;http://kissy.googlecode.com/svn/trunk/src/editor/demo/basic.html&quot; target=&quot;_blank&quot;&gt;kissy编辑器&lt;/a&gt;（功能尚不完善）。但是开源编辑器都各有不足，ckeditor足够强大，重写了浏览器的所有操作。但是模块之间的耦合性很高（3.0有所改善，但仍然不够），体积过于庞大，其他的一些编辑器则要么bug太多，功能不全，要么不方便二次开发。另外，一些对编辑器要求很高的服务，像&lt;a href=&quot;http://www.zoho.com/&quot; target=&quot;_blank&quot;&gt;zoho&lt;/a&gt;、&lt;a href=&quot;http://docs.google.com/&quot;&gt;Google docs&lt;/a&gt;等等，都带有一个很强大的编辑器。&lt;/p&gt;
&lt;h2&gt;目标&lt;/h2&gt;
&lt;p&gt;一个优秀的编辑器，首先要尽量解决浏览器之间的差异，在不同的浏览器下表现一致。&lt;/p&gt;
&lt;p&gt;另外，为了让编辑器在各种不同环境下适应不同的需求，尤其是二次开发的需求，这个编辑器还应该是“&lt;strong&gt;通用&lt;/strong&gt;”、“&lt;strong&gt;可扩展&lt;/strong&gt;”、“&lt;strong&gt;低耦合&lt;/strong&gt;”的。&lt;/p&gt;
&lt;p&gt;具体的设计思路在后面我会专门撰文说明，首先的这几篇文章，是让一些没有接触过编辑器开发的童鞋了解一些基础知识。&lt;/p&gt;
&lt;p&gt;本文是在线编辑器系列文章的第一篇，在这个系列文章中，我会逐步深入和大家分享编辑器开发过程中的奥妙和各种奇怪的问题。下一篇文章将介绍如何拥有一个可编辑区域，如果你对我的文章感兴趣，欢迎从页面右边&lt;a href=&quot;http://feed.pmme.cn/&quot; target=&quot;_blank&quot;&gt;订阅&lt;/a&gt;我的博客及时收到更新。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/381376224/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/get-a-editable-area-editor-chapter/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376224/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376224/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://www.pmme.cn/archive/get-a-editable-area-editor-chapter/feed/</wfw:commentRss><slash:comments>1</slash:comments><description>关于本系列文章
计划暂时是这样，首先介绍一些历史、知识背景，然后详细分析现状和需求，开始设计一个可扩展，低耦合的编辑器，最后针对一些难点问题进行单个分析。
历史、现状
起初...&lt;img src=&quot;http://www1.feedsky.com/t1/381376224/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/get-a-editable-area-editor-chapter/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376224/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376224/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>Experience</category><category>Front-End Development</category><category>编辑器</category><category>editor</category><category>javascript</category><pubDate>Wed, 23 Dec 2009 08:10:07 +0800</pubDate><author>berg</author><comments>http://www.pmme.cn/archive/get-a-editable-area-editor-chapter/#comments</comments><guid isPermaLink="false">http://www.pmme.cn/?p=1359</guid><dc:creator>berg</dc:creator><fs:srclink>http://www.pmme.cn/archive/get-a-editable-area-editor-chapter/</fs:srclink><fs:srcfeed>http://www.pmme.cn/?feed=rss2</fs:srcfeed><fs:itemid>feedsky/berg/~1230757/381376224/1233376</fs:itemid></item><item><title>善用分布式版本管理系统管理个人代码</title><link>http://www.pmme.cn/archive/manage-your-code-with-mercurial/</link><content:encoded>&lt;p&gt;大多数人都知道或者善用多种版本管理系统，传统集中式版本管理系统有CVS、&lt;a href=&quot;http://subversion.tigris.org/&quot; target=&quot;_blank&quot;&gt;SVN&lt;/a&gt;等，后来，出现了一些分布式管理系统，如&lt;a href=&quot;http://git-scm.com/&quot; target=&quot;_blank&quot;&gt;GIT&lt;/a&gt;、&lt;a href=&quot;http://mercurial.selenic.com/&quot; target=&quot;_blank&quot;&gt;mercurial&lt;/a&gt;等。几乎所有有开发工作的公司，都会选择一个版本管理系统，并且制定一些规范来管理代码，道理很简单，使用版本管理系统能在多人开发，跟进bug，追查问题方面减少很多管理和沟通的成本。&lt;/p&gt;
&lt;p&gt;但是，我觉得个人的代码，包括一些软件配置文件，完全可以使用分布式版本管理系统来管理，可以让我们减轻很多麻烦。&lt;/p&gt;
&lt;p&gt;使用传统的集中式版本控制软件来管理，好处如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;不用担心因为无意的错误修改，删除而丢失过去的代码&lt;/li&gt;
&lt;li&gt;可以随时查看历史情况，你就不用为“xx功能、yy修改到底是什么时候加进来的，为什么要加”这类事情而挠破头皮了&lt;/li&gt;
&lt;li&gt;可以进行分支开发，比如说一个功能你不是很确定能否实现，拉一个分支开发就是了&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;更进一步，使用分布式的版本控制还有如下好处：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在本地就有版本仓库，你可以在任何时候进行ci和roolback，无需联网&lt;/li&gt;
&lt;li&gt;超级快速的分支切换&lt;/li&gt;
&lt;li&gt;方便的和他人（其他机器）共享代码，一个push，或者pull，就能快速的同步修改&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;下面我举几个例子来让大家感受一下善用分布式版本管理的好处。&lt;/p&gt;
&lt;h3&gt;保证多台机器上的配置文件统一&lt;/h3&gt;
&lt;p&gt;我们有很多很多配置文件，尤其是linux下。vim配置，apache站点设置，桌面的配置，pidgin的账号设置等等。&lt;br /&gt;
但是如果有多台计算机，如果两台机器上配置不统一，用起来不顺手，更可能会带来麻烦，我们需要找到这些配置文件，并且拷贝一份最新的到当前机器，但是如果两边都有修改，就可能会丢失修改，或者需要手动merge。&lt;br /&gt;
过去可能用人使用过rsync来同步文件，能解决部分问题，但是如果使用分布式版本管理系统，在每台机器上都有一个独立的代码仓库，用这来管理配置文件再方便不过了！&lt;/p&gt;
&lt;p&gt;首先，我们现在一台拥有最新版本配置文件的机器上初始化一个版本库&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;linux&quot; style=&quot;font-family:monospace;&quot;&gt;cd ~/
hg init
hg add .vimrc .screenrc .fvwm #添加所有你关注的配置文件&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后，一旦有新机器需要使用这个配置，clone一份即可&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;linux&quot; style=&quot;font-family:monospace;&quot;&gt;cd ~/
hg clone ssh://berg@lastPC://home/berg/
hg up&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果在任何一台机器上有修改，只需要ci到当前机器，并且到其他机器上pull这份修改。&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;linux&quot; style=&quot;font-family:monospace;&quot;&gt;hg ci
ssh berg@anotherPC://home/berg/&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;我们不需要关心代码的合并，也不需要关心配置文件的具体名称和位置（在linux下面，所有的配置都是隐藏文件），一切细节都交给mercurial来管理。&lt;/p&gt;
&lt;h3&gt;使用中心服务器&lt;/h3&gt;
&lt;p&gt;分布式管理原则上是没有一个强制的中心服务器，但是如果我们在管理的规则中加上中心服务器，在某些时候就能避免一些尴尬的发生。&lt;/p&gt;
&lt;p&gt;举一个例子，假设我有三个开发环境，一台在公司，一台在家里，还有一台服务器。在公司时，我家里的机器是离线的，在家里则反过来。于是我白天在公司开发完毕后，想在家里获得最新的版本，最简单的办法就是在服务器上架设一个中心版本库，下班时，push代码到服务器上，回家就可以直接pull了。&lt;/p&gt;
&lt;p&gt;使用中心服务器可以避免在需要开发时，发现最新版本所在计算机不在身边，并且处于离线状态的尴尬。&lt;/p&gt;
&lt;h3&gt;灵活的分支开发&lt;/h3&gt;
&lt;p&gt;不要以为分支功能在小项目中就毫无用处，有的时候，善用分支可以减少很多麻烦。而集中的版本控制系统处理分支很麻烦，让人避退三舍，可是到了分布式版本控制这里，分支变得很简单，看看下面的例子。&lt;/p&gt;
&lt;p&gt;我在开发一个项目时，遇到了一个较大的修改，涉及面较广。&lt;br /&gt;
如果直接在主干上开发，如果在开发过程中发现了bug，或者其他临时插入的想法，我有两种选择：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;直接在线上修改，或者重新clone一份到本地的其他目录进行开发&lt;/li&gt;
&lt;li&gt;把“projectA”这个项目做为一个分支在本地开发&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;两种好处的优劣是很明显的，第一种，我要么需要冒线上修改的风险，要么需要在本地配置另外一套环境；而第二种，我只需要在碰到其他问题的时候，将分支切换回去就好了。下面是命令示例：&lt;/p&gt;
&lt;p&gt;首先，将本地仓库的当前branch设置成项目A的名称：projectA&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;linux&quot; style=&quot;font-family:monospace;&quot;&gt;hg branch projectA&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;我进行projectA分支的开发，如果在开发的过程中，我需要切换到原来的分支：&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;linux&quot; style=&quot;font-family:monospace;&quot;&gt;hg ci -m &amp;quot;projectA commit&amp;quot;
&amp;nbsp;
hg up default #切换到主干&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;开发完毕后提交并且push到线上：&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;linux&quot; style=&quot;font-family:monospace;&quot;&gt;hg ci -m &amp;quot;modified something&amp;quot;
&amp;nbsp;
hg push&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;接下来我又能迅速的切换回原来开发到原来开发到一半的uploadify分支&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;linux&quot; style=&quot;font-family:monospace;&quot;&gt;hg up projectA&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;分布式版本管理的好处一下就体现出来了，我可以在本地迅速的切换分支，分支建立的成本也很低。这样能让我们更灵活的应对需求&lt;/p&gt;
&lt;h3&gt;小结&lt;/h3&gt;
&lt;p&gt;好了，本文就写到这里。小结一下，使用分布式版本管理系统管理个人mini项目、软件配置文件，能给开发和管理带来很大的便利，使用中心版本仓库能避免机器离线导致无法获取最新代码的问题，善用分支能让开发者更灵活的应对需求。&lt;/p&gt;
&lt;p&gt;看了本文后，是否你对分布式管理系统也充满了兴趣呢？或者你有一些更好的实践？欢迎在下面留言共同探讨。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/381376225/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/manage-your-code-with-mercurial/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376225/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376225/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://www.pmme.cn/archive/manage-your-code-with-mercurial/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>大多数人都知道或者善用多种版本管理系统，传统集中式版本管理系统有CVS、SVN等，后来，出现了一些分布式管理系统，如GIT、mercurial等。几乎所有有开发工作的公司，都会选择一个版本管理...&lt;img src=&quot;http://www1.feedsky.com/t1/381376225/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/manage-your-code-with-mercurial/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376225/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376225/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>Experience</category><category>linux</category><category>Linux</category><category>mercurial</category><category>scm</category><category>分布式</category><pubDate>Sun, 13 Dec 2009 23:03:37 +0800</pubDate><author>berg</author><comments>http://www.pmme.cn/archive/manage-your-code-with-mercurial/#comments</comments><guid isPermaLink="false">http://www.pmme.cn/?p=1318</guid><dc:creator>berg</dc:creator><fs:srclink>http://www.pmme.cn/archive/manage-your-code-with-mercurial/</fs:srclink><fs:srcfeed>http://www.pmme.cn/?feed=rss2</fs:srcfeed><fs:itemid>feedsky/berg/~1230757/381376225/1233376</fs:itemid></item><item><title>在javascript编程中灵活使用try-catch</title><link>http://www.pmme.cn/archive/use-try-catch-in-javascript-programing/</link><content:encoded>&lt;p&gt;上周，在&lt;a href=&quot;http://www.sharej.com&quot; target=&quot;_blank&quot;&gt;分享家&lt;/a&gt;的qq交流群里，经常有人向我反馈不能下载东西。于是直接联系了一个用户，发现他的浏览器报出pageTracker对象不存在错误。&lt;/p&gt;
&lt;p&gt;问题很显然了，由于我在下载链接的onmousedown事件中添加了Event统计，如果用户的Google Analytics代码没有加载成功（显然是万恶的教育网造成的），那么就会报出这样错误。&lt;/p&gt;
&lt;p&gt;请看原来的代码片段：&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;javascript&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span style=&quot;color: #003366; font-weight: bold;&quot;&gt;function&lt;/span&gt; analytics&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;category&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; action&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; label&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; value&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#123;&lt;/span&gt;
&amp;nbsp;
    pageTracker._trackEvent&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;category&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; action&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; label&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; value&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;;&lt;/span&gt;
&amp;nbsp;
&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;修改一下，加上try-catch屏蔽这个错误：&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;javascript&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span style=&quot;color: #003366; font-weight: bold;&quot;&gt;function&lt;/span&gt; analytics&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;category&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; action&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; label&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; value&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#123;&lt;/span&gt;
&amp;nbsp;
    &lt;span style=&quot;color: #000066; font-weight: bold;&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#123;&lt;/span&gt;
&amp;nbsp;
        pageTracker._trackEvent&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;category&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; action&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; label&lt;span style=&quot;color: #339933;&quot;&gt;,&lt;/span&gt; value&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;;&lt;/span&gt;
&amp;nbsp;
    &lt;span style=&quot;color: #009900;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span style=&quot;color: #000066; font-weight: bold;&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;e&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;用try-catch来屏蔽浏览器错误是一个Javascript编程中很常用的一个技巧，灵活使用可以给开发者减少很多麻烦，下面再举一例。&lt;/p&gt;
&lt;p&gt;最近，我在开发一个通用的所见即所得编辑器。某些时候，程序需要记录住当前状态的节点，给后续程序处理。但麻烦来了，用户如果持续的在进行编辑动作，在程序后续处理时，节点可能已经不在DOM树中了。&lt;/p&gt;
&lt;p&gt;在IE下，如果你调用一个&lt;strong&gt;不存在的文本节点&lt;/strong&gt;(nodeType == 3)的任何属性或者方法，浏览器直接报错。根本找不到能判断这个节点是否存于DOM树中的方法。于是有了如下代码：&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;javascript&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span style=&quot;color: #000066; font-weight: bold;&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#123;&lt;/span&gt;
&amp;nbsp;
    &lt;span style=&quot;color: #000066; font-weight: bold;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;ele.&lt;span style=&quot;color: #660066;&quot;&gt;ownerDocument&lt;/span&gt; &lt;span style=&quot;color: #339933;&quot;&gt;!=&lt;/span&gt; editor.&lt;span style=&quot;color: #660066;&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span style=&quot;color: #000066; font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #003366; font-weight: bold;&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span style=&quot;color: #000066; font-weight: bold;&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#40;&lt;/span&gt;e&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span style=&quot;color: #000066; font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #003366; font-weight: bold;&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color: #339933;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #009900;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;上面的代码很好懂，首先判断这个节点是不是在编辑器中，如果不是，返回false；如果在过程中出现了错误，也返回false。&lt;/p&gt;
&lt;p&gt;关于try-catch的故事就说到这里，最后要提醒大家，try-cacth会影响javascript的性&lt;del datetime=&quot;2009-12-11T16:11:34+00:00&quot;&gt;功&lt;/del&gt;能，因此不应该在追求性能的环境中使用，尤其是一些基础方法或者会被多次调用的方法中。&lt;br /&gt;
下一篇文章，我将使用一个更好的办法来解决文首提到的Google Analytics报错的问题。欢迎你&lt;a href=&quot;http://feed.pmme.cn/&quot;&gt;订阅我的博客&lt;/a&gt;，在第一时间获得更新。&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/381376226/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/use-try-catch-in-javascript-programing/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376226/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376226/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content:encoded><wfw:commentRss>http://www.pmme.cn/archive/use-try-catch-in-javascript-programing/feed/</wfw:commentRss><slash:comments>0</slash:comments><description>上周，在分享家的qq交流群里，经常有人向我反馈不能下载东西。于是直接联系了一个用户，发现他的浏览器报出pageTracker对象不存在错误。
问题很显然了，由于我在下载链接的onmousedown事件中...&lt;img src=&quot;http://www1.feedsky.com/t1/381376226/berg/feedsky/s.gif?r=http://www.pmme.cn/archive/use-try-catch-in-javascript-programing/&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;&lt;p class=&quot;fswww1&quot;&gt;&lt;a href=&quot;http://www1.feedsky.com/r/l/feedsky/berg/381376226/art01.html&quot; target=&quot;_blank&quot;&gt;&lt;img border=&quot;0&quot; ismap=&quot;ismap&quot; src=&quot;http://www1.feedsky.com/r/i/feedsky/berg/381376226/art01.gif&quot; onerror=&quot;this.style.display='none'&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description><category>Experience</category><category>Front-End Development</category><category>Programing</category><category>javascript</category><pubDate>Sat, 05 Dec 2009 20:40:31 +0800</pubDate><author>berg</author><comments>http://www.pmme.cn/archive/use-try-catch-in-javascript-programing/#comments</comments><guid isPermaLink="false">http://www.pmme.cn/?p=1321</guid><dc:creator>berg</dc:creator><fs:srclink>http://www.pmme.cn/archive/use-try-catch-in-javascript-programing/</fs:srclink><fs:srcfeed>http://www.pmme.cn/?feed=rss2</fs:srcfeed><fs:itemid>feedsky/berg/~1230757/381376226/1233376</fs:itemid></item></channel></rss>