• 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. 关于动画

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

  • 相关阅读:
    C语言scanf函数转换说明表及其修饰符表
    C语言printf函数转换说明表及其修饰符表
    JAVA中this和super用法
    JAVA构造器,重载与重写
    初步学习JAVA面向对象初步认识及面向对象内存分析图举例说明
    webpack4.0报WARNING in configuration警告
    chrome开发者工具--使用 Network 面板测量您的网站网络性能。
    随笔记录--Array类型
    PXC(percona xtradb cluster)新加节点避免SST的方法
    pt-online-schema-change原理解析
  • 原文地址:https://www.cnblogs.com/bluen/p/5055878.html
Copyright © 2020-2023  润新知