zoukankan      html  css  js  c++  java
  • 拥抱haXe之javascript 也玩mvc

    haXe是高级语言的高级语言,可以将一个haXe程序转换为其它的高级语言,如JS。haXe有很多优点,比如,强类型、泛型、内联、宏、动态语言特性、命名空间……,用haXe写程序比用JS写程序舒服得多。本文尝试使用haXe开发js程序,搭建一个前端mini型mvc例子。

    语言:haXe。haXe编译器可以把haXe程序编译成js程序。

    开发工具:FlashDevelop

    haXe的简介及安装见《html5 canvas 版 hello world! 暨haXe简介》。开发之前,需要修改Flash Develop配置,将Tools->Program Setting->HaXeContext->Disable Compiler-based Completion 设置为 true。否则的话,haXe的自动完成会很痛苦。

    image

    项目结构如上图。其中:index.html是演示页面。页面中引用的jsTest.js就是本haXe项目所生成的js文件。js程序的入口就是Main.hx中的main方法(后文详述) 。main方法查找本页面中的所有的haXe标签,根据标签的name,分派出不同的Controller出来,然后根据haXe标签的map配置,把haXe所在节点的父节点及兄弟节点中id对应的节点映射到控制器里的字段。这样一来,一个页面可以对应0个、1个或多个Controller,每个页面片段也可以对应0个、1个或多个Controller,具有极大的灵活性。

    有map的存在,在Controller那边,可以少写很多代码。map语法为:

    (1)不同的map项由“;”分割;

    (2)每个map项语法为“元素id:映射到字段的id”,如果省略掉“:”和之后的内容,则使用元素id作为映射字段的id。

    这样一来,就可以把客户端的行为封装成强类型的、严格规划好命名空间的、有严格文档的haXe代码。开发前端时,只需要将不同的元素id映射到不同的Controller中即可实现不同的控制行为。

    下面看看核心类:

    (1)Page.hx

    Page类封装了一些常用的方法:

    package ;

    import js.Dom;

    #if hack
    import js.HtmlDom;
    import js.Document;
    import js.HtmlCollection;
    #end

    import js.Lib;

    class Page
    {
        public static function getControllers():HtmlCollection<HtmlDom>
        {
            return doc().getElementsByTagName("haXe");
        }
        public static inline function doc():Document
        {
            return Lib.document;
        }
        public static function getById(id:String,node:HtmlDom=null):HtmlDom
        {
            if (id == null || id == '') return null;
            else if (node == null)
            {
                return doc().getElementById(id);
            }
            if (node.id == id) return node;
            else
            {
                if (node.hasChildNodes() == true)
                {
                    var item:HtmlDom = node.firstChild;
                    while (item != null)
                    {
                        if (item.id == id) return item;
                        item = item.nextSibling;
                    }
                }
            }
            return null;
        }
        public static function getsByName(name:String):HtmlCollection<HtmlDom>
        {
            return doc().getElementsByName(name);
        }
    }

    这里有一个技巧:FlashDevelop 对haXe自动完成支持的不完善。很多js命名空间下的类不能正确支持。比如,Page.hx文件,如果不引入js.HtmlDom等三个类(红色部分),则无法提供自动完成支持,而如果引入这三个类,则编译报错(这三个类已经在js.Dom中了)。解决方案就是使用一个haXe不认识的编译开关,比如“hack”,既能让FlashDevelop提供智能支持,又不会参与到编译过程中去。

    (2)Controller.hx

    Controller.hx 类主要完成map功能,代码为:

    import js.Dom;

    #if hack
    import js.HtmlDom;
    import js.Document;
    import js.Event;
    #end

    import js.Lib;

    class Controller
    {
        public function new(map:String = null, node:HtmlDom = null):Void
        {
            if (map == null) return;
            var mapItems:Array<String> = map.split(';');
            var dy:Dynamic = this;
            for (i in 0 ... mapItems.length)
            {
                var itemTxt:String = mapItems[i];
                var pairs:Array<String> = itemTxt.split(':');
                if (pairs.length > 0)
                {
                    var v0:String = StringTools.trim(pairs[0]);
                    var v1:String = v0;
                    if (pairs.length > 1)
                    {
                        v1 = StringTools.trim(pairs[1]);
                    }
                    if (v0.length > 0 && v1.length > 0)
                    {
                        untyped {
                            dy[v1] = Page.getById(v0,node);
                        }   
                    }
                }
            }
        }   
    }

    (3)Test.hx

    Test类为具体的Controller,为页面添加控制,代码为:

    package orc;

    import js.Dom;

    #if hack
    import js.HtmlDom;
    import js.Document;
    import js.Event;
    #end

    import js.Lib;

    class Test extends Controller
    {
        private var btnSubmit:HtmlDom;
        private var tbOutput:HtmlDom;
        public function new(map:String = null, node:HtmlDom = null):Void
        {
            super(map, node);
            var self:Test = this;
            this.btnSubmit.onclick = function(e:Event):Void
            {
                self.tbOutput.innerHTML = "测试一下";
            };
        }
    }

    (4)Main.hx

    Main类负责调度,且提供程序的入口,代码为:

    package ;

    import js.Dom;

    #if hack
    import js.HtmlCollection;
    import js.HtmlDom;
    import js.Document;
    import js.Event;
    #end

    import js.Lib;
    import orc.Test;

    class Main
    {
        static function main()
        {
            var ctrls:HtmlCollection<HtmlDom> = Page.getControllers();
            if (ctrls != null)
            {
                var l:Int = ctrls.length;
                for (i in 0 ... l)
                {
                    handle(ctrls[i]);
                }
            }
        }
        static function handle(node:HtmlDom):Void
        {
            var className:String = node.getAttribute("name");
            var map:String = node.getAttribute("map");
            var root:HtmlDom = map != null ? node.parentNode: null;
            switch(className)
            {
                case "orc.test":
                    new Test(map,root);
            }
        }
    }

    测试结果图:

    image

    所得到的JS文件大小为12K,其中约6K为haXe的js库。压缩后,文件大小为 4k。如果有多个页面的话,这个js文件会变大,但因为只下载一次,对于一般的网站或应用可以接受。

    这样做有什么好处呢?

    (1)强类型,可以充分利用IDE的提示和完成功能;

    (2)可以把代码放在公共的地方,方便代码的积累。代码抽象好了,一般的应用,只映射一下就搞定了;

    (3)代码结构清晰。

    随着html5的到来,前端的代码量会越来越大,越来越复杂。js太灵活了不好用。拥抱haXe吧!

     

  • 相关阅读:
    sublime如何自动保存
    什么是DQL、DML、DDL、DCL
    Linux Shall命令入门
    省市区地址三级联动jQuery插件Distpicker使用
    ThinkPHP3.2设置404跳转页面
    File.separator
    HiddenHttpMethodFilter
    SpringMVC环境搭建
    JVM介绍(一)
    some characters cannot be mapped using iso-8859-1 character encoding
  • 原文地址:https://www.cnblogs.com/xiaotie/p/2154078.html
Copyright © 2011-2022 走看看