监听输入框值变化的新方法

传统监听输入框的做法就是使用keyupkeydownkeypress,或者change事件来实现,但keyupkeydownkeypress事件是只要完成击键事件后就触发,不考虑输入框的值是否变化,也监听不了使用鼠标右键『剪贴』和『粘贴』这些操作。而change事件必须是焦点离开输入框后才触发,并不能实时监听。所以这两个事件来监听输入框值变化并不完美。

HTML5带来了一个新方法:input。它可以实时监听textarea、text、password和search的内容变化,而不用等到输入栏失去焦点就能触发,正是我们想要的。input的浏览器最低版本支持如下:

名称 Chrome Firefox (Gecko) Internet Explorer Opera Safari
版本 (Yes) 2 9 10 (Yes)

对于版本在9以下的IE浏览器可以使用IE传有的onpropertychange事件,onpropertychange事件可以监听元素的标准属性值变化,当然也包括value属性的变化。但是一个元素的属性变化时,也会触发这个事件,比如name属性变化,也会触发这个事件。这个结果不是我们想要的,但可以使用event.propertyName值来判断是否是元素的值发生变化。

IE9开始IE才支持使用addEventListener来绑定事件,所以可以用这个来判断到底是用input还是onpropertychange,代码如下:

/*
 * http://julabs.com
 */
if(document.addEventListener){
	// 支持input
	document.getElementById('myInput').addEventListener('input', function(){});
}else if(document.attachEvent){
	// 支持onpropertychange
	document.getElementById('myInput').attachEvent('onpropertychange', function(e){
	// 判断是不是元素的value值发生了变化
		if (e.propertyName.toLowerCase() == 'value'){

		}  
	});
}

演示代码如下:


input事件只有在用户输入的情况下才触发,如果用JS改变控件的值,是不会触发这个事件的,而onpropertychange则会触发,这个比较好。

需要注意的是,在IE9中,inputonpropertychange两个事件都有个小bug,那就是当使用鼠标右键执行『剪切』和『删除』时,这两个事件都不会触发,但IE其它版本都是正常可用的。

参考文章:

发表在 前端 | 标签为 , , | 一条评论

IE11不再支持attachEvent方法了

发现JS的一个错误,后来查找,原来是document.attachEvent这个语句发生了错误。就感到奇怪,因为用的是IE,觉得IE就应该支持attachEvent方法的。再查,我的IE已经被360更新到11版本了,而IE11却已经移除了对attachEvent方法的支持。

所以在使用attachEvent方法时,不能通过判断浏览器是否是IE来决定是否使用attachEvent方法了,而要使用功能判断。代码如下:

/*
 * http://julabs.com
 */
var addEvent = function(element, type, listener) {
	if(element.addEventLister){
		element.addEventLister(type,listener,false);
	}else if(element.attachEvent && listener.call){
		element.attachEvent('on'+type,function(){
			return listener.call(element,window.event);
		});
	}else{
		element['on'+type] = function() {
			return listener.call(element);
		}
	}
}

参考:

发表在 前端 | 标签为 , | 6 条评论

seajs模块的合并

seajs模块的合并比较简单,把几个的模块的代码放在同一个文件里面就可以了。如下:

/*
 * http://julabs.com
 */
define('pet',[],function(require, exports, module){
	return {
		'speak':function(){
			console.log('hello world');
		},
		'eat':function () {
			console.log('eat');
		}
	};
});

define('cat',['pet'],function(require, exports, module){
	var Pet = require('pet'),
	Cat = {};
	// 扩展 Cat 对象
	for(var i in Pet){
		if(Pet.hasOwnProperty(i)){
			Cat[i] = Pet[i];
		}
	}

	Cat.speak = function(){
		console.log('Miao');
	};

	return Cat;
});

define('dog',['pet'],function(require, exports, module){
	var Pet = require('pet'),
	Dog = {};
	// 扩展 Dog 对象
	for(var i in Pet){
		if(Pet.hasOwnProperty(i)){
			Dog[i] = Pet[i];
		}
	}

	Dog.speak = function(){
		console.log('Wang');
	};

	return Dog;
});

同一文件中的不同模块相互引用,直接require模块的ID名称就可以了。那么怎么在其它文件中引用合并文件中的模块呢?如果想调用cat模块,直接用下面的代码:

/*
 * http://julabs.com
 */
seajs.config({
	'base':'/demo',
	'alias':{
		'cat':'pet.js',
	}
});

seajs.use(['cat'],function(Cat){
	Cat.speak(); // 输出 "hello world"
	Cat.eat(); // 输出 "eat"
});

你会发现调用sepeak方法会输出”hello world“,而不是自己原以为的”Miao“。因为seaJs遇到这种问题,它会自动把放在第一个位置上的模块拿过来用,所以就出现了错误。如果想用合并文件里面的一个小模块,就要use两次才行。先use调用合并文件,然后再use下小模块,如下代码:

/*
 * http://julabs.com
 */
seajs.config({
	'base':'/demo',
	'alias':{
		'pet':'pet.js'
	}
});
seajs.use(['pet'],function(){
	// 调用一个模块
	seajs.use(['pet'],function (Pet) {
		Pet.eat(); // 输出 "eat"
	});

	// 调用两个模块
	seajs.use(['cat','dog'],function (Cat,Dog) {
		Cat.speak(); // 输出 "Miao"
		Cat.eat(); // 输出 "eat"
		Dog.speak(); // 输出 "Wang"
		Dog.eat(); // 输出 "eat"
	});
});

调用小模块的语句一定要包含在调用合并文件的语句里面才行。

相关与参考文章:

发表在 前端 | 标签为 , | 3 条评论

seajs模块化jQuery与jQuery插件

jQuery修改成SeaJs的模块代码非常简单,就是用下面这段语句将jQuery源代码包裹起来:

define('jquery',[],function(require, exports, module){
	//这里放jQuery源代码
	module.exports = jQuery;
});

也可以加一个判断,如果define已经被定义,就把jQuery模块化,如果define没有被定义,正常执行jQuery代码:

/*
 * http://julabs.com
 */
(function(factory) {
	if (typeof define === 'function') {
		define('/jquery', [], factory);
	}
	else {
		factory();
	}

})(function(require) {
	//这里放jQuery源代码
	if (require) return $.noConflict(true);

});

如果你用的是jQuery1.7版本以上的,那就更方便了。可以看下jQuery源码的最后几行,你会发现类似下方的代码:

if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
	define( "jquery", [], function () { return jQuery; } );
}

如果判断语句为真,那么jQuery就会自动模块化。所以改下判断语句,只留typeof define === "function"jQuery便可以自动模块化:

if ( typeof define === "function") {
	define( "jquery", [], function () { return jQuery; } );
}

模块化后的调用代码如下:

<script src="/script/sea.js"></script>
<script>
/*
 * http://julabs.com
 */
seajs.config({
	'base':'/script',
	'alias':{
		'jquery':'jquery.sea.js'
	}
});

seajs.use(['jquery'],function($){
	console.log($);
});
</script>

继续阅读

发表在 前端 | 标签为 , | 6 条评论

XP能连上路由但上不了网

用XP连无线路由器,已经发现了路由器并且显示已经正确连接上了路由器,但就是上不了网。在网上找了很多方法,一个一个试,还是不行。后来想到以前也曾经碰到这种事情,好像是加密方式的问题,于是修改了下加密方式,果然能够正常上网了。

  1. 右键『网上邻居』, 在弹出的快捷菜单中选择『属性』 ;
  2. 在打开的『网络连接』窗口中右键『无线网络连接』,在弹出的快捷菜单中还是选择『属性』;
  3. 在弹出的『无线网络连接 属性』对话框中点选『无线网络配置』选项卡;
  4. 在『首选网络』中选择要连接的网络名称,然后点击『属性』按钮;
  5. 这时候会弹出路由网络的属性,选择『关联』选项卡;
  6. 在『无线网络密钥』中,把『网络身份验证』设置为『WPA2-PSK』,把『数据加密』设置为『AES』。

无线网络密钥 数据加密

发表在 软件 | 留下评论

使用writing-mode实现中文竖排

在网页中实现中文竖排最方便的方法就是使用CSS的writing-mode属性,而最新的webkit已经支持这个属性了,但还是不能直接使用,需要在它前面加个-webkit-前缀。如下:

-webkit-writing-mode: vertical-rl;

在中国使用最多的两个浏览器引擎,一个是webkit,一个是IE的Trident,而IE本身就已经支持writing-mode属性,那么现在等于大多数的中文使用者都能够正确浏览到网页中竖排的中文。而使用CSSfloat属性,可以轻松实现古书中的排版样式,查看演示。如下图:

writing-mode

HTML代码如下:

<div>
  <h2>本纪第一 太祖一</h2>
  太祖开天行道肇纪立极大圣至神仁文义武俊德成功高皇帝,讳元璋,字国瑞,姓硃氏。先世家沛,徙句容 ,再徙泗州。父世珍,始徙濠州之钟离。生四子,太祖其季也。母陈氏,方娠,梦神授药一丸,置掌中有光,吞之,寤,口余香气。及产,红光满室。自是夜数有光起,邻里望见,惊以为火,辄奔救,至则无有。比长,姿貌雄杰,奇骨贯顶。志意廓然,人莫能测。
</div>

CSS代码如下:


body{
  padding:5px;
  background:#fff;
}
div{
  width:300px;
  height:275px;
  margin:0;
  padding:0;
  line-height:16px;
  font-size:14px;
  line-height:1.4em;
  -webkit-writing-mode: vertical-rl;
  writing-mode:tb-rl;
  letter-spacing:2px;
}
h2{
  float:left;
  margin:0;
  padding:0;
  font-size:28px;
  line-height:32px;
  margin-bottom:10px;
}

下面是JsFiddle的在线演示,如果不能正确显示请直接点这里查看在线演示

继续阅读

发表在 前端 | 标签为 , , | 12 条评论

xampp的Apache shutdown unexpectedly错误

在安装XAMPP绿色版时,按照文档运行程序,最后在用xampp-control.exe启动Apache时总是报错,如下:

Error: Apache shutdown unexpectedly.
This may be due to a blocked port, missing dependencies,
improper privileges, a crash, or a shutdown by another method.
Check the "/xampp/apache/logs/error.log" file
and the Windows Event Viewer for more clues

在网上找了很多方法都没有用,于是试着运行apache_start.bat程序,希望能够启动,但还是不能正常启动,不过却给出了错误提示,错误定位在452行。于是在xampp安装目录/apache/confhttpd.conf找到452行:

Include "conf/extra/httpd-xampp.conf"

这是设置虚拟目录的,暂时没有用,直接把这一行注释了,XAMPP就可以正常启动Apache了。

后来因为要用到conf/extra/httpd-xampp.conf,所以又要重新载入这个文件,最后发现之所以启动不了Apache是因为conf/extra/httpd-xampp.conf文件中的17、18两行:

LoadFile "/xampp/php/php5ts.dll"
LoadModule php5_module "/xampp/php/php5apache2_4.dll"

可能绿色版的XAMPP没有这两个模块,将这两行注释掉就可以了。

附:

发表在 软件 | 标签为 | 2 条评论

HTML5与IE条件注释判断语句

以前曾经写过一篇《IE条件注释判断语句》,这篇文章现在已经显地非常得落伍了。但是IE条件注释判断现在在前端开发中还是发挥着非常大的作用的,就连W3C HTML5 LOGO页面也用上了。不过W3C HTML5 LOGO使用的是最新的语句,如下:

<!--[if lt IE 7 ]> <html lang="en" class="ie6 ielt8"><![endif]-->
<!--[if IE 7 ]><html lang="en" class="ie7 ielt8"><![endif]-->
<!--[if IE 8 ]><html lang="en" class="ie8"><![endif]-->
<!--[if (gte IE 9)|!(IE)]><!--><html lang="en"><!--<![endif]-->

可是上面代码的最后一句,就是<!--[if (gte IE 9)|!(IE)]><!--><html lang="en"><!--<![endif]-->,现在看来也是有些错误的。这段代码从字面上的意思是说当前是IE9+或者是非IE的浏览器。但是微软已经宣布,IE10不再支持条件注释了,所以用(gte IE 9)这个语句只能在IE9得到使用,而IE10根本不认这段代码,和其它非IE浏览器一样,只把它当成普通的注释。但是这段代码只是想判断当前浏览器是否支持HTML5,所以从最终实现效果上来说这段代码还是达到了目的。现在我整理了一份代码,演示和注释如下:

<!--[if lte IE 6]>我是版本号大于5小于等于6的IE!<![endif]-->
<!--[if IE 7]>我是IE 7!<![endif]-->
<!--[if IE 8]>我是IE 8!<![endif]-->
<!--[if IE 9]>我是IE 9!<![endif]-->
<!--[if gte IE 10]>你看不到我!<![endif]-->
<!--[if !(IE)]><!-->我是IE10或非IE浏览器!<!--<![endif]-->
<!--[if !IE]><!-->我是IE10或非IE浏览器!<!--<![endif]-->
<!--[if (gte IE 9)|!(IE)]><!-->ie9以上版本 或者 其它非IE浏览器!<!--<![endif]-->

继续阅读

发表在 前端 | 标签为 , , | 2 条评论

《inline-block 前世今生》读后感

前两天读了TaoBaoUED《inline-block 前世今生》,我根本没有想到貌似非常简单的inline-block竟然有这么深的渊源。原来IE 从 5.5 开始就已经支持display:inline-block了,只是支持的并不是那么完善。

在IE6、IE7中,inline-block是对inline元素有效的,但对于block元素则需要做一些额外的处理来达到inline-block的效果。

display:inline-block; /* IE6、IE7的inline元素 现代浏览器 */
*display:inline; /* IE6、7 block 元素 */
*zoom:1; /* IE6、7 block 元素 */

《inline-block 前世今生》中描述inline-block的详细程度令我吃惊,想到最近也看过一个技术人员写的文章,说前端高手和一般人的区别在于是否会深入理解技术内幕

同事曾经教我操作机器,还向我说明为什么这样做。我说只要让我知道怎么做就行了,为什么这么做我不用知道。同事就批评我说这就是我一直没有进步的原因,不愿意去深入、不愿意去探索为什么这样做,是永远也不会进步的。

发表在 前端 | 标签为 | 2 条评论

用YUI Compressor压缩SeaJS单独模块文件

近来正在研究SeaJS,碰到了压缩问题。原因是YUI Compressor在压缩SeaJS模块文件时,会把模块文件里面的requireexportsmodule等参数给替换了,导致SeaJS无法辨认,如下面代码所示:

define(function(require,exports,module){
	var $ = require("jquery");
	console.log($);
});

上面这段代码经过YUI Compressor压缩后就会变成下面这样:

define(function(b,a,c){var d=b("jquery");console.log(d)});

可以看到requireexportsmodule三个参数名已经被替换了,如果不想被替换,可以用YUI Compressornomunge功能。在刚才的模块文件里面添加"require:nomunge,exports:nomunge,module:nomunge";,如下所示:

define(function(require,exports,module){
	"require:nomunge,exports:nomunge,module:nomunge";
	var $ = require("jquery");
	console.log($);
});

YUI Compressor压缩后的代码如下:

define(function(require,exports,module){var a=require("jquery");console.log(a)});

看,requireexportsmodule三个参数名并没有被替换了,而且增加的"require:nomunge,exports:nomunge,module:nomunge";也会被自动消除,这样在SeaJS里就可以正常使用了。不过有下面几点需要注意:

  • "require:nomunge,exports:nomunge,module:nomunge";这段文字必须要添加在函数体的开始位置;
  • 只有YUI Compressor才会消除"require:nomunge,exports:nomunge,module:nomunge";字样,其它压缩软件不能自动消除;
  • YUI Compressor不支持合并多个SeaJS模块文件的功能,如果想合并多个SeaJS模块文件,要用spm

附:

发表在 软件 | 标签为 , , | 一条评论