标签归档:Javascript

文件上传 与 图片客户端预览

图片客户端预览:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="txt/html;charset=utf-8" />
<title>Javascript实现IE,firefox客户端图片预览</title>
<script>
//使用IE条件注释来判断是否IE6,通过判断userAgent不一定准确
if (document.all) document.write('<!--[if lte IE 6]><script type="text/javascript">window.ie6= true<\/script><![endif]-->');

function change(picId,fileId) {
	var pic = document.getElementById(picId);
  	var file = document.getElementById(fileId);
	
	//chrome,firefox7+,opera,IE10
  	if(window.FileReader) {
   		oFReader = new FileReader();
   		oFReader.readAsDataURL(file.files[0]);
   		oFReader.onload = function (oFREvent) {
			pic.src = oFREvent.target.result;
		};  
  	} else if (document.all) {
		//IE8-
   		file.select();
		//IE下获取实际的本地文件路径
   		var reallocalpath = document.selection.createRange().text;
		
		//IE6浏览器设置img的src为本地路径可以直接显示图片
   		if (window.ie6) {
			pic.src = reallocalpath; 
		} else { 
			//非IE6版本的IE由于安全问题直接设置img的src无法显示本地图片,但是可以通过滤镜来实现
    		pic.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='image',src=\"" + reallocalpath + "\")";
			//设置img的src为base64编码的透明图片,要不会显示红xx
    		pic.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
   		}
  	} else if (file.files) {
		//firefox6-
   		if (file.files.item(0)) {
    		url = file.files.item(0).getAsDataURL();
    		pic.src = url;
   		}
  	}
}
</script>
</head>
<body>
<form name="form1" enctype="multipart/form-data">
    <table>
        <tr>
            <td>选择图片:</td>
            <td >
            	<input type="file" name="file1" id="file1" onchange="change('pic1','file1')">
            </td>
            <tr>
            	<td>预览:</td>
            <td>
            	<img src="images/px.gif" id="pic1" >
            </td>
        </tr>
    </table>
</form>
</body>
</html>

Javascript实现图片客户端预览。这段实现代码对大部分浏览器应该都是可用的,特别是针对IE做的兼容,实在让人觉得IE无比的恶心。(实际测试IE9无法工作,实际IE9没有实现HTML5的File API)。HTML5引入的FileReader对象,目前大部分主流浏览器都支持,它可以读取文件或任意Blob的内容。

先搞清楚Blob:
Blob是对大数据块的不透明引用或者句柄(Binary Large Object)。Blob是不透明的,能对它们进行直接操作的就只有获取它们的大小(字节)、MIME类型以及将它们分割成更小的Blob。

在HTML5中,元素上的files属性是一个FileList对象。该对象是一个类数组对象,其元素要么是0,要么是用户选择的多个File对象。一个File对象就是一个Blob,除此,还多了name和lastModifiedDate属性:

<script>
function fileinfo(files){
	for(var i=0;i<files.length;i++){
		var f = files[i];
		console.log(f.name,f.size,f.type,f.lastModifiedDate);
	}
}
</script>

<input type="file" accept="image/*" multiple onchange="fileinfo(this.files) "/>

注意这里的files属性。它就是文件选择框选择的文件(可以多选)。文件类型的input元素多了一个multiple属性,弹出来的选择框可以选择多个文件,对应保存到files这个类数组中。(IE8及以下对这个multiple属性视乎都不支持,为了可以使用需要技巧,WordPress中使用的文件上传插件http://www.plupload.com/)。除了Multple属性,HTML5还带来了accept属性,比如值允许图片,值可以为image/*,或者用逗号分隔多个值。

File文件域继承自Blob,参考:
js_file_blob

那么如何读取这个Blob的内容呢,这个就是FileReader对象的作用了:

//方法
abort
readAsText(file,[encoding])
readAsBinaryString(file)
readAsDataURL(file)

//事件
onabort
onerror
onloadstart
onload
onloadend
onprogress(在应用进度条时有用)

//属性
result

注意三个方法可以取回Blob的内容,不过要注意的是无论读取成功或失败,方法并不会返回读取结果,这一结果存储在result属性中(异步进行,一般在事件onload中取result内容)。这里主要关注readAsDataURL(file)方法,这个方法就是读取返回的内容换成用户URL的数据,比如一张图片,就转换成如下格式:

data:image/jpeg;base64,xxxxx

基本是data:开头,紧接Mime类型,然后是base64,表示之后的数据是base64编码,对于图片,可以直接赋值给img标签的src属性,图片就可以显示出来。

上面讨论过读取内容会填充到result中,它是异步进行,那么在什么时机获取这个result呢,这个可以通过onload事件实现,通过绑定一个回调函数(onload触发时,result已经被填充)获取result内容。

fr.onload = function(){
	var fc = this.result;
}

//
fr.onload = function(e) {
	var fc = e.target.result;
}

文件一旦开始读取,无论成功或失败,实例的 result 属性都会被填充。如果读取失败,则 result 的值为 null ,否则即是读取的结果,绝大多数的程序都会在成功读取文件的时候,抓取这个值。(onload事件的回调函数函数中判断一下是否为null)

如果要使用Ajax批量上传文件,服务器接收一下,以下是一段范本:

<?php 
if(isset($_POST['name'])){
    file_put_contents("D:/".$_POST['name'],$_POST['data']);
    
    exit;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>客户端文件上传测试</title>
<style type="text/css">
body { font:12px Helvetica, arial, sans-serif }
</style>

<!-- JS  -->
<script type="text/javascript" src="jquery.js"></script>

<!--[if lte IE 8]>
<script type="text/javascript">
var fuckIe=true;
</script>
<![endif]-->

<script type="text/javascript">
$(function(){
	var result = {};
	
	$("#file1").change(function() {
		if(typeof fuckIe !== "undefined"){
			alert("玛尼,IE6 7 8不支持当前功能。珍惜生命,请远离IE。");
			return;
		}
	
		var file = document.getElementById("file1");
		
		var files = {};
		for(var i=0;i<file.files.length;i++){
			var name = file.files[i].name;
			// 一次文件选择框只能选择相同目录中的文件,应该不存在同名情况,不过这里还是进行了去重逻辑
    		if(typeof files[name] === 'undefined'){
        		files[name] = file.files[i];
    		}
        	
        	// 可用参数  这里的大小 和 类型可以用来限制用户选择的文件
    		//console.log(file.files[i]);
        	//console.log("文件名称 - "+file.files[i].name);
			//console.log("文件大小 - "+file.files[i].size);
			//console.log("文件类型 - "+file.files[i].type);
			//console.log("修改时间 - "+file.files[i].lastModifiedDate);
		}
		
		// 把文件内容记录到全局数据,可以多次跨目录多选,这里根据文件名去重,严格的可以对文件内容取签名去重
		for(var name in files){
			if(result[name]){ continue; }
			result[name] = new FileReader();
			result[name].readAsDataURL(files[name]);
		}
	});

	function formatResult(){
		if(typeof fuckIe !== "undefined"){
			alert("玛尼,IE6 7 8不支持当前功能。珍惜生命,请远离IE。");
			return false;
		}
		
		var fr = {};
		for(var r in result){
			if(typeof result[r].result == 'undefined'){
				fr = {};
				alert("请等待文件读取完毕...");
				return;
			}
			fr[r] = result[r];
		}

		return fr;
	}
	$("#upload").click(function(){
		var fr = formatResult();
		if(!fr){ return; }
		result = {};
		for(var r in fr){
			$.post("index.php",{"name":r,"data":fr[r].result},function(){
			});
			$("#file1").val('');
		}
	});

	$("#review").click(function(){
		var fr = formatResult();
		if(!fr){ return; }
		$("#imglist").html('');
		for(var r in fr){
			$("#imglist").append('<li><img width="200" src="'+fr[r].result+'" /></li>');
		}
	});
});
</script>

</head>
<body>
<table>
    <tr>
        <td>
            <input type="file" name="file1" id="file1" accept="images/*" value="请选择文件" multiple="multiple" />
        </td>
        <td>
            <input type="button" id="upload" value="上传" cantrigger='' />
        </td>
        <td>
            <input type="button" id="review" value="预览" cantrigger='' />
        </td>
    </tr>
</table>
<br />

<ul id="imglist">

</ul>
</body>
</html>

不得不说的是,在IE中,文件多选框难产(IE高版本可能支持input类型为file的表单的mutiple属性,未测试),FileReader对象大概也是IE9以上才有(Win7默认为IE8浏览器),所以,为了兼容IE,需要做很多工作,这个就是为何第三方的文件上传插件存在的价值,比如Wordpress中使用的plupload(http://www.plupload.com/),它使用Flash和Silverlight,对于无法弹出多选框的浏览器(主要是IE),通过Flash或Silverlight来实现,而上传文件大概也是对应的。

那么,也就是说,如果你不打算兼容IE 6 7 8,应该就可以不需要使用第三方的插件了。

<?php
if (isset ( $_POST ['name'] )) {
    list ( , $data ) = explode ( ',', $_POST ['data'] );
    file_put_contents ( "D:/" . $_POST ['name'], base64_decode ( $data ) );
    
    header ( 'Content-type: text/json' );
    echo json_encode ( [ 
        'success' => 1,
        'err' => '' 
    ] );
    exit ();
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>客户端文件上传测试</title>
<style type="text/css">
body {
	font: 12px Helvetica, arial, sans-serif
}
</style>

<!-- JS  -->
<script type="text/javascript" src="jquery.js"></script>

<!--[if lte IE 8]>
<script type="text/javascript">
var fuckIe=true;
</script>
<![endif]-->

<script type="text/javascript">
$(function(){
    var result = {};
     
    $("#file1").change(function() {
        if(typeof fuckIe !== "undefined"){
            alert("玛尼,IE6 7 8不支持当前功能。珍惜生命,请远离IE。");
            return;
        }
        var file = document.getElementById("file1");
        
      	for(var i=0;i<file.files.length;i++){
       		var name = file.files[i].name;
          	var reader = new FileReader();
          	reader.readAsDataURL(file.files[i]);

          	(function(name){
            	reader.onload = function(){
               		$("#imglist").append('<li><img alt="'+name+'" width="200" src="'+this.result+'" /></li>');
              	};
          	})(name);        
       	}
    });
    
    $("#upload").click(function(){
    	var ilst = $("#imglist img");
    	$("#file1").val('');
    	ilst.each(function(){
        	var $this = $(this);
        	var name = $this.attr('alt');
        	var data = $this.attr('src');

        	$.post('file_up.php',{"name":name,"data":data},function(d){
				if(d['success'] > 0) {
					$this.parents("li").remove();
				} else {
					alert(name+"上传失败");
				}
            },'json');
        });
    });
});
</script>

</head>
<body>
	<table>
		<tr>
			<td><input type="file" name="file1" id="file1" accept="images/*"
				value="请选择文件" multiple="multiple" /></td>
			<td><input type="button" id="upload" value="上传" cantrigger='' /></td>
		</tr>
	</table>
	<br />

	<ul id="imglist">

	</ul>
</body>
</html>

Javascript碎片笔记

JavaScript只有一个单一的数字类型。它内部被表示为64位的浮点数。值NaN是一个数值,它表示一个不能产生正常结果的运算结果。NaN不等于任何值,包括它自己。可以用函数isNaN(number)检测NaN。

值Infinity表示所有大于1.79xxxe+308的值。

转义字符允许把那些正常情况下不被允许的字符插入到字符串中,比如反斜线、引号和控制符。\u约定允许指定用数字表示的字符码位。

"A" === "\u0041"

字符串有一个length属性。

字符串是不可变的。一旦字符串被创建,就永远无法改变它。通过+运算符去链接其它的字符串会得到一个新字符串。

被当做假:
false
null
undefined
空字符串’ ‘
数字 0
数字 NaN

除此,所有值都被当做真,包括true 字符串”false”以及所有对象。

for (myvar in obj) {
	if (obj.hasOwnProperty(myvar)) {
		...
	}
}

通常须通过检查object.hasOwnProperty(var)来确定这个属性名就是该对象的成员,还是从其原型链里找到的。

return语句如果没有指定返回表达式,其返回值是undefined。JavaScript不允许在return(break)关键字和表达式之间换行。

JavaScript的简单类型包括数字、字符串、布尔值(true和false)、null值和undefined值。其它所有值都是对象。数字、字符串和布尔值类似对象,因为它们有方法,但它们是不可变的。

对象是属性的容器,其中每个属性都有名字和值。属性的名字可以是包括空字符串在内的任意字符串。属性值可以是除undefined值之外的任何值。(不能没有名字 和 不能没有值)

var sum = function(){
	var i, sum = 0;
	for(i = 0; i< arguments.length;i++){
		sum += arguments[i];
	}
}

arguments并不是一个真正的数组。arguments有一个length属性,但它缺少所有的数组方法。

一个函数总是返回一个值。如果没有指定返回值,则返回undefined。

Function.prototype.method = function(name,func){
	this.prototype[name]  = func;
	return this;
}
//改进
Function.prototype.method = function(name,func){
	if(!this.prototype[name]){
		this.prototype[name]  = func;
	}
	return this;
}

Number.method('integer',function(){
	return Math[this<0?'ceiling':'floor'](this);
});

String.method('trim',function(){
	return this.replace(/^\s+|\s+$/g,'');
}

作用域的好处是内部函数可以访问定义它们的外部函数的参数和变量(除了this和arguments)。

判断变量为数组:

var is_array = function (value) {
	return value &&
		typeof value === 'object' &&
		value.constructor === Array;
};

//以下是最可靠的方法
var is_array = function(value){
	return value &&
		typeof value === 'object' &&
		typeof value.length === 'number' &&
		typeof value.splice === 'function' &&
		!(value.propertyIsEnumerable('length'));
}

——————-
注意:现在大部分浏览器都应该支持Array.isArray()方法,为了兼容性,可用jQuery中提供的$.isArray()。

Javascript的undefined和null

Javascript中的数据类型有undefined,boolean,number,string,object。没错,undefined是一种数据类型。任何没有定义的变量 和 定义未赋值的变量都是undefined类型,而且它的值是undefined,表示值没有定义未知。

对于一个变量只要赋值了,只要不是赋值undefined,那么它就不是undefined;变量还可以赋值undefined,如果这样做,那么这个变量相当于没有定义过 或 定义了没有赋值,所以这个操作无意义。

对于null值,它的类型应该是null,但是JS中为了兼容性,typeof一个赋值了null的变量时,返回object。对于null,表示空值,可以把null赋值给变量,用来表示这个变量是空的,这个跟undefined的区别在于,undefined表示未声明或声明了未赋值,而null表示变量声明并且赋值了null值。

通常,可以预定义一个变量并赋值为null,表示变量已经预定义。我们也可以把null看做是对象类型的一个特殊值。只是一个特殊值而已,不同于undefined它还包含其它信息(变量未声明 声明未赋值)

另外,NaN是数字类型的特殊值,表示不是数字。

	var a0=null;
	var a1=123;
	var a2="123";
	var a3=[1,2,3];
	var a4=function(){};
	var a5=true;
	
	console.log(typeof a);				//undefined
	console.log(typeof a0);				//object
	console.log(typeof a1);				//number
	console.log(typeof a2);				//string
	console.log(typeof a3);				//object
	console.log(typeof a4);				//function
	console.log(typeof a5);				//boolean
	
	console.log(undefined == null);		//true
	console.log(undefined === null);	//false
	
	var a=undefined;					
	var b=null;
	console.log(a);						//undefined
	console.log(typeof a)				//undefined
	console.log(b);						//null
	console.log(typeof b);				//object

	console.log(undefined in window);	//true

Javascript 插件 alertify.js

地址:http://fabien-d.github.io/alertify.js/,它可以用来替代Javascript中生硬的弹框,比如alert()。不过alertify已经停止维护,但由于项目中使用这个东西,故而稍研究一下。

在使用上先引入CSS和JS:

<link rel="stylesheet" href="PATH_TO_FILE/alertify.css" />
<link rel="stylesheet" href="PATH_TO_FILE/alertify.default.css" />

<script src="PATH_TO_FILE/alertify.min.js"></script>

还可以引入jQuery,不过alertify不依赖jQuery(纯JS)。

先大概看看alertify.js:

(function (global, undefined) {
	"use strict";

	var document = global.document,
	    Alertify;

	Alertify = function () {
                // .....
		return {
			alert   : function (message, fn, cssClass) { _alertify.dialog(message, "alert", fn, "", cssClass); return this; },
			confirm : function (message, fn, cssClass) { _alertify.dialog(message, "confirm", fn, "", cssClass); return this; },
			extend  : _alertify.extend,
			init    : _alertify.init,
			log     : function (message, type, wait) { _alertify.log(message, type, wait); return this; },
			prompt  : function (message, fn, placeholder, cssClass) { _alertify.dialog(message, "prompt", fn, placeholder, cssClass); return this; },
			success : function (message, wait) { _alertify.log(message, "success", wait); return this; },
			error   : function (message, wait) { _alertify.log(message, "error", wait); return this; },
			set     : function (args) { _alertify.set(args); },
			labels  : _alertify.labels,
			debug   : _alertify.handleErrors
		};
	};
	// AMD and window support
	if (typeof define === "function") {
		define([], function () { return new Alertify(); });
	} else if (typeof global.alertify === "undefined") {
		global.alertify = new Alertify();
	}
}(this));

典型的自执行函数,把this传递给global,this就是当前的window对象,再获取document对象。内部定义了Alertify对象,这个对象内部定义了所有可以的方法,最后在window上附加一个叫alertify的属性,它指向了Alertify对象,注意看Alertify内部的return语句,这样全局就可以直接使用alertify.xxx()方法了。

注意看set方法,实际传递到_alertify.set(args),这个_alertify内部定义的变量有:

			/**
			 * Labels object
			 * @type {Object}
			 */
			labels : {
				ok     : "OK",
				cancel : "Cancel"
			},

			/**
			 * Delay number
			 * @type {Number}
			 */
			delay : 5000,

			/**
			 * Whether buttons are reversed (default is secondary/primary)
			 * @type {Boolean}
			 */
			buttonReverse : false,

			/**
			 * Which button should be focused by default
			 * @type {String}	"ok" (default), "cancel", or "none"
			 */
			buttonFocus : "ok",

			/**
			 * Set the transition event on load
			 * @type {[type]}
			 */
			transition : undefined,

这个就是可以定制的内容。所以我们第一步就是配置一下(也可以使用默认的,不需要配置)

alertify.set({
				labels : {
					ok     : "确定",
					cancel : "取消"
				},
				delay : 5000, //错误提示框消失时间
				buttonReverse : false,
				buttonFocus   : "ok"
			});

接下来就是具体API的使用了,压缩包中的例子:

	<script>
		function reset () {
			$("#toggleCSS").attr("href", "../themes/alertify.default.css");
			alertify.set({
				labels : {
					ok     : "OK",
					cancel : "Cancel"
				},
				delay : 5000,
				buttonReverse : false,
				buttonFocus   : "ok"
			});
		}

		// ==============================
		// Standard Dialogs
		$("#alert").on( 'click', function () {
			reset();
			alertify.alert("This is an alert dialog");
			return false;
		});

		$("#confirm").on( 'click', function () {
			reset();
			alertify.confirm("This is a confirm dialog", function (e) {
				if (e) {
					alertify.success("You've clicked OK");
				} else {
					alertify.error("You've clicked Cancel");
				}
			});
			return false;
		});

		$("#prompt").on( 'click', function () {
			reset();
			alertify.prompt("This is a prompt dialog", function (e, str) {
				if (e) {
					alertify.success("You've clicked OK and typed: " + str);
				} else {
					alertify.error("You've clicked Cancel");
				}
			}, "Default Value");
			return false;
		});

		// ==============================
		// Ajax
		$("#ajax").on("click", function () {
			reset();
			alertify.confirm("Confirm?", function (e) {
				if (e) {
					alertify.alert("Successful AJAX after OK");
				} else {
					alertify.alert("Successful AJAX after Cancel");
				}
			});
		});

		// ==============================
		// Standard Dialogs
		$("#notification").on( 'click', function () {
			reset();
			alertify.log("Standard log message");
			return false;
		});

		$("#success").on( 'click', function () {
			reset();
			alertify.success("Success log message");
			return false;
		});

		$("#error").on( 'click', function () {
			reset();
			alertify.error("Error log message");
			return false;
		});

		// ==============================
		// Custom Properties
		$("#delay").on( 'click', function () {
			reset();
			alertify.set({ delay: 10000 });
			alertify.log("Hiding in 10 seconds");
			return false;
		});

		$("#forever").on( 'click', function () {
			reset();
			alertify.log("Will stay until clicked", "", 0);
			return false;
		});

		$("#labels").on( 'click', function () {
			reset();
			alertify.set({ labels: { ok: "Accept", cancel: "Deny" } });
			alertify.confirm("Confirm dialog with custom button labels", function (e) {
				if (e) {
					alertify.success("You've clicked OK");
				} else {
					alertify.error("You've clicked Cancel");
				}
			});
			return false;
		});

		$("#focus").on( 'click', function () {
			reset();
			alertify.set({ buttonFocus: "cancel" });
			alertify.confirm("Confirm dialog with cancel button focused", function (e) {
				if (e) {
					alertify.success("You've clicked OK");
				} else {
					alertify.error("You've clicked Cancel");
				}
			});
			return false;
		});

		$("#order").on( 'click', function () {
			reset();
			alertify.set({ buttonReverse: true });
			alertify.confirm("Confirm dialog with reversed button order", function (e) {
				if (e) {
					alertify.success("You've clicked OK");
				} else {
					alertify.error("You've clicked Cancel");
				}
			});
			return false;
		});

		// ==============================
		// Custom Log
		$("#custom").on( 'click', function () {
			reset();
			alertify.custom = alertify.extend("custom");
			alertify.custom("I'm a custom log message");
			return false;
		});

		// ==============================
		// Custom Themes
		$("#bootstrap").on( 'click', function () {
			reset();
			$("#toggleCSS").attr("href", "../themes/alertify.bootstrap.css");
			alertify.prompt("Prompt dialog with bootstrap theme", function (e) {
				if (e) {
					alertify.success("You've clicked OK");
				} else {
					alertify.error("You've clicked Cancel");
				}
			}, "Default Value");
			return false;
		});
	</script>

一、alertify.alert(“字符串”)弹出提示框;alertify.confirm(“字符串”,function(e){})弹出确认框,通过回调函数传递的e判断是确认还是取消;alertify.prompt(“字符串”,function(e,str){})弹出一个输入确认框,通过回调函数的e判断是确认还是取消,str获得输入的字符串;

二、alertify.log(“字符串”,,持续时间);alertify.success(“字符串”);alertify.error(“字符串”);

最后,alertify.success(“字符串”)这类函数弹出的框无法自定义,大概需要自己去修改样式文件。

永久链接:http://blog.ifeeline.com/1659.html

Javascript在子窗口中操作父窗口DOM

父窗口:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type='text/javascript' src='jquery-1.10.1.js'></script>
<script>
jQuery("document").ready(function(){
	
	$("#open").click(function(){
		win=window.open("n.html","win","width=800,height=500,top=200,left=200,toolbar=no");	
	});
	
});
 
</script>
</head>
<body>
<button id="open">Open</button>
<div id="container">Hello World</div>
</body>
</html>

点击Open按钮将弹出一个窗口,链接到n.htmml,内容如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type='text/javascript' src='jquery-1.10.1.js'></script>

</head>
<body>
<script>
jQuery("document").ready(function(){
	$("#trigger").click(function(){
                alert(opener.$("#container").text()); 

		alert($("#container",$(opener.document)).text());	
		
		alert($(opener.document).find("#container").text());
	});
});

</script>
<button id="trigger">触发</button>
</body>
</html>

点击触发按钮,将会取出父窗口中id为container容器的内容显示。

在Javascript中,window代表窗口,它是一个容器,任何其它变量与函数都是从它开始,任何没有使用var前缀而使用的变量,默认是window的变量。window的opener指向打开它的父窗口,opener可能为空,因为它不一定是从一个存在的窗口中被打开的。

JQuery中的美元符号实际也是window对象的一个属性而已,所有opener.$这种语法就可以操作父窗口内容,这是最为便利的方式。

window.open快速参考:

window=object.open([URL ][, name ][, pramaters]]]])

URL:       新窗口的URL地址
name:      新窗口的名称,可以为空
pramaters: 属性控制字符串,在此控制窗口的各种属性,属性之间以逗号隔开

fullscreen={ yes/no/1/0 }是否全屏,默认no
channelmode={ yes/no/1/0 } 是否显示频道栏,默认no
toolbar={ yes/no/1/0 } 是否显示工具条,默认no
location={ yes/no/1/0 } 是否显示地址栏,默认no
directories = { yes/no/1/0 } 是否显示转向按钮,默认no
status={ yes/no/1/0 } 是否显示窗口状态条,默认no
menubar={ yes/no/1/0 } 是否显示菜单,默认no
scrollbars={ yes/no/1/0 } 是否显示滚动条,默认yes
resizable={ yes/no/1/0 } 是否窗口可调整大小,默认no
width=number窗口宽度(像素单位)
height=number 窗口高度(像素单位)
top=number窗口离屏幕顶部距离(像素单位)
left=number窗口离屏幕左边距离(像素单位)

这个东西仍然有应用价值的地方在于它可以跳出一个子窗口,然后在子窗口中选择一些东西然后会写到父窗口中,对于子窗口,假如数据有多页,那么使用纯JS方案,显然比较麻烦,在这里就可以翻页,然后把合适的数据回写到父窗口。

Javascript 数组操作

1、数组的创建

var arrayObj = new Array(); //创建一个数组
var arrayObj = new Array([size]); //创建一个数组并指定长度,注意不是上限,是长度
var arrayObj = new Array([element0[, element1[, ...[, elementN]]]]); //创建一个数组并赋值

2、数组的元素的访问

var testGetArrValue=arrayObj[1]; //获取数组的元素值
arrayObj[1]= "这是新值"; //给数组元素赋予新的值

3、数组元素的添加

arrayObj. push([item1 [item2 [. . . [itemN ]]]]);// 将一个或多个新元素添加到数组结尾,并返回数组新长度
arrayObj.unshift([item1 [item2 [. . . [itemN ]]]]);// 将一个或多个新元素添加到数组开始,数组中的元素自动后移,返回数组新长度
arrayObj.splice(insertPos,0,[item1[, item2[, . . . [,itemN]]]]);//将一个或多个新元素插入到数组的指定位置,插入位置的元素自动后移,返回""。

push是比较常用的函数了。

4、数组元素的删除

arrayObj.pop(); //移除最后一个元素并返回该元素值
arrayObj.shift(); //移除最前一个元素并返回该元素值,数组中元素自动前移
arrayObj.splice(deletePos,deleteCount); //删除从指定位置deletePos开始的指定数量deleteCount的元素,数组形式返回所移除的元素

注意splice函数,它是往数组中间插入和删除元素的有效方法。

5、数组的截取和合并

arrayObj.slice(start, [end]); //以数组的形式返回数组的一部分,注意不包括 end 对应的元素,如果省略 end 将复制 start 之后的所有元素
arrayObj.concat([item1[, item2[, . . . [,itemN]]]]); //将多个数组(也可以是字符串,或者是数组和字符串的混合)连接为一个数组,返回连接好的新的数组

6、数组的拷贝

arrayObj.slice(0); //返回数组的拷贝数组,注意是一个新的数组,不是指向
arrayObj.concat(); //返回数组的拷贝数组,注意是一个新的数组,不是指向

7、数组元素的排序

arrayObj.reverse(); //反转元素(最前的排到最后、最后的排到最前),返回数组地址
arrayObj.sort(); //对数组元素排序,返回数组地址

8、数组元素的字符串化

arrayObj.join(separator); //返回字符串,这个字符串将数组的每一个元素值连接在一起,中间用 separator 隔开。
toLocaleString 、toString 、valueOf:可以看作是join的特殊用法,不常用

数组对象的2个属性
1 length属性
指明数组的长度,可变,如果改小这个值,对应数据将丢失。如果改大,访问没有初始化的数据将得到undefined。length属性可能被隐式修改,比如数组长度是10,但是进行了arr[19]=60这个操作,这时length属性值为20,这个特征很奇特(比如Java中length属性是只读的)。

利用这个特征,如果要清空一个数组,可以把length赋值为0即可。另外,如果要清空一个数组,还可以进行arr = []操作,这样就空了。

2 constructor 属性
表示创建对象的函数。数组得到的就是Array。这个实际是构造函数的引用,不是字符串。

永久链接:http://blog.ifeeline.com/1030.html

Javascript JSON字符串生成工具

jQuery中可以把JSON字符串进行解析,但是没有提供把对象或数组变成JSON字符串的工具。有时需要把客户端的数据生成JSON字符串,然后传送到PHP,在PHP中用json_deconde()或json_encode()来处理这种数据,非常方便。

经过搜索,找到了一个工具,下载地址:https://github.com/douglascrockford/JSON-js

这个包里面的json2.js是json.js的替代版本。只需要把json2.js引入即可。

这个文件创建一个全局的叫JSON的对象,它有两个方法stringify 和 parse.( This file creates a global JSON object containing two methods: stringify and parse.),stringify就是把对象或变量变成JSON字符串的方法,parse是解析JSON字符串变成对象或数组的方法。从源代码可知,它还扩展了Javascript内置对象的方法:

    if (typeof Date.prototype.toJSON !== 'function') {

        Date.prototype.toJSON = function () {

            return isFinite(this.valueOf())
                ? this.getUTCFullYear()     + '-' +
                    f(this.getUTCMonth() + 1) + '-' +
                    f(this.getUTCDate())      + 'T' +
                    f(this.getUTCHours())     + ':' +
                    f(this.getUTCMinutes())   + ':' +
                    f(this.getUTCSeconds())   + 'Z'
                : null;
        };

        String.prototype.toJSON      =
            Number.prototype.toJSON  =
            Boolean.prototype.toJSON = function () {
                return this.valueOf();
            };
    }

Date 和 String Number Boolean都可以用toJSON来变成JSON字符串(实际上只有Date的toJSON比较有意义)。自定义对象或数组转换成JSON字符串参考:

var json = ['a','b','c'];
alert(JSON.stringify(json));

就能获取JSON字符串。更加详细的用法可以参考json2.js文件中的注释。

永久链接:http://blog.ifeeline.com/913.html

jQuery插件收藏 – Base64

在客户端进行Base64编码对于数据传送非常有利,比如在HTML中的表单的密码框的数据默认就是使用Base64编码传送的。不过想要自己实现把客户端的数据进行base64进行传送,就需要自己手动转换了。不过在jQuery里,有一款叫Base64的插件,实现了客户端的Base64的编码,下载地址:http://plugins.jquery.com/base64/

jQuery Base64

这个插件代码不多,实际也不复杂。用法参考下载包中的例子:

        var dec = $('#decode'),
            enc = $('#encode');

        // you can set utf8 encoding and decoding via global option
        // possible options:
        // `utf8encode` - utf8 encoding only (default: `false`)
        // `utf8decode` - utf8 decoding only (default: `false`)
        // `raw` - both (default: `true`)
        $.base64.utf8encode = true;

        enc.keyup(function () {
            dec.val($.base64.btoa(this.value));
            // also possible:
            // dec.val( $.base64('encode', this.value) );
            // dec.val( $.base64.encode(this.value) );
        });


        dec.keyup(function () {
            // note: you can pass a third parameter to use the utf8 en- / decode option
            enc.val($.base64.atob(this.value, true));
            // also possible:
            // dec.val( $.base64('decode', this.value) );
            // dec.val( $.base64.decode(this.value) );
        });

$.base64.utf8encode默认是false,可以设置它对utf8进行编码,JS使用的是utf8编码,所以可能需要修改。(对应的有$.base64.utf8decode)。

之后可以直接使用$.base64.btoa()进行编码,使用$.base64.atob()进行解码。这两个名字比较TMD不直观,实际上它们对应$.base64.encode()和$.base64.decode(),直接使用这两个函数即可。这两个函数的第二参数直接是否使用utf8编码,如果使用了全局设置,这个参数可以忽略。

最后,还有超级函数,就叫$.base64(),它有三个参数,第二第三参数跟上面的函数一样,第一个参数指定是编码还是解码(encode 或 decode)。

一般直接使用$.base64.encode()和$.base64.decode()就可以了(记得第二参数直接编码)。

永久链接:http://blog.ifeeline.com/910.html

Javascript压缩工具

压缩脚本的工具有很多,有JSMin,或是YUI Compressor,它们都可以用来压缩脚本文件(后者还可以处理CSS)。还可以用Google Closure Compiler。Google Closure Compiler有多种用法,例如网页版,网络API版,还有独立应用程序版。和YUI Compressor不同的是,YUI Compressor是一个压缩器(Compressor),而Google Closure Compiler更是一个编译器(Compiler),也就是说Google Closure Compiler的压缩并不仅仅是去除注释和空白,还可以在保证代码正确性的情况下进一步地改写成更省空间的做法,一个字节算一个字节,例如:

a = new Object    => a = {}
a = new Array     => a = []
if (a) b()        => a && b()
return 2 * 3;     => return 6;

Closure Compiler是一个JavaScript优化器,将Web应用编译成压缩的、高性能的JavaScript代码。编译器去除无效代码,并将剩余代码重写并压缩,使Web应用能够快速在浏览器的JavaScript引擎上执行。

Google Closure Compiler网页版本:http://closure-compiler.appspot.com/home (我这里需要翻墙)
Google Closure Compiler

jquery-1.10.1.js为压缩版本是268K,使用”Whitespace only”得到的结果是139K,使用”Simple”得到的是91.92KB,而使用”Advanced”得到的是83.1K,而jQuery官方提供的jquery-1.10.1.min.js版本是91K。使用Simple方式得到的代码容量和jQuery官网提供的压缩版本非常接近。

“Generally the best way to do it is to use the Google Closure Compiler (used by jQuery) or YUI compressor. jQuery provides a pre-minified version of jQuery for your convenience.

Packing JavaScript using Dean Edwards’ Packer (specifically using the base64 encode) is not recommended, as the client-side decoding has significant overhead that outweighs the file-size benefits.

压缩最好的工具是Google Closure Compiler (jQuery使用) 或者 YUI compressor,Dean Edwards’ Packer不推荐使用。

Dean Edwards’ Packer的在线工具:http://dean.edwards.name/packer/(JS实现):
packer

不过Dean Edwards’ Packer还提供了PHP等的实现版本,可以访问:Dean Edwards’ Packer – PHP版本
php-packer

Packer压缩虽然很小,但是传递到客户端后需要消耗客户端的计算资源来反压缩,相对消耗的资源来说,得到的容量下降比较不划算,如果结合使用gzip压缩,它的优势就完全没有了。不过为了制造一些让人完全看不懂的代码,packer在这方面用得就比较多了。经过packer压缩的代码传递到客户端后,需要自解压成原始代码,这个就是要把压缩的代码放入eval函数中的原因,而想用它来加密JS,基本是徒劳的,JS是解释执行的,再如何加密都必须是JS能解释的代码,你可以把代码进行变量替换等干扰操作,但这个无法阻止别人去分析窥探你代码的逻辑。

一般,经过packer压缩的代码,只要把eval函数里面的代码传递给document.write()函数就能得到未压缩前的代码,实际上eval中的代码是一个自执行函数:
JS自执行函数

这个自执行函数运行后就得到原始代码,这些原始代码放入eval中当做JS执行。当把这个自执行的函数放入document.write()中时,自执行函数依然会自动执行,执行后得到原始代码的字符串,自然把这个结果输出就是未压缩之前的代码了。

既然原理已经很清楚了,那么我们就把这些代码还原,要还原这些代码,异常简单:

jQuery(document).ready(function(){
	$("#unpack").click(function(){
		var text = $("#src").val();
		var res = /^eval\((.*)\)/.exec(text);
		$("#unpacked").val("");
		
		if(res == null){
			alert("不是通过Pack压缩的代码!");
		}else{
			eval("var vv ="+res[1]);
			$("#unpacked").val(vv);
		}
	});
	
	$("#clearpack").click(function(){
		$("#unpacked").val("");
	});
});

Javascript unPack 工具

把自执行函数提取出来,这个时候是字符串,然后拼接字符串(编写js代码,把自执行函数赋值给它),然后用eval函数执行这段代码,这样自执行的函数结果就取出来了。

Unpack工具:Javascript UnPack工具

原创文章,转载务必保留出处。
永久链接: http://blog.ifeeline.com/897.html

Javascript/JQuery产品多图切换与图片放大代码收藏

图片切换于放大

效果:多图切换与图片放大

以下是代码:

$(document).ready(function(){								
	var photo=document.getElementById('photo');
	var image1=new Image();  
	var image2=new Image();  
	image1.src=photo.getElementsByTagName('img')[0].src;   //原始尺寸
	image2.src=photo.getElementsByTagName('img')[1].src;   //缩小尺寸
	var scales=Math.round((image1.width/image2.width)*Math.pow(10,2))/Math.pow(10,2);  //四舍五入取整 保留两位小数,放大率
								
	$("#photo .prev").click(function() {
		var total_num = parseInt($('#photo_list .li').length);
		var num = parseInt($("#photo .prev").attr('num'));
		if(num == 0){
			if(total_num > 4){
				$("#photo_list .li:first").before($("#photo_list .li:last")); //把最后一个元素移动到最前面
				var currency_num = 0;
			}else{
				var currency_num = total_num - 1;
			}
		}else if(num > 0 && num < 4){
			var currency_num = num - 1;
		}else{
			var currency_num = 3;
		}

		$("#photo .prev").attr('num',currency_num);
		$("#photo_list .hover").removeClass("hover");
		var current = $('#photo_list').find(".li").eq(currency_num);
		$(current).addClass("hover");
		do_image_change(current);
	});
								
	$("#photo .next").click(function() {
		var total_num = parseInt($('#photo_list .li').length);
		var num = parseInt($("#photo .prev").attr('num'));
		if(num >= (total_num - 1) || (total_num > 4 && num ==3) ){
			if(total_num > 4 && num == 3){
				$("#photo_list .li:last").after($("#photo_list .li:first"));
				var currency_num = 3;
			}else{
				var currency_num = 0;
			}
		}else if(num >= 0 && num < 3){
			var currency_num = num + 1;
		}else{
			var currency_num = 0;
		}
		$("#photo .prev").attr('num',currency_num);
		$("#photo_list .hover").removeClass("hover");
		var current = $('#photo_list').find(".li").eq(currency_num);
		$(current).addClass("hover");
		do_image_change(current);
	});
								
	//放大镜
	if(image2.width==0 && image2.height==0){ //图片没有完成加载,等待加载完毕后再显示
		image2.onload=function(){
			$("#photo .browser").css("display","block");
			$("#map").css("display","block");
			magnifier.init({ 
				cont : document.getElementById('photo'), 
				img : document.getElementById('magnifier_img'), 
				mag : document.getElementById('map'), 
				scale : 2
			}); 
		}
	}else{
		$("#photo .browser").css("display","block");
		$("#map").css("display","block");
		magnifier.init({ 
			cont : document.getElementById('photo'), 
			img : document.getElementById('magnifier_img'), 
			mag : document.getElementById('map'), 
			scale : 2
		});
	}
								
	$("#photo_list .li").click(function() {
		var total_num = parseInt($('#photo_list .li').length);
		for(var i=0; i<total_num; i++){
			if($("#photo_list .li").eq(i).find("img").attr("imgb") == $(this).find("img").attr("imgb")){
				$("#photo .prev").attr('num',i);
				break;
			}
		}
		$("#photo_list .hover").removeClass("hover");
		$(this).addClass("hover");
		do_image_change(this);						 
	});
								
	function do_image_change(current){
		var photo=document.getElementById('photo');
		$('#magnifier_img').attr('src','');  //放大的图
		$('#photo .original_img').attr('src','');	//原始图
		$('#map').css('border','0');		//放大图的容器
									
		var src = $(current).find("img").attr("imgb");
		var bigimgSrc = $(current).find("img").attr("bigimg");	
		$('#photo .link_image').attr('src',bigimgSrc);		// 中尺寸  
		$('#photo .original_img').attr('src',src);			// 大尺寸 原始
									
		var image3=new Image();  
		image3.src=photo.getElementsByTagName('img')[0].src; 
		if(image3.width==0 && image3.height==0){
			image3.onload=function(){
				magnifier.init({ 
					cont : document.getElementById('photo'), 
					img : document.getElementById('magnifier_img'), 
					mag : document.getElementById('map'), 
					scale : 2
				}); 
			}
		}else{
			magnifier.init({ 
				cont : document.getElementById('photo'), 
				img : document.getElementById('magnifier_img'), 
				mag : document.getElementById('map'), 
				scale : 2
			});
		}
		$('#map').css('border','1px solid #000');
	}						
})	

永久链接:http://blog.ifeeline.com/860.html