AngularJS对带有contentEditable的普通元素directive一个ng-model

[code lang=”js”]

‘use strict’;
angular
.module(‘app’)
.directive(‘contenteditable’, function() {
return {
restrict: ‘A’, // only activate on element attribute
require: ‘?^ngModel’, // get a hold of NgModelController
link: function(scope, element, attrs, ngModel) {
if (!ngModel) {
return;
} // do nothing if no ng-model
// Specify how UI should be updated(更新ui)
ngModel.$render = function() {
element.html(ngModel.$viewValue || ”);
};
// Listen for change events to enable binding(添加事件)
element.on(‘blur keyup change’, function() {
scope.$apply(readViewText);
});
// No need to initialize, AngularJS will initialize the text based on ng-model attribute
// Write data to the model
function readViewText() {
var html = element.html();
// When we clear the content editable the browser leaves a <br> behind
// If strip-br attribute is provided then we strip this out
if (attrs.stripBr && html === ‘<br>’) {
html = ”;
}
ngModel.$setViewValue(html);
}
}
};
});
[/code]
Well-Crafted Apps: How make a two-way binding to your contenteditable DIV or SPAN using AngularJS directives

angularJS controller之间的通信

1、event
这里可以有两种方式,一种是$scope.$emit,然后通过监听$rootScope的事件获取参数;另一种是$rootScope.$broadcast,通过监听$scope的事件获取参数。
这两种方法在最新版本的Angular中已经没有性能区别了,主要就是事件发送的方向不同,可以按实际情况选择。
[code lang=”js”]
/******* example ****/
///////子级传递数据给父级
// 子级传递
$scope.$emit(‘transferType’, "我要发送给父");

// 父级接收
$scope.$on(‘transferType’, function(event, data) {
$scope.transferType = data;
//console.log(data),接收到的值
};

/////// 父级传递数据给子级
// 父级传递
$scope.transferType = ”;
$scope.$broadcast(‘transferType’, "我要发送给子");

// 子级接收
$scope.transferType = ”;
$scope.$on(‘transferType’, function(event, data) {
$scope.transferType = data;
//console.log(data),接收到的值
}
[/code]

2、service
可以创建一个专用的事件Service,也可以按照业务逻辑切分,将数据存储在相应的Service中。

3、$rootScope
这个方法可能会比较dirty一点,胜在方便,也就是把数据存在$rootScope中,这样各个子$scope都可以调用,不过需要注意一下生命周期

4、直接使用$scope.$$nextSibling及类似的属性
类似的还有$scope.$parent。这个方法的缺点就更多了,官方不推荐使用任何$$开头的属性,既增加了耦合,又需要处理异步的问题,而且scope的顺序也不是固定的。不推荐

另外就是通过本地存储、全局变量或者现代浏览器的postMessage来传递参数了,除非特殊情况,请避免这类方式。

js和jq获取宽高

工作中经常会用到js获取页面或者容器的宽高,经常会混淆。

如果出现获取的值不对,可能是页面未load渲染完成
下面结果都是基于ie7 =以上的结果
一、获取浏览器工作窗口宽高

[code lang=”js”]
/*1、获取窗口的高度与宽度(不包含工具条与滚动条)*/
document.documentElement.clientWidth/document.documentElement.clientHeight;//(IE、FireFox)
$(window).width()/$(window).height();

/*2、获取窗口的高度与宽度(包含滚动条)*/
window.innerWidth/window.innerHeight;//>IE8(api说是不包含工具条与滚动条,但实际上是包括了的滚动条的宽度)

/*3、获取窗口的高度与宽度(包含工具条与滚动条)*/
window.outerWidth/window.outerHeight;//>ie8
[/code]

二、获取document,body的宽高

[code lang=”js”]
/*1、获取document的整体高度(包括被卷去的部分)*/
document.body.clientWidth/document.body.clientHeight ;//IE、FireFox、Opera
document.body.offsetWidth/document.body.offsetHeight;//包括边线的宽高
document.body.scrollWidth/document.body.scrollHeight;

$(document).width()/$(document).height()/$(‘body’).height();
[/code]

三、获取滚动条的高度

[code lang=”js”]
/*1、浏览器滚动条滚动的位移*/
document.body.scrollTop/document.body.scrollLeft/

/*2、返回当前页面相对于窗口显示区左上角的位置(测试结果是返回浏览器滚动条滚动的位移)*/
window.pageXOffset/window.pageYOffset;//>ie8
[/code]

四、浏览器的宽高位置

[code lang=”js”]
/*1、返回浏览器相对于屏幕窗口的坐标*/
window.screenX/window.screenY;//>ie8
window.screenLeft/window.screenTop;
/*2、返回屏幕的宽高*/
window.screen.height/window.screen.width;
/*3、屏幕可用工作区的宽高*/
window.screen.availHeight/window.screen.availWidth;
[/code]

document.onreadystatechange事件的用法分析

转载自:http://www.jb51.net/article/20445.htm

onreadystatechange 事件能辨识readyState 属性的改变。

[code lang=”js”]
<script type="text/javascript">
var xmlHttp;
//创建一个XmlHttpRequeset对象
function createXMLHttpRequest(){
if(window.ActiveXObject){
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else if(window.XMLHttpRequest){
xmlHttp = new XMLHttpRequest();
}
}
//开始一个请求
function startRequest(){
createXMLHttpRequest();
xmlHttp.onreadystatechange = state_change;
xmlHttp.open("GET", "SimpleRespose.xml", true);
xmlHttp.Send(null);
}

function state_change(){
//描述一种"已加载"状态;此时,响应已经被完全接收。200表示成功收到
if(xmlHttp.readyState == 4 && xmlHttp.status == 200){
alert("The Server Replied with:" + xmlHttp.responseText);
}
}
</script>
[/code]

这个写法是有些小问题的,首先创建xmlHttpRequest对象,当它完毕的时候,xmlHttpRequest.readyState的值是0,xmlHttp.onreadystatechange = statechange,因为状态没有改变(xmlHttpRequest.readyState的值是0),所以不触发函数。
但是结构是正常的,研究后发现于原来它运行的机制是这样的。首先创建一个xmlHttpRequest的对象之后xmlHttp.readyState的值是0了,然后xmlHttp.onreadystatechange = state_change没有运行。紧接着是open(),这个函数发生了之后xmlHttp.readyState的值是1了,那么就会有一个断点在Open()函数处断开,保留现场,紧接着又返回到xmlHttp.onreadystatechange = state_change运行,然后再执行Send()函数,这个函数发生了之后xmlHttp.readyState的值是2了,接着又返回到xmlHttp.onreadystatechange = state_change运行。以此类推。

js判断上传文件大小

[code lang=”js”]
<html>
<head>
<title>js判断上传文件大小</title>
<Script language="JavaScript" type="text/javascript">
function checkFileSize(filesizeKb){
try{
var isIE = /msie/i.test(navigator.userAgent) && !window.opera;
var target = document.getElementById("filename");
/**** 判断图片宽高 ******/
var img = new Image(); //构造JS的Image对象
//获取图片url
img.src = getFileUrl(target);
img.onload = function(){
console.log(‘上传的图片大小为:’+ img.width);
};
/**** 判断图片size ******/
function fileChange(target) {
var fileSize = 0;
if (isIE && !target.files) {
var filePath = target.value;
var fso = new ActiveXObject("Scripting.FileSystemObject");
if(!fso.FileExists(filePath)){
alert("上传文件不存在,请重新输入!");
document.execCommand("undo");//对网页的所有表单进行撤销的
return false;
}
var file = fso.GetFile (filePath);
fileSize = file.Size;
}else {
fileSize = target.files[0].size;
}
var size = fileSize / 1024;
if(size>10000){
alert("附件不能大于10M");
}
};
//获取图片url
function getFileUrl(target) {
var url;
if (navigator.userAgent.indexOf("MSIE") >= 1) { // IE
url = target.value;
} else if (navigator.userAgent.indexOf("Firefox") > 0) { // Firefox
url = window.URL.createObjectURL(target.files.item(0));
} else if (navigator.userAgent.indexOf("Chrome") > 0) { // Chrome
url = window.URL.createObjectURL(target.files.item(0));
}
return url;
};
fileChange(target);
formname.submit();
}
} catch(e){
if(e.description=="Automation服务器不能创建对象"){
alert("文件大小验证未生效!\r\n启用此验证,请如下修改浏览器设置:工具->Internet选项->安全->本地Intranet->自定义级别->ActiveX控件和插件->对没有标记为安全的ActiveX控件进行初始化和脚本运行->启用!");
formname.submit();
}else{
//alert(e.description);
//可能出现“拒绝访问”异常,刷新后又无此异常
window.location.reload();
}
}
}
</script>
</head>
<body>
<form name="formname" action="test2.jsp">
<input type="file" name="filename" id="filename"><br>
<input type="button" value="上传文件" onclick="checkFileSize(45)" ><br>
</form>
</body>
< /html>
[/code]

移动端开发-rem

对于手机开发,适配是一个非常麻烦的事情,大家一般都是是呀百分百或者缩放来做,但是这种方法还是会导致实际效果跟设计稿差别很大。
借鉴腾讯的做法,使用先计算当前尺寸对应设计稿的1像素比例,在rem来写尺寸大小。这个方法个人到现在发现是最好的一种
只需要按照图片或者容器在设计稿的尺寸来写,就能很完美的呈现
1、在head标签里引入下面代码
[code lang=”js” type=”js”]
//全局字体rem
(function(window, document, widSize) {
‘use strict’;
var hotcss = {};
(function() {
var viewportEl = document.querySelector(‘meta[name="viewport"]’),
dpr = window.devicePixelRatio || 1,
maxWidth = 540;

dpr = dpr >= 3 ? 3 : ( dpr >=2 ? 2 : 1 );

document.documentElement.setAttribute(‘data-dpr’, dpr);
hotcss.dpr = dpr;

document.documentElement.setAttribute(‘max-width’, maxWidth);
hotcss.maxWidth = maxWidth;

var scale = 1 / dpr,
content = ‘width=device-width, initial-scale=’ + scale + ‘, minimum-scale=’ + scale + ‘, maximum-scale=’ + scale + ‘, user-scalable=no’;

if (viewportEl) {
viewportEl.setAttribute(‘content’, content);
} else {
viewportEl = document.createElement(‘meta’);
viewportEl.setAttribute(‘name’, ‘viewport’);
viewportEl.setAttribute(‘content’, content);
document.head.appendChild(viewportEl);
}

})();
hotcss.mresize = function() {
//var innerWidth = document.documentElement.getBoundingClientRect().width || window.innerWidth;
var clientWidth = document.documentElement.clientWidth,
clientHeight = document.documentElement.clientHeight;

//横屏
clientWidth = (clientWidth>clientHeight)? clientHeight: clientWidth;
console.log(clientWidth);
////优化pc和平板体验
if (hotcss.maxWidth && (clientWidth / hotcss.dpr > hotcss.maxWidth)) {
clientWidth = hotcss.maxWidth * hotcss.dpr;
}
console.log(clientWidth);

var htmlSize = clientWidth / widSize * 100;
htmlSize = htmlSize < 50 ? 50 : htmlSize;
document.documentElement.style.fontSize = htmlSize + ‘px’;
};

setTimeout(function() {
hotcss.mresize();
//防止某些机型怪异现象,异步再调用一次
}, 333);
//绑定resize的时候调用
hotcss.mresize();

})(window, document, 750);
[/code]
2、在css填写容器宽高时,(假设设计尺寸宽是640)直接填写图片或者设计的 尺寸值/100 + rem。(eg:图片尺寸200x100px,可以直接写width:2rem;height:1rem;)
这种方式 在不同手机下显示尺寸都是跟设计稿完美对应的,唯一需要修改的就是高度不一样,元素之间的间隔需要做修改
3、高度不一样,调整间隙可以使用媒体查询配合

禁止document滚动,保留内部滚动

html:
onmousewheel=”return scroll(event,this)”

[code lang=”js”]

this.scroll = function(event,scroller){
var k = event.wheelDelta? event.wheelDelta:-event.detail*10;//区分mousewheel或DOMMouseScroll
scroller.scrollTop = scroller.scrollTop – k;
return false;
}

//测试
function preventDefault(e) {
e = e || window.event;
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
}

/*$(navList).hover(function(event){
if (window.addEventListener) {
window.addEventListener(‘DOMMouseScroll’, function(e){preventDefault(e);}, false);
}
window.onmousewheel = document.onmousewheel = function(e){preventDefault(e);};
},function(event){
if (window.removeEventListener) {
window.removeEventListener(‘DOMMouseScroll’, function(e){preventDefault(e);}, false);
}
window.onmousewheel = document.onmousewheel = null;
})*/

[/code]

js高级

一、js之作用域链(AO链)
总结:
js执行顺序
一:词法分析阶段
1、先把接收到的参数放到激活对象上(AO)

2、再对函数体中代码作分析
a: var xx = yy;
做法:声明一个xx属性在激活对象上,但不赋值,所以值是undefined;
如果参数上有已经有xx,则不做动作.

b:function ttt() {}
做法:直接声明ttt属性(覆盖参数产生AO),且内容是函数体。

二:执行语句阶段

1.作用域:
[code lang=”js”]
/*
活动对象/激活对象, Active Object
函数的变量 有其作用域,
即, 引用某变量时,在某个范围内查询该变量,
这个范围,又在哪儿?

在AO上找

在函数调用的瞬间,会产生一个AO,
这个AO对象,的属性, 即存储着该函数所能引用到的变量.
*/
[/code]

2.词法分析(预编译):
[code lang=”js”]
/*
在函数运行时,会先进行词法分析
1.分析参数:函数声明的参数,形成AO的属性,值是undefined
2.分析变量声明:
分析变量声明,如var age;
如果AO上还没有age属性,则添加AO属性,值是undefined
如果AO上已经有age属性,则不做任何影响
3.分析函数声明:如function age(){},则把函数赋值给AO.age;注:如果之前age 属性已经存在,则无情的覆盖
*/
function t3(greet){
var greet = "hello";
alert(greet);
function greet(){};
alert(greet);
}
t3(null);
//结果:function()

[/code]

二:函数表达式和arguments(object)
arguments和this 每个函数都有自己独有的,且不进行链式查找

arguments是收到的实参副本列表

arguments.callee 属性代表 当前运行的函数

判断鼠标向上滚动还是向下滚动

因为不同的浏览器有不同的滚轮事件。主要是有两种,onmousewheel(firefox不支持)和DOMMouseScroll(只有firefox支持),关于这两个事件这里不做详述,想要了解的朋友请移步:鼠标滚轮(mousewheel)和DOMMouseScroll事件,所以在这个过程中需要添加事件监听,代码如下:兼容firefox采用addEventListener监听。
/*注册事件*/
if(document.addEventListener){
document.addEventListener(‘DOMMouseScroll’,scrollFunc,false);
}//W3C
window.onmousewheel=document.onmousewheel=scrollFunc;//IE/Opera/Chrome
另外判断滚轮向上或向下滚动在浏览器中也要考虑兼容性,现在五大浏览器(IE、Opera、Safari、Firefox、Chrome)中Firefox 使用detail,其余四类使用wheelDelta;两者只在取值上不一致,代表含义却是一致的,detail只取±3,wheelDelta只取±120,其中正数表示为向上,负数表示向下。

[code]
var isScroll = true;
//判断方向
var scrollFunc = function(e){
//1:top,2:bottom
var direct = 0;
e = e || window.event;
//单次滚动控制
if(isScroll){
isScroll = false;
//判断浏览器IE,谷歌滑轮事件
if (e.wheelDelta) {
//当滑轮向上滚动时
if(e.wheelDelta > 0) {
direct = 1;
console.log("滑轮向上滚动");
}
//当滑轮向下滚动时
if(e.wheelDelta < 0) {
direct = 2;
console.log("滑轮向下滚动");
}
}
//Firefox滑轮事件
else if(e.detail){
//当滑轮向上滚动时
if(e.detail< 0){
direct = 1;
console.log("滑轮向上滚动");
}
//当滑轮向下滚动时
if (e.detail> 0){
direct = 2;
console.log("滑轮向下滚动");
}
};
//通过结果执行切换
if(direct != 0){
isScroll = true;
self.scrollTab(direct);
};
};
};
[/code]

在非firefox浏览器中,滚轮向上滚动返回的数值是120,向下滚动返回-120

而在firefox浏览器中,滚轮向上滚动返回的数值是-3,向下滚动返回3

代码部分如下,e.wheelDelta是判断是否为非firefox浏览器,e.detail为firefox浏览器
if(e.wheelDelta){//IE/Opera/Chrome
t1.value=e.wheelDelta;
}else if(e.detail){//Firefox
t2.value=e.detail;
}