问题描述

在servlet中可能经常会出现中文乱码的情况,大致分为以下三种 * 表单处理(get/post) * 超链接() * sendRedirect()乱码(response.sendRedirect(“test.servlet?username=测试”))

原因解释及解决方案


表单处理

首先,浏览器默认一般都是UTF-8的方式编码的,而服务端默认以ISO-8859-1编码,也是以此方式来将字节流转化成字符串。 假如说页面中设置了<meta charset=utf-8>,那么发送请求时,url是以UTF-8发送字节流,而服务端使用request.getparameter直接得到的字符串,也就是用ISO-8859-1将字节流转化成字符串,因此出现乱码。 简而言之,一个字符串,以什么编码方式转化成字节流,就要用什么编码方式还原

  • post提交:

解决方法:在接收方的request.setCharacterEncoding(‘utf-8’);

  • get提交:

如果你使用以上的方法的话,结果还是乱码,原因在于,get方法中数据是在请求行中的,不是封装在请求体,而setCharacterEncoding针对的是请求体中的内容, 解决方法:

String request=new String(request.getParameter("key").getBytes("ISO-8859-1"),"UTF-8")

这样写看起来很麻烦,我们可以把他写成一个工具类,

public class MyTools{
	public static String getNewString(String str){
	String newstr=new String(str.getBytes("iso-8859-1"),"utf-8");
	return newstr;
	}
}

超链接

从超链接的格式上可以看到,他本质上使用的get方式提交,那我们可以使用get提交的解决方案来解决此问题


sendRedirect()

在使用sendRedirect发送数据之前,如果数据中有中文字段,需要先转化一下编码方式,用以下这种办法,也可以解决IE6中乱码的问题

String message = "测试";
message = URLEncoder.encode(message,"GBK");
response.sendRedirect(url+"?message ="+message);

问题模型

假设现在有一个页面,存了1000个button,点击button显示这是第几个button,怎么实现这个功能呢

以前我们通常是给一个元素绑定一个事件,但是监听器可能会导致内存泄露或者性能降低,并且监听器越多这种可能性越大,为此,我们有了另一种办法,将监听放在其父元素或者更高的元素上,减少监听器的数量。


背景知识

先来看看JavaScript中设置事件监听的几种办法:

  1. element.[‘on’+type]=function(){} //所有浏览器
  2. element.attachEvent(‘on’+type,listener); //IE6-10支持,IE11不支持
  3. element.addEventListener(type,listener,[usecapture]); //IE6-8不支持

区别:

  1. element['on' + type]不支持对一个元素的一个事件注册多个监听,并且不能使用事件捕获

  2. attachEvent是IE为了实现绑定多个监听而引入的,不过这也也还是不能使用事件捕获,而且IE11也已经抛弃这种方法了。

  3. addEventListener是W3C工作组在DOM Level 2开始引入的一个注册事件监听器的方法,存在3个事件阶段,捕获-目标-冒泡,传播路径如下图:

W3C_Event

  • 捕获阶段: 在事件对象到达目标元素之前,事件对象从window开始经过祖先节点传到目标节点
  • 目标阶段: 事件对象到达其目标节点,假如一个事件对象被标志为不能冒泡,则在目标阶段处理完之后不会进入冒泡阶段
  • 事件冒泡: 看名称应该能看出一些端倪,事件对象沿着目标节点往上传递,与捕获阶段相反,到达window结束

可以将usecapture设置为true(false)来控制监听生效的阶段,true表示在捕获阶段生效,false表示在冒泡阶段生效。如果要跳过冒泡阶段的话,可以将event.bubbles设置为false


问题解决

现在让我们来解决一下之前的那个问题,我们可以在document上设置一个监听,判断点击事件到底是在第几个button发生的,那么我们可以这么做

document.addEventListener('click',function(e) {
	if (e.target.nodeName.toUpperCase()==='BUTTON') {
		var buttonList=document.getElementsByTagName('button');
			for (var i = 0; i < buttonList.length; i++) {
				if (e.target===buttonList[i]) {
					console.log("button:"+(i+1));
				};
			};
	};
},false);

补充

除了代理监听还有什么办法呢,有吗?有的,我们还有闭包嘛,我们可以使用闭包那些i值缓存起来,咱们来简单实现一下:

var buttonList=document.getElementsByTagName('button');
	for (var i = 0; i < buttonList.length; i++) {
		(function(j) {
			buttonList[j].onclick=function() {
				console.log("button:"+(j+1));
			}
		})(i);
};

在线demo

demo例子


背景

今天碰到css的一个小问题,于是重温一下css选择器的优先级的问题

计算优先级

优先级是根据由每种选择器类型构成的级联字串计算而成的。他是一个对应匹配表达式的权重。 如果优先级相同,靠后的 CSS 会应用到元素上。

注意:元素在DOM树的位置不影响优先级

优先级顺序

优先级逐级增加的选择器列表:

  • 通用选择器(*)
  • 元素(类型)选择器
  • 类选择器
  • 属性选择器
  • 伪类
  • ID选择器
  • 内联样式

基于类型的优先级

优先级是根据选择器类型进行计算的,下面有个例子可以说明一下这个选择优先级,虽然属性选择器里使用的ID,但是优先级还是没有ID选择器高,因此应用到元素上的样式为第一种

* #foo {
  color: green;
}
*[id="foo"] {
  color: purple;
}

将其用到下面的HTML中

<p id="foo">I am a sample text.</p>

演示例子: <iframe width="100%" height="300" src="https://jsfiddle.net/donqi/vmo5m3re/embedded/result,css,html,js/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>

选择器优先级一致

优先级相同的情况下,后面定义的会覆盖前面定义的样式,classList里的顺序并不影响结果 举例:

<div class="box padding border"></div>
<div class="box border padding"></div>
<div class="padding box border"></div>

CSS:

div{
    height:100px;
    width:100px;
    padding:20px;
    margin:20px;
    border:10px solid hsla(0,0%,0%,0.5);
    background-color:#ccc;
    background-image:url("/favicon.png");
    background-repeat:space;
    background-origin:content-box;
}
div.box{
    
    background-clip:content-box;
}
div.border{
    background-clip:border-box;
}
div.padding{
    background-clip:padding-box;
}

演示例子:

最后说两句

这里说的是css选择器的优先级,对于到底表现哪种样式,还有一点特别重要,css解析器是从右到左的顺序解析的。比如上面的例子中,会先寻找id为”foo”的元素

* #foo {
  color: green;
}

为什么要这么做呢,下回再说

可以先看看详细说明:http://stackoverflow.com/questions/5797014/why-do-browsers-match-css-selectors-from-right-to-left/5813672#5813672


Webkit作为一个开源的浏览器引擎,而且apple和google都大力推广,其重要性不言而喻 chrome和Safari浏览器中添加了一些小功能

1.input标签/textarea标签聚焦高亮 屏蔽方法:

input, textarea{outline: none;}

2.textarea标签缩放 去掉缩放:

/**css2.0*/
textarea {width: 400px; max-width: 400px; height: 400px; max-height: 400px; }
/**css3.0*/
textarea{resize: none;}

注意:如果考虑兼容webkit核心的浏览器,要注意输入框(文本框)要尽量保持原来的样式。 当你隐藏了点击前的样式,又忘记去掉聚焦之后的默认样式,webkit引擎浏览器就会出现问题。


问题描述

第一部分: 用CSS控制3个<div>标签实现下面这个布局

buju

第二部分:用javascript优化布局

由于我们的用户群喜欢放大看页面,于是我们给上一题的布局做一次优化。当鼠标略过某个区块的时候,该区块会放大25%,并且其他的区块仍然固定不动。

jsxiaoguo


实现思路

第一部分,可以用float,也可以absoulte,看大家喜欢了,这里我使用的是absolute定位,将右边的主要内容放在前面,这样能够先加载主要内容,代码如下

div{
		background-color:grey;
		position:absolute;
	}
	#main{
		margin-left: 210px;
		height: 500px;
		width: 300px;

	}
	#left1{
		width: 200px;
		height: 245px;
	}
	#left2{
		width:200px;
		height:245px;
		top:255px;
		margin-top:10px;
	}

第二部分:

鼠标滑过时,将zIndex设为100,不影响其他元素布局,离开时恢复 使用事件代理,直接通过document监听鼠标 鼠标滑过时,宽高变为120%,将margin-top和margin-left减小20px; 如果图片大小都差不多大话,可以将边距减少10%,效果还比较好 在这里要注意以下几点:

  • IE8及以下添加监听使用的是attchEvent,并且响应函数里this的值是window对象而不是触发事件的元素
  • 获取元素之前的宽高时,用先获取到元素的宽高,这里就可以用我们之前讨论过的方法,IE用element.currentStyle,其他用window.getComputedStyle(element,[, pseudoElt]),不清楚的看这里->获取样式表
  • 利用parseInt转化类型时,如果在字符串开始处无法获得任何数字,会返回NaN,IE中用currentStyle获取样式表的话,如果margin未定义的话,值是auto
  • 想要获取元素的最终样式,如果你这么写:
var style=window.getComputedStyle(e)||e.currentStyle;

IE8及以前就会报错,说不支持getComputedStyle属性或方法,IE中,如果碰到未定义的变量就会开始报错,不管是不是在if判断句还是或运算符前,不知道这不是一个bug啊,按理说第一句为假的时候应该要判断后面一句的啊,现在我们只能调换顺序了

js代码如下:

/**attachEvent响应函数中this的值会变成window对象而不是触发事件的元素*/
	function returnEvent(e) {
		if (e.target) {
			return e.target;	
		} else if(e.srcElement){
			return e.srcElement;
		};
	}
		/**针对IE中currentStyle获取到的属性值可能是auto,导致转化成int时出现NaN的情况**/
	function improInt (attr) {
		if (parseInt(attr)) {
			return parseInt(attr);
		} else{
			return 0;
		};
	}
	/**div变大***/
	function bigger(e) {
		var node=returnEvent(e);
		if (!!node&&node.nodeName.toUpperCase()=="DIV") {
			node.style.zIndex=100;
			var style=(node.currentStyle||window.getComputedStyle(node));//非IE和IE
			node.style.width=1.2*improInt(style.width)+"px";//宽度放大1.2倍
			node.style.height=1.2*improInt(style.height)+"px";//高度放大1.2倍
			node.style.marginTop=(improInt(style.marginTop)-20)+"px";
			node.style.marginLeft=(improInt(style.marginLeft)-20)+"px";
			node.style.backgroundColor="red";
		};
	}
	/**鼠标离开时,图片恢复原样**/
	function smaller(e) {
		var node=returnEvent(e);
		console.log("returnEvent(e)"+returnEvent(e));
		if (!!node&&node.nodeName.toUpperCase()=="DIV") {
			node.style.zIndex=0;
			var style=node.currentStyle||window.getComputedStyle(node);//非IE和IE
			node.style.width=improInt(style.width)/1.2+"px";
			node.style.height=improInt(style.height)/1.2+"px";//高度缩减1.2倍
			node.style.marginTop=(improInt(style.marginTop)+20)+"px";
			node.style.marginLeft=(improInt(style.marginLeft)+20)+"px";
			node.style.backgroundColor="grey";
		};
	}
	//在document上监听鼠标事件
	if (document.addEventListener) {//其他浏览器和IE8以上都支持
		document.addEventListener('mouseover',bigger,false);
		document.addEventListener('mouseout', smaller, false);
	} else if(document.attachEvent){//IE8及以下下事件监听使用的是attachEvent
		document.attachEvent('onmouseover',bigger);
		document.attachEvent('onmouseout',smaller);
	};

具体实现:

具体实现:DEMO例子