[高级程序设计]从高级程序设计中搬来的一些值得注意的地方

1、默认情况下只有表单字段可以获得焦点,但是如果对于其它的元素首先把tabindex设置为-1,然后调用focus方法也能获取焦点,只有opera不支持这个技术

      var elem=document.getElementById("elem");
         elem.tabIndex=-1;
	  elem.focus();
2、HTML5的autofocus属性

window.οnlοad=function(e)
	{
	    var elem=document.getElementById("autofocus");
         if(elem.autofocus)//支持HTML5属性的autofocus值为true
		 {
		   elem.focus();
		 }
  }
HTML部分

3、change事件具有特殊性,如果是input/textarea元素,在他们失去焦点同时value值改变的时候就会触发。但是select元素只要选项改变,即使没有失去焦点也会触发!
	
	
	
	  
	  
	 
14、关于select选项option的值

var select=document.forms[0].elements['location'];
	//推荐使用text/value获取文本和选项的值
	var text=select.options[0].text;
	var value=select.options[0].value;
   //不推荐下面的DOM方法
   var text=select.options[0].firstChild.nodeValue;
   var value=select.options[0].getAttribute('value');
注意:选择框的change事件和其它表单的change事件触发的条件不一样,其它控件change只有在值被修改而且焦点离开了当前字段时候触发,而select的change事件只有选中了选项就会触发;在未指定value特性的情况下,IE8会返回空字符串,而IF9+等其它会返回和text属性一样的值;选择框的type只能是select-one/select-multiple一种,取决于是否有multiple属性
如果是单选的select,我们可以用selectbox.selectIndex获取到选项,如下:

单选我们可以用selectedIndex获取到我们选择的option的所有的信息,如text/value值

 $('select')[0].οnchange=function(e)
  {
	var select=document.forms[0].elements['location'];
	//获取到了select对象了
	var option=select.options[select.selectedIndex];
	//通过selectIndex获取到选项
	console.log(option.text+"="+option.value);
	}
对于可以选择多项的选择框selectedIndex属性就好像只允许选择一项一样,设置selectedIndex的值会导致取消以前所有的选项并选择指定的哪一项,而读取时候只会返回选中项的第一项,所以多项选择我们采用这种方式:取得对某一项的引用,然后将selected属性设置为true!与selectedIndex不一样的是,在允许多项选择的对象中,设置selected属性不会取消对于其它选项的选择,因为可以动态选中多项,但是在单选中如果修改某一个选项的selected属性会取消对其它选项的选择,同时将selected设置为false对单选选择框没有效果!

下面获取所有的选中的options

function getSelectedOptions(select)
 {
   var result=new Array();
   var option=null;
   for(var i=0,len=select.options.length;i
总之:如果是多选select这时候会给每一个option默认一个selected为true,所以我们遍历所有的options集合然后选择selected为true的option就可以了!而对于单选的option我们通过获取selectedIndex就可以获取到了!
15、为select对象添加option对象和移除option对象
添加option第一种方式是DOM方法:

 var newOption=document.createElement("option");
   newOption.appendChild(document.createTextNode("1"));
   newOption.setAttribute("value","qinliang");
   $('select')[0].appendChild(newOption);
第二种方式是Option的构造方式,但是该方式不支持IE8-
var newOption=new Option("text","value");
   //第二个为vaue值,但是在IE8一下的浏览器有问题
   $('select')[0].appendChild(newOption);
第三种方式是通过add方法

  var newOption=new Option("text","value");
  //DOM规定这个方法有两个参数,要添加的新选项和位于新选项之后的选项
  //如果想在最后添加选项第二个参数是null,IE对add方法的实现第二个参数可选
  //如果指定该参数必须是新选项之后的索引,兼容DOM的浏览器必须指定第二个参数
  //因此如果要兼容浏览器就不能只传入一个参数!
  //如下面会在所有浏览器中把新选项添加到列表最后!
   $('select')[0].add(newOption,undefind);
如果想把新选项添加到其它位置那么就应该用标准DOM技术和insertBefore方法!
如果是移除选项:

方式1:调用select的removeChild方法就可以

方式2:调用select的remove方法传入下标就可以了

方式3:就是把相应的选项设置为null

var select=$('select')[0];
select.options[0]=null;//设置为空
当然我们如果要移除所有的options对象,那么我们可以不断移除第一个选项就可以了:

 function clearSelect(select)
 {
   for(var i=0,len=select.options.length;i
移动选项基于这样一个事实:如果把处于DOM中的元素通过appendChild添加到页面的其它部分,那么元素会从原来的位置上消失

 function reArrange(select)
 {
   var optionToMove=select.options[1];
   //把第二个移动到第1个前面!
   select.insertBefore(optionToMove,select.options[optionToMove.index-1]);
 }
 reArrange($('select')[0]);

16、如何判断select元素的option元素是否有值value!

if(option.selected)
{
  if(option.hasAttribute)
  {
    var optValue=(option.hasAttribute('value')?option.value:option.text);
	//找到选中项的时候需要确定什么值,如果不存在value特性,或者存在该特效
	//但是值为空字符串,都要用选项的文本代替,在DOM兼容的浏览器中用hasAttribute方法
	//在IE中需要用specified属性!
  }else
  {
    optValue=(option.attribute('value').specified?option.value:option.text);
  }
}
17、富文本操作的部分

主要是使用document.execCommand,这个方法可以对文档执行预定义的命令,可以为该函数传递三个参数,要执行的命令,表示浏览器是否需要为命令提供一个界面的布尔值和执行命令必须的值(如果不需要值要传递null)。为了确保浏览器兼容性,第二个参数应该始终是false,因为在FF中即使设置了true也会抛出错误!与剪切板有关的命令在不同浏览器中差异大,Opera没有实现任何剪切板命令,而FF默认禁止他们(必须修改用户的首选项来启用他们),SF/Chrome实现了cut/copy却没有实现paste,不过即使不能通过execCommand来执行命令,但是可以通过相应的快捷键达到同样的操作!

  frames['design'].document.execCommand('bold',false,null);
   //同样的方法也适用于页面contenteditable为true的区域,只要把对
   //框架的引用替换为当前页面的document对象集合
执行bold命令的时候,IE/Opera会使用strong包裹,SF/Chrome使用b标签,FF使用span标签。因此不能指望富文本编辑器会产生一致的HTML!

通过下列的方法可以判断当前文本是否合适执行相应的命令:

frames['design'].document.queryCommandEnabled('bold')
但是仅仅是确定是否合适,如FF在默认情况下会禁用剪切操作,但是仍然返回true!
下面方法确定是否已经把命令应用到了选择的文本:

 frames['design'].document.queryCommandState('bold')//可以利用这个方式更换粗体,斜体等按钮状态
下面的方法用于获取执行命令时候传入的值,即document.execCommand的第三个参数
frames['design'].document.queryCommandValue('fontsize');
   //其中fontsize是命令名称,这里是获取到值!

通过getSelection方法可以获取到富文本选取,然后对该选取进行操作:

我是你老公
点击按钮我们可以把元素的背景颜色变成红色

window.οnlοad=function()
{
  frames['design'].document.designMode='on';
}
 $('input')[0].οnclick=function(e)
 {
     var selection=frames['design'].getSelection();
     console.log(selection);
     //通过getSelection获取选择的文本,这个方法是window和document对象的属性!
	  var selectText=selection.toString();
	  //获得代表选区的范围!
	  var range=selection.getRangeAt(0);
	  //突出选择的文本,当选择了iframe中的文本,然后点击按钮的时候就会添加
	  //红色的背景!
	  var span=frames['design'].document.createElement('span');
	  span.style.backgroundColor='red';
	  range.surroundContents(span);
   }
HTML5将getSelection方法纳入了标准,但是FF3.6+中调用document.getSelection会返回一个字符串,为此在FF3.6+中改作调用window.getSelection可以返回selection对象,FF8修改了这个bug!同时IE8-浏览器不支持DOM,但是我们可以通过她支持的selection对象操作文本,IE中的selection对象是document的属性:

在IE中我们通过htmlText和pasteHTML实现了选择文本后背景色变成红色的情况:

$('input')[0].οnclick=function(e)
{
	var  range=frames['design'].document.selection.createRange();
	var selectText=range.text;//获取文本
	//但是如果要高亮显示文本可以用htmlText/pasteHTML
	range.pasteHTML(" " + range.htmlText+ "");
}

当我们需要把富文本内容提交给服务器的时候就需要特殊的处理,我想这也是xhEditor的原理把(xhrEditor也需要在submit中才能访问富文本内容)

 $('form')[0].οnsubmit=function(e)
 {
  var event=e?e:window.event;
  var target=event.target?event.target:event.srcElement;
  target.elements['comments'].value=frames['design'].document.body.innerHTML;
  //富文本不属于表单空间,不会自动提交给服务器,而需要我们手动提交html
  //为此我们添加一个隐藏的表单控件,让它的值等于从iframe中提取的值,从而
  //确保在提交表单之前填充comments字段,特别是当要调用submit方法来提交表单时候
  //一定不要忘记!
 }

18、Canvas绘图部分注意事项

浏览器不支持canvas
注意:如果把宽度和高度放置在style里面这时候画出来的就是长方形而不是正方形!

可以通过lineWidth设置描边线条,通过lineCap控制线条末端的形状是平头,圆头,还是方头(butt,round,square);通过lineJoin控制线条相交的方式是圆交,斜交,还是斜接(round,bevel,miter)!

 var drawing=document.getElementById('drawing');
	 if(drawing.getContext)
	 {
	   var context=drawing.getContext('2d');
	     context.strokeStyle="#ff0000";
	      //在strokeRect前设置
		context.lineWidth="1";
		//控制线条相交的方式时候是圆角相交!
		context.lineJoin="round";
		//控制线条末端的形状是圆角!
		context.lineCap="round";
	      context.strokeRect(10,10,50,50);
	 }
其中上面的lineCap,lineJoin在绘制线条的时候特别清晰

var drawing=document.getElementById('drawing');
	 if(drawing.getContext)
	 {
	   var context=drawing.getContext('2d');
	   //开始路径
	   context.beginPath();
	   context.lineWidth='0.05';
	   context.arc(100,100,99,0,2*Math.PI,false);
	   //必须移动到内圆上的某一点防止多余的线条出现!
	   context.moveTo(194,100);
	  context.arc(100,100,94,0,2*Math.PI,false);
	  var result=context.isPointInPath(195,100);
	 //该函数接受x,y参数作为参数,用于在路径被关闭之前
	 //确定画布上某一点是否在路径上!
	   context.stroke();
	   //描边
	 }
已知上面的画布是宽度和高度都是100,所以外圆的最大宽度是100,但是这时候如果lineWidth特别大,就会产生不明显的效果,所以用了lineWidth为0.05!
利用canvas也可以绘制文本

	 context.font='bold 14px Arial';
	 context.textAlign="center";
	 //建议使用start/end而不是left/right,还可能是center
	 context.textBaseline="middle";
	 //可能是top/hanging,middle,alphabetic,bottom等
	 var fontSize=100;
	 context.font=fontSize+"px Arial";
	 //measureText方法接受一个参数,也就是要绘制的文本,返回一个TextMetrics
	 //对象,返回的对象目前只有一个width属性,该方法利用font,textAlign,textBaseline
	 //的当前值计算指定文本的大小!
	 while(context.measureText('Hello World').width>140)
	 //140表示目标临界宽度
	 {
	   fontSize--;
	   context.font=fontSize+"px Arial";
	 }
	 context.fillText("12",100,20);
	 //fillText使用fillStyle绘制文本,strokeText使用strokeStyle为文字描边
	 //大多数情况下使用fillText
	   context.stroke();
	   //描边
	 }
fillText,strokeText可以接受第四个参数,也就是文本的最大像素宽度,提供这个参数后调用fillText/strokeText如果传入的字符串大于最大宽度,那么文本字符的高度正确,但是宽度会收缩以适应最大宽度!

可以用context的save和restore保存对绘图上下文的设置和变换

var context=drawing.getContext('2d');
	   context.fillStyle="#ff0000";
	   context.save();
	   //保存绘图上下文的设置和变换
	   context.fillStyle="#00ff00";
	   context.save();
	   //保存绘图上下文的设置
	   context.moveTo(0,0);
	   context.lineTo(100,100);
	   //这时候是黑色,因为默认是黑色填充
	   context.stroke();
	   context.restore();
	   //得到绿色
	   context.fillRect(0,0,50,50);
	   //得到红色
	   context.restore();
	   context.fillRect(100,100,50,50);
可以通过drawImage把图片绘制到画布上

      var context=drawing.getContext('2d');
	  var img=document.querySelector('img');
	  //把图像的部分的绘制到画布上,原图片是[0,10]到[50,50]的部分
	  //drawImage还可以传递一个canvas作为第一个参数,这样就可以把
	  //另一个画布绘制到当前画布上,但是绘制的图像必须来自于同一个域
	  //否则抛出错误!
	  context.drawImage(img,0,10,50,50,0,100,40,60);
注意:toDataURL是canvas的方法,不是context的方法
为上下文设置阴影属性

 var context=drawing.getContext('2d');
	   //设置形状或者路径x方向的偏移量
	   context.shadowOffsetX=5;
	   //形状或路径y方向的阴影偏移量默认是0
	   context.shadowOffsetY=5;
	   //模糊的像素,默认是0
	   context.shadowBlur=4;
	   //阴影颜色
	   context.shadowColor='rgba(0,0,0,0,5)';
	   //绘制红色的矩形
	   context.fillStyle="#ff0000";
	   context.fillRect(10,10,50,50);
	   //绘制蓝色矩形
	   context.fillStyle="rgba(0,0,255,1)";
	   context.fillRect(30,30,50,50);
这些属性都是通过context来修改
我们也可以通过createLinearGradient方法来创建渐变

var context=drawing.getContext('2d');
	  var gradient=context.createLinearGradient(30,30,70,70);
	  gradient.addColorStop(0,"white");
	  gradient.addColorStop(1,"black");
	  //addColorStop接受两个参数,色标位置和CSS颜色值
	  //其中色标位置从0到1
	  context.fillStyle=gradient;
	  //把渐变对象设置为fillStyle/strokeStyle的值
	  //从而让渐变绘制形状或者描边
	  context.fillRect(30,30,50,50);
通过createRadialGradient创建径向渐变

 var context=drawing.getContext('2d');
	 var gradient=context.createRadialGradient(55,55,10,55,55,30);
	 //前三个参数是起点的圆心和半径,后面三个参数也是一样的
	 //很显然这里是同心圆!
	 gradient.addColorStop(0,"white");
	 gradient.addColorStop(1,"black");
	 context.fillStyle="#ff0000";
	 context.fillRect(10,10,50,50);
	 //绘制渐变矩形
	 context.fillStyle=gradient;
	 context.fillRect(30,30,50,50);
可以通过createPattern来创建模式对象

var context=drawing.getContext('2d');
	   var img=$('img')[0];
	   var pattern=context.createPattern(img,"repeat");
	   context.fillStyle=pattern;
	   //把fillStyle设置为模式对象
	   context.fillRect(10,10,150,150);

该函数的第一个参数可以是video元素或者一个canvas元素!其中第二个参数与css的background-repeat属性相同,包括repeat,repeat-x,repeat-y,no-repeat!注意:模式和渐变一样都是从画布的原点(0,0)开始的!

通过getImageData和putImageData可以对图片原始数据进行处理

var drawing=document.getElementById('drawing');
	 if(drawing.getContext)
	 {
	  var context=drawing.getContext('2d');
	  var img=document.images[0];
	  context.drawImage(img,0,0);
	  //绘制原始图片
	  var imageData=context.getImageData(0,0,img.width,img.height);
	  //获取到图像原始数据,返回ImageData实例,该对象有width/height/data属性
	  var data=imageData.data;
	  //data属性是一个数组,保存着图像中每一个像素的数据
	  //每一个像素的数据用4个元素保存,分别是红绿蓝透明度
	  for(var i=0,len=data.length;i

把data数组回写到imageData对象上面后,调用putImageData方法把图片数据绘制到画布上,最终得到图像的黑白版!

19、代码调试部分

如果有finally那么try/catch中的return都会被忽略

          try
	 {
		window.name="qinliang";
	 }
	 catch (error)
	 {
	 //该error对象的message属性是唯一一个保证所有浏览器都支持的
	 //属性,还有一个name用于保存错误类型,除了Opera9之前的浏览器
	 //都支持
	 }finally
	 {
	   //只要包含了finally,那么try/catch中的return语句都会被忽略
	 }
如果需要知道错误的类型可以用instanceof,可以判断是什么类型的错误如,TypeError/ReferenceError/URIError/RangeError/SyntaxError/EvalError等
自定义错误类型必须继承Error,同时指定name,message属性

 //要自定义错误必须为新创建的错误类型指定name和message
	function CustomError(name,message)
	{
	  this.name=name;
	  this.message=message;
	}
	CustomError.prototype=new Error();
	//利用原型链继承通用错误类型
	throw new CustomError('my message',"自定义错误异常");
    //throw用于随时抛出自定义错误,抛出错误的时候要给throw指定一个值
	//这个值是什么类型没有要求,遇到throw时候代码立即停止执行,仅当
	//有try..catch捕获到抛出的错误时候才会继续执行
	console.log(1);
	//不会执行,除非上面try..catch掉
或者我们也直接可以抛出一个自定义错误类new Error('Arguments must be an array');
在Chrome/IE/FF中指定全局的onerror事件处理没有try.catch的错误

//任何没有try-catch处理的错误都会触发window对象的error事件,Opera/SF不支持
//任何浏览器中都不会创建event对象,但是可以接受三个参数:错误消息,错误所在的URL
//错误的行号,大多数我们只用message,而且必须通过DOM0绑定
  window.οnerrοr=function(message,url,line)
  {
    console.log(message);
	return false;
	//返回false可以阻止浏览器报告错误的默认行为,实际上是充当了整个文档的try..catch
	//可以捕获所有没有代码处理的运行时错误,这个事件处理程序是报告错误的最后已到防线,尽量
	//少使用。IE中即使发生error事件代码仍然正常执行,所有变量和数据都保存,因此可以在onerror中
	//访问,但是在FF中,常规代码停止执行,事件发生之前的所有变量和数据都被销毁,因此几乎就无法判断错误
	//类型
  }
图像也有一个error事件,该事件有一个event对象

var img=new Image();
  img.οnerrοr=function(e)
  {
    console.log(e);
	//图像的onerror会返回一个以图像为目标的event对象
  }
  img.src='1.jpg';
  //这样当加载图像失败就会显示警告框,需要注意的是
  //发生error事件时,图像的下载过程已经结束也就是说
  //不能再重新下载了!
我们可以模仿CSP中常见的report-uri来回报前端的错误日志

 function logError(sev,msg)
 {
   var image=new Image();
   image.src="log.jsp?sev="+encodeURIComponent(sec)+"&msg="+encodeURIComponent(msg);
   //通过image发生get请求到服务器
 }
//模块初始化如果出错就调用他,这在seajs中都是有这种形式的,在CSP中可以设置report-uri
//指定回报的url
for(var i=0,len=mods.length;i

如果要设置一个兼容浏览器的log函数,可以如下设定

 function log(message)
 {
  if(typeof console=='object')
  {
    console.log(message);
  }else if(typeof opera=='object')
  {
  //在Opera10.5之前,javascript通过opera.postError来访问javascript控制台
  //该方法可以往控制台写入任何信息
    opera.postError(message);
  }else if(typeof java=='object'&&typeof java.lang=='object')
  {
  //liveConnect也就是在javascript中运行java代码,FF/SF/Pera都支持
  //因此可以操作java控制台
    java.lang.System.out.println(message);
   }
 }
在FF/SF/Opera中可以调用java控制台开输入javascript消息!在不执行javascript控制台的IE7等浏览器中可以创建一个区域,然后在该区域里面写入log就可以了!
如果在大型项目中我们需要调试的时候就会用到assert函数,有点像jUnit测试,只是没有jUnit功能那么强大而已:

//大型引用程序都是用assert函数抛出错误
function assert(condition,message)
{
  if(!condition)
  {
   throw new Error(message);
  }
}
//用法如下
function divide(num1,num2)
{
  assert(typeof num1=='number' && typeof num2=="number",'both arguments must be number');
  //如果不是数字那么抛出错误
  return num1/num2;
}
console.log(divide(5,3));
在IE9之前所有的DOM对象都是以COM对象而不是元素的javascript实现的,所以可能会导致未找到成员错误

  //在IE中如果在对象被销毁之后又给该对象赋值就会导致未找到
   //成员的错误,而导致这个错误的原因就一定是COM对象!
   document.οnclick=function(e)
   {
     var event=e?e:window.event;
	 //在chrome等浏览器中没有这种现象
	 setTimeout(function()
	 {
	   event.returnValue=false;
	 },1000)
   }
在IE9以下的浏览器中,因为在点击事件以后event被销毁,所以再次给其赋值就会导致未找到成员错误,而其它浏览器中没有这种现象!

你可能感兴趣的:(javascript,前端开发)