打印

[原创]web前端结构与行为的分离

如今的web开发也需要越来越接近MVC框架模式,web的前端可视为由结构+表现+行为组成,根据W3C的标准,使用xhtml+css已经使得结构和表现成功分离。在网上看到越来越多被重构过的网站是件非常令人欣喜的事情,如果现在要让我再做一个表格布局的网页,当我看到那一堆可以被一句CSS代替的表格代码时,我甚至会恶心到想吐!标准给挣扎在混沌的淤泥里的我们带来了清新空气,良好重构过的页面也像出淤泥而不染的清莲,香馨沁人心脾!那么下一步就应该是结构和行为的分离了,因为表现和行为本来是不相关的,就算微软的浏览器标准支持一个我当时非常喜欢的css里的behavior,但现在看来表现依然不能包括行为,不应该去代替行为行事。在这个三角形里,结构可以说是重点,表现依赖于结构,行为也依赖于结构,表现和行为的联系相对较少(除了一些特效操作),表现是被结构导入的,于是开始思考,行为是否也可以完全由外部导入,在结构即html页面里完全看不到一句javascript代码?
经过本人一番研究,至少一半左右简单应用的行为是可以分离开的。为什么说是一半呢,由于通过对对象定义的事件函数还存在参数传递的一些问题,但绕过这个障碍实施全部应用的可行性正在研究中,而且态势也在逐渐明朗,将在下文提及。所以答案是肯定的——结构(html)与行为(javascript)可以实现分离!
下面来看分离面临的核心问题,一个我的实例(为方便调试,js代码仍写在script标签里,但其他任何body里的对象都不再添加js代码):

 提示:您可以先修改部分代码再运行
函数initBehavior()的作用就是建立一个操作序列,为每个html文档结构中需要使用行为的对象进行事件触发与相应操作处理函数的连接,即生成行为。如例子中对id为holder的div元素添加的onclick事件函数,同理也可以添加onmouseover,onmouseout……等事件。于是我们分离的第一步完成了,这一步要做的就是重复initBehavior函数里面的内容,添加其他触发事件。
接下来要做的就是具体实现每个触发函数了,如上例showNode()函数,问题的核心也就在这里,因为定义的是事件处理入口,函数中没办法在定义事件的时候就确定参数,于是参数表就隐式被传递了。为什么说有参数表,这也是在查阅了网上一些资料才知道的,每个函数也是一个对象,函数对象就有一个属性是arguments:Array(),而当函数被调用时,参数都是arguments里的元素,这个大家可以另外做测试。要说的是,不同的浏览器在这里有一点小小的区别,对于IE,每当一个事件被触发时他的一个全局对象window.event就会接收到信息,在处理函数的参数表里并没有体现。而FF则不同,一个事件触发时,则与这个事件连接的处理函数会带有一个默认的事件参数,作为参数表里的第一个参数传递给处理函数,这里参数表就派上用场了,看上面的程序,由于函数没有定义形参,IE解析的参数表里面是空的,所以函数里定义的evt得到的是event的引用,FF则因为事件作为第一个参数表里的元素也得到一个事件对象。下一句也就容易理解了,对于不同浏览器,FF的事件来源属性是target,IE的是srcElement,那么到这里就通过解析得到事件来源对象,也就可以对这个对象进行相关操作了,那么本来需要从函数传递过来的对象参数也就不必要了。这里说到上面提到的一个不允许传递参数的机制,这个是在flash的ActionScript里也碰到的,仔细思考了一下,似乎明白了设置这个机制的道理,因为当一个事件触发函数时,其实需要传递的参数都是在外部暂时静态存在的,那么直接在函数里调用外部的对象或其他数据,也就完成了需求。
说是完成了,但心里总是隐隐约约觉得不妥,好象还是不完美,不过到这已经足够了,我们的目的是结构与行为的分离,那么已经实现了,收工大吉!

[ 本帖最后由 bound0 于 2006-12-11 16:04 编辑 ]
本帖最近评分记录
  • Sheneyan 威望 +2 原创内容 2006-12-9 15:07
顶一下。。。楼主分析的挺好。。。这个问题我也在想

感觉楼主的连接函数比较烦琐啊。。。如果需触发事件多的话那还不累死。。。。。。能不能这样呢??
window.onclick = initBehavior;
initBehavor(){
var evt=initBehavor.arguments[0]||window.event;
var obj = evt.srcElement || evt.target;//然后判断
switch (obj){
case : '处理1'
      //调用某函数;
   break;
.................
}
}

这里好像能够从多态性这里找到点灵感。。。我觉得可以把他写成一个处理对象。。。。。。。传过来的同一个事件不同的源对象可以有不同的处理方式。。具体的情况再想想

[ 本帖最后由 luciferzzn 于 2006-12-8 23:44 编辑 ]
终于有人顶了,呵呵,LSD想法也不错,多讨论讨论
呵呵,虽然这种形式的代码应该已经在很多网站上实质存在,但似乎没有人将它们进行比较有条理的整理。谢谢楼主的归纳。
子叶:子乌的叶子
帅哥们,美女们,新的一年终于来了,祝贺你们...终于又老了一岁~

TOP

还在为头像烦恼?还在为不能关注好友动态烦忧?快来蓝色理想家园吧!
呵呵,谢谢版主支持

TOP

结构与行为的分离的文章很少看到,支持一下

TOP

很好,结构[XHTML]+表现[CSS]+行为逻辑[JS]的分离其实正是W3C所倡导的
我认为W3C一开始推XMTHML其主要目的就是结构化你的HTML文档,结构化做好了,利用DOM+JS对页面逻辑的分离就非常容易了
我要这天,再遮不住我眼,要这地,再埋不了我心,要这众生,都明白我意,要那诸佛,都烟消云散!

TOP

复制内容到剪贴板
代码:
经过本人一番研究,至少一半左右简单应用的行为是可以分离开的。为什么说是一半呢,由于通过对对象定义的事件函数还存在参数传递的一些问题,但绕过这个障碍实施全部应用的可行性正在研究中,
8知道楼主这个话啥意思,有例子吗?
我好像还没碰到过不能分离的例子……挑战一下
我要这天,再遮不住我眼,要这地,再埋不了我心,要这众生,都明白我意,要那诸佛,都烟消云散!

TOP

回复 #8 aquarior 的帖子

楼主的意思是不得不放弃惯用的xxx("yyy")的这种传递参数的写法,想挑战的话无非就是给网页元素添一个新的属性之类的俗招儿。onMyEvent="4548,7877,4545" 这种意思吧。挑战这个好像没多大挑战性。

给楼主修正了一下示例代码中的[引号](原来用的是中文的“引号” )。
[Bound0 专题列表]QUE SAIS-JE?
生物信息技术支持动漫论坛动漫分享群:45274013

TOP

其实惯用的xxx('yyy')照样可以使用,只是得使用那个不怎么好的Function而已。。

 提示:您可以先修改部分代码再运行
子叶:子乌的叶子
帅哥们,美女们,新的一年终于来了,祝贺你们...终于又老了一岁~

TOP

依靠javascript分离结构行为迟早会败的很惨。原因:

数据一旦海量,变动输出格式史非常繁琐的,而且,你这样负荷做,数据负荷只能更高。

楼主说的,我所能理解的,就一点,这不就是事件处理么?
23555455(WEB中高程Q群) 我的播客,去代码片断平台

TOP

用prototype.js的bindAsEventListener处理方式就行

TOP

我也同意三者分离,也正在这样要求自己,可是不论是表现还是行为,都还是依赖结构的,因此一个相对好的分离策略是必要的。
无限级算法thread-2780498-1-6.html 2780498-1-1.html

TOP

呵呵,最近由于工作原因一直在研究google map api,被它的事件处理机制深深吸引

有兴趣的可以去看看,很简洁漂亮
子叶:子乌的叶子
帅哥们,美女们,新的一年终于来了,祝贺你们...终于又老了一岁~

TOP

看的我心痒痒的,也想好好学学JS了
引用:
原帖由 Sheneyan 于 2006-12-11 21:51 发表
呵呵,最近由于工作原因一直在研究google map api,被它的事件处理机制深深吸引 :D

有兴趣的可以去看看,很简洁漂亮
greengnn's space/web design
Design your life with Web Standards WEB标准群:46077068

TOP

添加一个事件的方法是不是可以这样

function Returnevent(obj,eventname){
       switch(eventname){
              case "onclick":
              return obj.onclick;
              break;
              case "onkeydown":
              return obj.onkeydown;
              break;
              case "onchange":
              return obj.onchange;
              break;
              case "onmouseover":
              return obj.onmouseover;
              break;
              }
       }
function addevent(obj,eventname,func){
       if(Returnevent(obj,eventname)==null){
         if(navigator.userAgent.indexOf("MSIE")>=0){
            var f =new Function("event",func);
            obj.attachEvent(eventname,f);
       }
       else{
        obj.setAttribute(eventname,func);
            }
        }
}
function addeventtoTagname(theTagName,eventname,func){
       var objarray=document.getElementsByTagName(theTagName);
       for(a=0;a<objarray.length;a++){
              addevent(objarray[a],eventname,func)
              }
       }

//调用:
addeventtoTagname("a","onclick","alert('test')")

[ 本帖最后由 gzlingye 于 2006-12-13 17:59 编辑 ]

TOP

js现在越来越重要了的 希望出多一些这样的简介

TOP

引用:
如果现在要让我再做一个表格布局的网页,当我看到那一堆可以被一句CSS代替的表格代码时,我甚至会恶心到想吐!
同感~

TOP

说得太绝对了吧?

TOP

典型DOM应用
http://stillfar.com

TOP

回复 #1 & #18 的帖子

引用:
原帖由 redstone 于 2006-12-29 13:19 发表

[quote]如果现在要让我再做一个表格布局的网页,当我看到那一堆可以被一句CSS代替的表格代码时,我甚至会恶心到想吐!
同感~ [/quote]


你们的思想太过片面了,不知道你们用不用Photoshop或Firework之类的工具切图来做网页?这些工具默认都会用table去包装那些被切割后的一块块的小图片,那么复杂的排版用table就能轻松搞定,你们试试把它转换成DIV+CSS,看看你们会有多累,那些代码有多恶心吧!

TOP

.....看技术要全面不要以偏概全。
http://www.qlili.com 个人站帮点啊

TOP

我贴段不完整的
复制内容到剪贴板
代码:
/**
*给指定元素增加监听,触发时执行一定的操作
*示例:
*var callBack=function(e,obj){alert(obj.id);};
*BX.Event.addListener('sample','click',callBack);
*这么在sample元素点击的时候将弹出它的id也就是sample
*@param {String||Array||Object} el 代操作对象的id,对象本身,id数组,对象数组;
*@param {String} eventName 事件名称,比如click,load,mouseover,mouseout等
*@param {Function} func(_ev,_scope) 事件触发的方法,其中e为出发的事件对象,_scope为响应该对象的元素对象如div,window等
*/
    addListener:function(objs,eventName,func,range){
        var _run=function(el){
            var _scope=el;
            var _fn=function(e){
                var _ev=e||window.event;
                //传递相应事件的元素对象
                if(range){
                    func.apply(range,[_ev,_scope])
                }
                else
                {
                    func(_ev,_scope);
                }
            };
            if (!P.Event._cache[el])
            {
                P.Event._cache[el]=[];
            }
            /*防止重复绑定同样的事件*/
            if (P.Event._cache[el][func])
            {
                //return false;
            }
            P.Event._cache[el][func]=_fn;
            if(el.attachEvent){
                el.attachEvent('on'+eventName,_fn);
            }else if(el.addEventListener){
                el.addEventListener(eventName,_fn,false);
            }
            else
            {
                el['on'+eventName] = _fn;
            }
        };
        this._batch(objs,_run);
    },
    removeListener:function(objs,eventName,func)
    {
        var _run=function(el)
        {
            if(el.detachEvent)
            {
                el.detachEvent('on'+eventName,P.Event._cache[el][func]);
            }
            else if(el.removeEventListener)
            {
                el.removeEventListener(eventName,P.Event._cache[el][func],false);
            }
            else
            {
                el['on'+eventName] = null;
            }
            P.Event._cache[el][func]=null;
        }
        this._batch(objs,_run);
    }
}

TOP

任何事物有利就一定有避,使用哪种技术其实也是一种衡量·
无谓好坏,在已有的资源下选择利大于避的才是王道~~~~
www.5study.net www.websdeveloper.cn

TOP

当你的页面元素过多,数量过大的时候,这么绑定,是一件极其痛苦的事情

TOP

楼主想法是好的,实现表现与行为的分离,但实际应用中好像做到完全的分离还是有些复杂的,也许是我学艺不精吧,哈哈
我对楼主说的那种传参还是不是很明白
document.getElementById("holder").onclick=showNode;
而showNode里如果需要传N多参数的话,是如何通知showNode的呢?!

TOP

回复 #21 MingmingdotNet 的帖子

呵呵,这个是要纠正下的。
24楼说的很有道理:
任何技术其,无谓好坏,在已有的资源下选择利大于避的才是正确的
xhz一路狂奔
http://7ibu.com
http://xhz.home.sunbo.net
启步网欢迎你

TOP

学习ING............................
www.9ihaody.cn

TOP