js渐渐入门之懒人框架- laz.js

 一 前言

 js 是一门神奇的语言。我们在使用js过程中,难免会使用到自己封装的小接口,即使我们已经有了完备的jquery框架。因此我准备记录下来laz.js 框架的编写过程, 也是记录自己的学习过程。

框架编写除了有好的抽象思维和恰当的使用环境之外,自然需要最简单的接口。而正如水里的鸭子,表面平静水下抓狂,一个接口越简单,那么实现这个接口的方法就越复杂。难免的,就要接触到关于传出参数的种种处理。

<body>
<ul>
<li>1</li>
<li>
<div class="div_class">
    <div class = "part0">1</div>
    <div class = "part1">2</div>
    <div class = "part2">3</div>
</div>
</li>
</ul>
</body>

<!-- 一段这样的html代码 使用laz.js 可以这样: -->
<body>
<ul>
<li>1</li>
<li>
<script>
$$Div
(
  {class:"div_class"}
  $$Div({class:"part0"}).setHTML('1'),
  $$Div({class:"part1"}).setHTML('2'),
  $$Div({class:"part2"}).setHTML('3')
).addToNext();
</script>
</li>
</ul>
</body>

二 进入正题

1.关于参数

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)
    {
          // 遍历参数 
    }
}

 2. 关于类型判断

  我不认为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 一个类/类型 进行判断

3.关于HTML 节点的获得和创建

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 等等

4. 关于动画

碎觉了。。 希望明天能坚持记录下来。。

原文地址:https://www.cnblogs.com/bluen/p/5055878.html