zoukankan      html  css  js  c++  java
  • 我的前端架构之一--页面作用域

    我的前端架构汇总

    初学者推荐文章:JavaScript秘密花园

    场景

    现在页面的内容大都是分块的,常见的如下结构:

    <html>
    <head></head>
    <body>
        <header>
        </header>
        <main>
            <left>
            </left>
            <content>
            </content>
            <right>
            </right>
            <footer>
            </footer>
        </main>
    </body>
    </html>

    其中 left ,right,content,footer 是使用(或部分使用)异步加载的方式来加载远程页面的。

    如果left是菜单, content是一个带有选项卡的多页面结构,很多情况下,content下的每个页面需要一个 iframe 来隔离每个页面,避免 A 页面 和 B 页面控件ID和 Js 方法名重复。

    加载iframe 1会造成一些性能的浪费,2会增加客户端浏览器的压力,因为Dom结构很庞大,3给各个选项卡页面通信、页面间带来麻烦。

    我需要解决的就是不使用 iframe 而加载很多页面,又不会产生冲突。

    解决方案

    给Dom元素添加作用域,作用域可以看作是页面的Dom大容器,它也是一棵树,根节点是 html。作用域结构是下面的结构:

    html
        left
        content
        right
        footer

    jv.page(dom) 方法返回 dom元素所在的作用域。为了简化操作,可以在 click 等带有event,可以找到事件触发源的方法里,使用 jv.page() 得到当前作用域。

    $(selector, jv.page(dom)) 方法对DOM元素进行选择。

    页面上定义方法

    普通方法定义是不行的,像这样:

    function test(){}

    这种定义方法是公开到 window 下的。类似于:

    window.test = function(){}

    如果A页面和B页面都使用同一个 test 方法,则 B页面的 test 方法会覆盖 A页面的 test方法。

    我们要改造的效果是:把方法定义到各个作用域上去。核心是作用域!

    新的定义方法:

    this.test = function(){}

    this 不是常量,它不一定是 window,它表示该Dom容器做为作用域的 MyPageObject 对象,它和作用域DOM容器是一一对应的,但不是作用域DOM容器。它同样是一棵树。这棵树的根是 window ,子数据在 window.SubPages 中存储

    我们在加载远程异步加载页面的时候,需要手动指定 this 对象 。核心代码:

    $.extend.LoadView = function (p) {
        //清空当前节点的内容。
        //Ajax获取远程内容。在回调中处理HTML
        //1. 使用过滤器过滤出要显示的部分。
        //2. 把 Js 分为两部分: 最先执行的JS,和 最后执行的JS ,中间填充 DOM对象(包含Css)
        //3. 运行最先执行的JS,(如果 script 标签有 init 属性,则认为它是需要最先加载执行的JS ) 使用 call 或 apply 改变 Js 的 this当前上下文。
        //4. 填充DOM
        //5. 运行最后执行的JS,使用 call 或 apply 改变 Js 的 this 当前上下文。
    }

     

    这样定义的页面,这个页面可以独立运行,也可以被LoadView多次加载运行。

    this 是当前加载页面部分的作用域对象。由于this易变,我们引入了 me 对象。me是在后台自动加入的。上面定义方法的方式也可以这样:

    me.test=function(){}

    页面中调用方法

    如果在页面上使用 this.test = function(){} 定义了方法,如何使用呢。如下:

    <script>
        this.test = function(){
            var doer = jv.getDoer();
            alert(doer.innerHTML);    //显示确定
        }
    </script>
    <body>
        <button onclick="jv.me(event).test(event)">确定</button>
    </body>

    其中 jv.me(event) 方法找出 作用域的 MyPageObject 对象,即方法中定义的 this 对象。 传入 event 对于浏览器兼容性来说,是有必要的。 

    jv.getDoer(event) 方法会递归查找方法参数中的 event 对象,找出触发事件的源。所以在调用方法时,参数最后要传递 event

    jv.getDoer按以下优先级进行确认:

            var ret = null;
            if (evt.srcElement) {
                ret = evt.srcElement;
            }
            else if (evt.target) {
                ret = evt.target;
            }
            else if (evt.originalEvent === true) {
                ret = evt.target;
            }
            else if (evt.originalEvent == "me") {
                ret = evt.target;
            }
            else if (evt.originalEvent == "func") {
                ret = evt.target();
            }
            else if (evt.originalEvent == "jquery") {
                ret = $(evt.target)[0];
            }
            else if (evt.fromElement) {
                ret = evt.fromElement;
            }
            else if (evt.currentTarget) {
                ret = evt.currentTarget;
            }

    如果对父元素绑定了事件,使用子元素触发了click,则:

    currentTarget 表示父元素; target表示子元素。

    自定义页面的生命周期

    作用域的 MyPageObject 对象 简称 me 对象,因为它是通过 jv.me() 得到的。

    每个页面的最后,都会调用一个Js方法:jv.myOnInit(); 来实现页面的自动化和执行页面生命周期的各个方法。

    jv.myOnInit 会依次执行以下方法

    1. 执行 me.Page_PreInit

    2. 执行 jv.MyInitOn_PreFith ,系统脚本给最初的容器计算高度

    3. 执行 jv.MyInitOn 字典里的 value 部分。这是系统脚本注册的自动化部分。

    4. 执行 me.Page_Init

    5. 执行 me.Page_Render 字典里的 value 部分,这是页面脚本自己的自动化部分。

    6. 执行 jv.MyInitOn_Fithed,系统脚本在脚本最后,计算容器高度。

    7. 执行 me.Page_Inited

    其中2,3,6 是系统自动执行的脚本。除去2,3,6,其余的部分,就是页面能控制的生命周期。

    1. Page_PreInit

    2. Page_Init, 最常用

    3. Page_Render 这是字典结构。

    4. Page_Inited

    自动化脚本示例:

    1. 自动化初始化时间选择控件。

    引用的第三方时间选择控件的Api,一般是显式进行定义,像这样: $("#id").时间控件方法(格式);如 My97:

    $("#date").click(function () { WdatePicker({ $dpPath: jv.Root + "R/My97/", dateFmt: "yyyy-MM-dd" }); });

    利用页面最后会执行 jv.myOnInit 中的 jv.MyInitOn 字典的数据,进行自动化初始化。

        jv.MyInitOn["MyDate"] = function (container) {
            jv.loadJsCss("js", jv.Root + "R/My97/wdatepicker.js");
    
            container = container || jv.page();
    
            $(".MyDate", container).each(function () {
                var $self = $(this);
                var format = $self.attr("dtFormat") || 'yyyy-MM-dd';
                $self.click(function () { WdatePicker({ $dpPath: jv.Root + "R/My97/", dateFmt: format }); });
                if (!$self.val()) return;
    
                $self.val($self.val().getDate().toString(format));
            })
      });

    这样,所有包含 MyDate 的类元素,都会自动注册 click 事件,显示时间控件。只需要这样:

    <input class="MyDate"/>

    2. 改造默认的Ajax,在请求出错时,自动弹出信息框。

        jv.MyInitOn["InitJQueryAjax"] = function () {
    
            $.ajaxSetup({
                //请求成功后触发
                success: function (data) {
    
                },
                //请求失败遇到异常触发
                error: function (xhr, status, e) {
                    //弹框报错。
                },
                //完成请求后触发。即在success或error触发后触发
                complete: function (xhr, status) {
                    $(document.body).css("cursor", "default");
                },
                //发送请求前触发
                beforeSend: function (xhr, opt) {
                    $(document.body).css("cursor", "wait");
                }
            });
        };

    服务器额外管的闲事

    仅当是GET请求页面HTML时,为方便页面实现以上机制,服务器会对页面输出进行以下干涉:

    1. script标签移到最后。

    2. 去除重复引用

    3. 解析 ~/ 符号
    4. 把Mvc服务器定义的变量输出到前端: me.变量=值;

    5. 在最前面生成: jv.Root=""~/"";var me=new MyPageObject();jv.addRequest(me);me.SYSTEMPOWERBUTTON=[]; 

      其中:

      jv.addRequest用于分隔页面作用域

      me.SYSTEMPOWERBUTTON 用于定义该页面的按钮权限。

    6. 给 script 标签的最前头,添加: var me=this;

    项目部署教程:

    http://www.cnblogs.com/newsea/p/4781000.html

  • 相关阅读:
    VS停止调试,IIS Express也跟着关闭了
    会钓鱼的程序员
    彻底搞懂https原理
    Java小知识
    ORA-01000: 超出打开游标的最大数(java.sql.SQLException: ORA-00604: 递归 SQL 级别 1 出现错误)
    虚拟机电脑重启后连接不上ORACLE
    电视直播源
    国内开源镜像站
    分享一波泰勒斯威夫特手机高清壁纸
    阿里云网盘内测申请
  • 原文地址:https://www.cnblogs.com/newsea/p/4679080.html
Copyright © 2011-2022 走看看