js 是一门神奇的语言。我们在使用js过程中,难免会使用到自己封装的小接口,即使我们已经有了完备的jquery框架。因此我准备记录下来laz.js 框架的编写过程, 也是记录自己的学习过程。
框架编写除了有好的抽象思维和恰当的使用环境之外,自然需要最简单的接口。而正如水里的鸭子,表面平静水下抓狂,一个接口越简单,那么实现这个接口的方法就越复杂。难免的,就要接触到关于传出参数的种种处理。
javascript的每一个方法都支持不定参数:
function params_test() { // arguments 就是该方法的参数列表 var argList = arguments; };
因为这种参数列表的存在,我们可以玩出很多花样。比如默认参数的实现:
function default_param() { //设置默认参数 var param0 = arguments[0]==undefined?‘default value‘:arguments[0]; }
* 注意这里 arguments[0]==undefined?a:b 而不是 arguments[0]?a:b 是因为arguments[0] 也就是这个默认参数很有可能是一个boolean值并且是一个false 也有可能是一个number类型的0,这些都会导致程序选择默认值而不是传入参数,
我们之后在编写类型判断方法的时候也会提到。
或者不定参数的实现:
function lot_params() { for(var i in arguments) { // 遍历参数 } }
我不认为js是一种无类型的语言,准确的说,对于类型,我们不用操心的就是它那自由的 var 变量声明和赋值操作吧。
Object 是 javascript语言的基本类型。 我们可以说数组是Array 类型 也可以说数组是Object 类型,同理String等等也是。因此在类型判断的时候,我会将是否是Object的类型判断放在最后,因为但部分情况下,判断一个参数是否是Object的,意义并不太大。
以下是因为懒,所以加入进laz.js中的类型判断方法。
//判断是否是一个数组类型 用法如 is_array(tmp) function is_array() { return !arguments[0] ? false : arguments[0].constructor == Array; }; // 判断是否是一个字符串类型 用法如上。 function is_string() { return !arguments[0] ? false : arguments[0].constructor == String; }; // 判断是否是一个数字 int类型 function is_number() { return (arguments[0] != 0 && !arguments[0]) ? false : (arguments[0].constructor == Number || typeof arguments[0] == "number" || (!isNaN(arguments[0]))); }; //判断是否是bool类型 // 正如上文提到的:和is_number一样 数字0 和bool 的false 都会被认为是‘非‘逻辑 // 因此在处理这种类型时 绝对不能简单的if(param) function is_bool() { return (arguments[0] == undefined) ? false : arguments[0].constructor == Boolean }; //是否是element 节点类型 function is_element() {
return !arguments[0]?false:(arguments[0] instanceof Element); }; //是否是Text 文字文本类型 function is_text(){return !arguments[0]?false:(arguments[0] instanceof Text);}; //是否是一个function/ 方法 function is_function(){return !arguments[0] ? false : typeof arguments[0] == "function";}; // 这里用到统一的consturtor 用法如 is_type(param,MyClass) function is_type(p1,p2){return !p1?:false:p1.constructor?p1.constructor == p2:false;};
* constructor 属性返回对创建此对象的数组函数的引用 -- W3School 我的理解就是一个类的构造函数。 我们可以通过自己编写的is_type方法 传入参数1 一个对象 参数2 一个类/类型 进行判断
document 下element节点的获得 有很多种方式 因为在项目中 如果只获得几个节点 我会直接采用id的形式 而多个节点的获取 ,我会直接通过下面要介绍的laz.js 创建html 节点 同时保留相对应的js对象 来直接获取,
再加上jquery的选择器已经相当出色的,所以在懒人框架laz.js中并没有加入节点选择器的相关方法。下面主要说说创建节点。
<div class="div_class"> <div class = "part0">1</div> <div class = "part1">2</div> <div class = "part2">3</div> </div> <!-- Html 编写大概是这样的>
使用xml形式来描述一个树状结构,可能再恰当不过了。在写laz.js之初,我就在想 如何能让js写的像xml一样。= = 于是就有了下面的样式:
<script>
$$Div
(
{class:"div_class"}
$$Div({class:"part0"}).setHTML(‘1‘),
$$Div({class:"part1"}).setHTML(‘2‘),
$$Div({class:"part2"}).setHTML(‘3‘)
).addToNext();
</script>
是的,使用懒人js laz.js 这样写 就可以实现跟上面html一样的内容。$$Div 是一个方法名 主要用来创建 document.createElement(‘div‘),同时通过参数类型判断,给这个节点加入子节点和加入attributes。
当然 也就是说 你要想创建一个h3节点对象 那么你必须要有$$H3方法。 开始我是通过一个配置表 使用eval 生成 常用的一些html 节点方法 但是奈何使用eval生成方法 编辑器的代码提示不够只能,所以就把脏活一口气干完了。
function $$Ul(){ return _cook_node(‘ul‘,arguments)}; function $$Text(){ return _cook_node(‘text‘,arguments)}; function $$Li(){ return _cook_node(‘li‘,arguments)}; function $$Div(){ return _cook_node(‘div‘,arguments)}; function $$Input(){ return _cook_node(‘input‘,arguments)}; function $$P(){ return _cook_node(‘p‘,arguments)}; function $$H1(){ return _cook_node(‘h1‘,arguments)}; function $$H2(){ return _cook_node(‘h2‘,arguments)}; function $$H3(){ return _cook_node(‘h3‘,arguments)}; function $$Button(){ return _cook_node(‘button‘,arguments)}; function $$Iframe(){ return _cook_node(‘iframe‘,arguments)}; function $$Form(){ return _cook_node(‘form‘,arguments)}; function $$Label(){ return _cook_node(‘label‘,arguments)}; function $$Thead(){ return _cook_node(‘thead‘,arguments)}; function $$Tr(){ return _cook_node(‘tr‘,arguments)}; function $$Td(){ return _cook_node(‘td‘,arguments)}; function $$Th(){ return _cook_node(‘th‘,arguments)}; function $$Tbody(){ return _cook_node(‘tbody‘,arguments)}; function $$Thead(){ return _cook_node(‘thead‘,arguments)}; function $$Nav(){ return _cook_node(‘bav‘,arguments)}; function $$Table(){ return _cook_node(‘table‘,arguments)}; function $$A(){ return _cook_node(‘a‘,arguments)}; function $$Span(){ return _cook_node(‘span‘,arguments)}; function $$Br(){ return _cook_node(‘br‘,arguments)}; function $$I(){ return _cook_node(‘i‘,arguments)}; function $$B(){ return _cook_node(‘b‘,arguments)}; function $$Ol(){ return _cook_node(‘ol‘,arguments)}; function $$Img(){ return _cook_node(‘img‘,arguments)}; function $$Strong(){ return _cook_node(‘strong‘,arguments)}; function $$H4(){ return _cook_node(‘h4‘,arguments)}; function $$H3(){ return _cook_node(‘h3‘,arguments)}; function $$Article(){ return _cook_node(‘Article‘,arguments)};
嗯。 这是我目前能想到的最好的方法。 如果有更好的建议,请留言给我~ 接下来放上_cook_node 方法:
function _cook_node(tag,arr){ if (tag == "text"){ //如果是纯文本 if (is_string(arr)){return document.createTextNode(arr);}else{console.log("纯文本只支持字符串作为参数");} }else{ var element = document.createElement(tag); for(var i in arr){ var tmp = arr[i]; // 类型判断 如果是element 或者text 就把它 加入到节点中 // 如果不是, 那就作为系欸但的属性参数 if (is_element(tmp) || is_text(tmp)){ element.appendChild(tmp); }else { for (var key in tmp) {element.setAttribute(key, tmp[key]);}; } } return element; } };
我们通过以上的方法创建出节点对象 ,然后需要把这个对象添加到父节点中。
因为跟jq不同, 我们放回的是一个纯element对象, 因此 可以直接调用element的方法。
最常用的可能是下面几种情况:
1. 添加到当前javascript标签的前面或者后面 比如:
<body> <div> <ul> <li>1</li> <li>2</li> <!-- 我想创建一个li对象 并且放到这里 --> <li>4</li> </ul> </div> </body>
在不通过id class tag name等情况下, 将自己创建的element的对象插入到指定位置,该如何实现呢?
我的思路是这样的。 首先我们知道html 和js 包括css 是至上而下依次加载的,我们就通过这一特性,开始展开。
<body> <div> <ul> <li>1</li> <li>2</li> <!-- 我想创建一个li对象 并且放到这里 --> <script> //我们此时获取的script标签 其实是html页面加载到这个位置的所有script // 也可以理解为 这个列表的最后一个 就是当前的这个script标签 var slist = document.getElementsByTagName(‘script‘); </script> <li>4</li> </ul> </div> </body>
注意这句:也可以理解为 这个列表的最后一个 就是当前的这个script标签。
因此我们可以获得当前的script标签的节点 也可以获得当前script标签的父节点。 那么我们创建的子节点就自然而然‘找到爸爸’了。下面是针对Element对应的做的扩展。
//在script节点之前插入 Element.prototype.addToNext = function() { var slist = document.getElementsByTagName(‘script‘); if (slist.length > 0) { var s = slist[slist.length - 1]; var p = s.parentNode; p.appendChild(this); } return this; }; //在script节点之后插入 Element.prototype.addToLast = function() { var slist = document.getElementsByTagName(‘script‘); if (slist.length > 0) { var s = slist[slist.length - 1]; var p = s.parentNode; p.insertBefore(this,s); } return this; };
当然 为了在编写js的时候 可以实现‘不间断调用方法’ 比如a.to1().to2().... 我习惯在没有返回值的方法后面return this。 也因此针对element 扩展了其他方法,大多都是为了可以连续调用接口而写的:
Element.prototype.addChildElement = function () { this.appendChild(arguments[0]); return this; }; Element.prototype.addTo = function () { arguments[0].appendChild(this); return this; }; Element.prototype.addToBody = function () { this.appendTo(document.body); return this; }; Element.prototype.setHTML = function () { if (arguments[0] == undefined) return this; var t = ""+arguments[0]; if (t.indexOf(‘<‘) == -1 && t.indexOf(‘>‘) == -1 ) { this.appendChild(document.createTextNode(t)); }else { this.innerHTML = this.innerHTML + t; } return this; };
2. 通过选择器获得某个节点的对象 然后直接appendChild()
3. 插入到body
4 等等
碎觉了。。 希望明天能坚持记录下来。。
原文:http://www.cnblogs.com/bluen/p/5055878.html