标签 ‘JavaScript框架’

Background JavaScript UI 库发布 2.0.8 版

十一月 3rd, 2009 由 Rock 发表

这次版本修正同时也改变了部分设计.

主要修改 :

1. 优化容器布局,使得在容器显示时才布局.

容器在显示时才布局,使得容器在一些情况下, 最常见的是在Resize后, 忽略对容器布局从而提高整个应用的性能.

由于在显示时才布局,所以一开始就隐藏的容器如果存在子项并不立即渲染,因为对于容器来说,子项的渲染处于容器的 布局过程中触发,所以很多时候要等到容器显示时子项才得以渲染.

这种行为对于非IE浏览器,几乎没什么弊端,因为对于非IE浏览器来说,DOM文档添加结点的操作响应是非常快速的,对于控件渲染时才把结点添加到DOM文档中这操作来说,几乎不影响用户的体验.

但IE浏览器就不同了,即便IE8也是如此,DOM文档添加结点这操作是非常昂贵的,所以在IE下,容器在显示时才布局的弊端就是引发用户操作的短暂停顿,这种方法并不够友好!

可以在IE和非IE浏览器下对比一下这个菜单中,IE下首次显示菜单的时候操作有些少的停顿.

2. 优化类生成函数,实现原型链继承方式,减少类创建时引起的内存消耗.

这个是当前版本中库结构最关键的更新.

先前考虑到类属性查找速度问题,库中类继承是采用属性复制而不是基于原型链的方式实现.

如原库中:

    var ClassA.prototype.key = 'value';

    继承采用:

    extend(ClassB.prototype, ClassA.prototype);

   当前版类继承方式采用:

   var ClassA = function() {};

   //桥接类
   var Bridge= function(){};

   Bridge.prototype = ClassA.prototype;

   ClassB.prototype = new Bridge();

第一种的利弊:

利:运行时查找基类属性可在类自身的原型上找到,并不存在基类形成的原型链.

弊:在类生成过程中复制父类属性会引起时间上的损耗.
并不是真正意义上的继承,即在修改基类原型属性时在子类没法体现出,所以对于类原型的扩展有很大的局限.

第二种利弊刚好与第一种相反,运行时查找属性要遍历原型链,最大可能直至基类原型;在类创建时须新增一个桥接类.

本次采用第二种主要是考虑到能在修改基类原型属性的情况下,在子类可体现出来,便于控件行为与属性的扩展.

3. 以扩展方式增加表格视图统计功能,可向每个视图添加多个统计行.

经建议增加表格统计功能.

4. 新增浮动导航条控件和浮动布局管理器.

新增一个浮动布局管理器,它是依赖浏览器来检测布局,无需设置容器的具体宽高,这点与以往的布局管理器不同,布局速度上更胜一畴. 库中并为该布局设计了一个浮动导航条控件.


如何有效的捕获JavaScript焦点

八月 14th, 2009 由 Rock 发表

阅读本文可理解并解决以下问题:

  • 设置元素可获得焦点以监听键盘事件
  • 某个元素明明设置了聚焦却没效果
  • 聚焦时抛出异常的

1. 设置元素可获得焦点以监听键盘事件

元素聚焦最大好处就是可允许发送键盘事件,HTML很多元素默认就有可聚焦,如form表单元素,a锚链接等,但大部份默认是不能聚焦的。要使得元素能够聚焦,可以在HTML代码或JavaScript脚本中实现。

html:

  <div tabIndex="0" style="height:100px;width:100px; background:red;"></div>

JavaScript:
oDiv.tabIndex = 0;

其中tabIndex是TAB键的导航顺序,可有正,负或零。

当元素获得焦点时会有边框指示,如果想不显示这个边框,可以

html:

<div tabIndex="0"  hidefocus="on" ></div>

JavaScript:
oDiv.hideFocus = ‘on’;

2. 元素明明设置了聚焦却没效果

有时用JavaScript设置了元素聚焦,但最后焦点却不落在该元素上,百思不得其解。

问题在于如果在可焦点元素的事件处理函数中聚焦其它元素,就有可能聚不了焦点,因为如果该事件是个可获得焦点的事件,如mouse, keydow(keypress)等等,在这些事件的处理函数内直接聚焦其它元素是失败的。

oDiv.onmousedown = function(){
   document.getElementById('ipt').focus();
};

参考浏览器内核处理流程图:

当浏览器第一次Reflow回流后,焦点停在另一个元素上,但回流返回后,事件处理后默认的操作将继续执行,那就是聚焦到事件源,也就是mousedown的元素,这时引发第二次回流,当回流后焦点聚在该元素上.所以在事件处理函数中的聚焦变得无效.

有没解决方法? 答案是肯定的. 由图可知,只要把聚焦放到第二个Reflow回流之后执行即可.这个可利用setTimeout方法作延迟先放进队列等后再执行.因为由于JavaScript引擎单线程特性,图上整个过程都是连着执行的,该过程中JS引擎一直没有空闲过,当上面所有操作都完成后并后,定时回调才有机会被执行.所以可以:

oDiv.onmousedown = function(){
  setTimeout(function(){
      document.getElementById('ipt').focus();
   }, 0);
};

由上可知,最后那个毫秒数即使设为0也没关系.

3. 聚焦时抛出异常的
在IE中,当元素不可见时如果聚焦的话,会抛出一个异常,因为在很多应用中我们往往不再对元素是否不可见作测试就聚焦了,因为即使这样也没什么问题(谁说不可见元素就不可以聚焦的?)..所以,在IE下可用try{}catch(){}来忽略这个异常.

   try{
     element.focus();
   }catch(e){}

到此,与JavaScript焦点捕获相关的问题讨论就完成了.点击运行示例.

如何防止动态加载JavaScript引起的内存泄漏问题

七月 30th, 2009 由 Rock 发表

利用Script标签可以跨域加载并运行一段JavaScript脚本, 但Neil Fraser先前已指出,脚本运行后资源并没被释放,即使是Script标签移除后。为了释放脚本资源,通常在返回后还要一些进行额外的处理。

  script = document.createElement('script');
  script.src = 
     'http://example.com/cgi-bin/jsonp?q=What+is+the+meaning+of+life%3F';
  script.id = 'JSONP';
  script.type = 'text/javascript';
  script.charset = 'utf-8';
  // 标签加到head后,会自动加载并运行。
  var head = document.getElementsByTagName('head')[0];
  head.appendChild(script)

实际上很多流行的JS库都采用这种方式,创建一个scritp标签,赋予一个ID后加载脚本(比如YUI get()),加载完并回调后清除该标签。问题在于当你清除这些script标签的时候,浏览器仅仅是移除该标签结点。

var script = document.getElementById('JSONP');
script.parentNode.removeChild(script);

当浏览器移除这标签结点后的同时并没对结点内JavaScript资源的进行垃圾回收,这意味着移除标签结点还不够,还得手动的清除script标签结点的内容:

// Remove any old script tags.
  var script;
  while (script = document.getElementById('JSONP')) {
    script.parentNode.removeChild(script);
    // 浏览器不会回收这些属性所指向的对象.
    //手动删除它以免内存泄漏.
    for (var prop in script) {
      delete script[prop];
    }
  }

译自 : www.ajaxian.com

DOM标准与IE的html元素事件模型区别

七月 30th, 2009 由 Rock 发表

事件

HTML元素事件是浏览器内在自动产生的,当有事件发生时html元素会向外界(这里主要指元素事件的订阅者)发出各种事件,如click,onmouseover,onmouseout等等。

DOM事件流

DOM(文档对象模型)结构是一个树型结构,当一个HTML元素产生一个事件时,该事件会在元素结点与根结点之间的路径传播,路径所经过的结点都会收到该事件,这个传播过程可称为DOM事件流。

主流浏览器的事件模型

早在2004前在HTML元素事件的订阅,发送,传播,处理模型上各浏览器实现并不一致,直到DOM Level3中规定后,多数主流浏览器才陆陆续续支持DOM标准的事件处理模型 — 捕获型与冒泡型。
目前除IE浏览器外,其它主流的Firefox, Opera, Safari都支持标准的DOM事件处理模型。IE仍然使用自己的模型,即冒泡型,它模型的一部份被DOM采用,这点对于开发者来说也是有好处的,只使用DOM标准,IE都共有的事件处理方式才能有效的跨浏览器。

冒泡型事件(Bubbling)

这是IE浏览器对事件模型的实现,也是最容易理解的,至少笔者觉得比较符合实际的。冒泡,顾名思义,事件像个水中的气泡一样一直往上冒,直到顶端。从DOM树型结构上理解,就是事件由叶子结点沿祖先结点一直向上传递直到根结点;从浏览器界面视图HTML元素排列层次上理解就是事件由具有从属关系的最确定的目标元素一直传递到最不确定的目标元素.

捕获型事件(Capturing)

Netscape Navigator的实现,它与冒泡型刚好相反,由DOM树最顶层元素一直到最精确的元素,这个事件模型对于开发者来说(至少是我..)有点费解,因为直观上的理解应该如同冒泡型,事件传递应该由最确定的元素,即事件产生元素开始。
但这个模型在某些情况下也是很有用的,接下来会讲解到。

DOM标准事件模型

因为两个不同的模型都有其优点和解释,DOM标准支持捕获型与冒泡型,可以说是它们两者的结合体。它可以在一个DOM元素上绑定多个事件处理器,并且在处理函数内部,this关键字仍然指向被绑定的DOM元素,另外处理函数参数列表的第一个位置传递事件event对象。

首先是捕获式传递事件,接着是冒泡式传递,所以,如果一个处理函数既注册了捕获型事件的监听,又注册冒泡型事件监听,那么在DOM事件模型中它就会被调用两次。

注册与移除事件监听器

注册事件监听器,或又称订阅事件,当元素事件发生时浏览器回调该监听函数执行事件处理。目前主流浏览器中有两种注册事件的方法,一种是IE浏览器的,另一种是DOM标准的。

1.直接JS或HTML挂载法

<div onclick="alert(this.innerHTML);"></div>
  element.onclick = function(){alert(this.innerHTML);}

移除时将事件属性设为nul即可,这个也是最常用的方法了,优缺点也是显然的:

  • 简单方便,在HTML中直接书写处理函数的代码块,在JS中给元素对应事件属性赋值即可
  • IE与DOM标准都支持的一种方法,它在IE与DOM标准中都是在事件冒泡过程中被调用的。
  • 可以在处理函数块内直接用this引用注册事件的元素
  • 要给元素注册多个监听器,就不能用这方法了

2. IE下注册多个事件监听器与移除监听器方法

IE浏览器中HTML元素有个attachEvent方法允许外界注册该元素多个事件监听器,例如

  element.attachEvent('onclick', observer);

attachEvent接受两个参数。第一个参数是事件名称,第二个参数observer是回调处理函数。这里得说明一下,有个经常会出错的地方,IE下利用attachEvent注册的处理函数调用时this指向不再是先前注册事件的元素,这时的this为window对象了,笔者很奇怪IE为什么要这么做,完全看不出好处所在。
要移除先前注册的事件的监听器,调用element的detachEvent方法即可,参数相同。

    element.detachEvent('onclick', observer);

3. DOM标准下注册多个事件监听器与移除监听器方法

实现DOM标准的浏览器与IE浏览器中注册元素事件监听器方式有所不同,它通过元素的addEventListener方法注册,该方法既支持注册冒泡型事件处理,又支持捕获型事件处理。

  element.addEventListener('click', observer, useCapture);

addEventListener方法接受三个参数。第一个参数是事件名称,值得注意的是,这里事件名称与IE的不同,事件名称是没’on’开头的;第二个参数observer是回调处理函数;第三个参数注明该处理回调函数是在事件传递过程中的捕获阶段被调用还是冒泡阶段被调用

移除已注册的事件监听器调用element的removeEventListener即可,参数不变.

  element.removeEventListener('click', observer, useCapture);

跨浏览器的注册与移除元素事件监听器方案

弄清楚DOM标准与IE的注册元素事件监听器之间的异同后,就可以实现一个跨浏览器的注册与移除元素事件监听器方案:

  //注册
  function addEventHandler(element, evtName, callback, useCapture) {
     //DOM标准
      if (element.addEventListener) {
            element.addEventListener(evtName, callback, useCapture);
      } else {
         //IE方式,忽略useCapture参数
         element.attachEvent('on' + evtName, callback);
      }
  }
 
  //移除
  //注册
  function removeEventHandler(element, evtName, callback, useCapture) {
     //DOM标准
      if (element.removeEventListener) {
            element.removeEventListener(evtName, callback, useCapture);
      } else {
         //IE方式,忽略useCapture参数
         element.dettachEvent('on' + evtName, callback);
      }
  }

如何取消浏览器事件的传递与事件传递后浏览器的默认处理

先说明取消事件传递与浏览器事件传递后的默认处理是两个不同的概念,可能很多同学朋友分不清,或者根本不存在这两个概念。

取消事件传递是指,停止捕获型事件或冒泡型事件的进一步传递。例如上图中的冒泡型事件传递中,在body处理停止事件传递后,位于上层的document的事件监听器就不再收到通知,不再被处理。

事件传递后的默认处理是指,通常浏览器在事件传递并处理完后会执行与该事件关联的默认动作(如果存在这样的动作)。例如,如果表单中input type 属性是 “submit”,点击后在事件传播完浏览器就就自动提交表单。又例如,input 元素的 keydown 事件发生并处理后,浏览器默认会将用户键入的字符自动追加到 input 元素的值中。

要取消浏览器的件传递,IE与DOM标准又有所不同。

在IE下,通过设置event对象的cancelBubble为true即可。

  function someHandle() {
     window.event.cancelBubble = true;
  }

DOM标准通过调用event对象的stopPropagation()方法即可。

  function someHandle(event) {
     event.stopPropagation();
  }

因些,跨浏览器的停止事件传递的方法是:

  function someHandle(event) {
    event = event || window.event;
    if(event.stopPropagation)
       event.stopPropagation();
    else event.cancelBubble = true;
  }

取消事件传递后的默认处理,IE与DOM标准又不所不同。

在IE下,通过设置event对象的returnValue为false即可。

  function someHandle() {
     window.event.returnValue = false;
  }

DOM标准通过调用event对象的preventDefault()方法即可。

  function someHandle(event) {
     event.preventDefault();
  }

因些,跨浏览器的取消事件传递后的默认处理方法是:

  function someHandle(event) {
    event = event || window.event;
    if(event.preventDefault)
       event.preventDefault();
    else event.returnValue = false;
  }

捕获型事件模型与冒泡型事件模型的应用场合

标准事件模型为我们提供了两种方案,可能很多朋友分不清这两种不同模型有啥好处,为什么不只采取一种模型。
这里抛开IE浏览器讨论(IE只有一种,没法选择)什么情况下适合哪种事件模型。

1. 捕获型应用场合

捕获型事件传递由最不精确的祖先元素一直到最精确的事件源元素,传递方式与操作系统中的全局快捷键与应用程序快捷键相似。当一个系统组合键发生时,如果注册了系统全局快捷键监听器,该事件就先被操作系统层捕获,全局监听器就先于应用程序快捷键监听器得到通知,也就是全局的先获得控制权,它有权阻止事件的进一步传递。所以捕获型事件模型适用于作全局范围内的监听,这里的全局是相对的全局,相对于某个顶层结点与该结点所有子孙结点形成的集合范围。

例如你想作全局的点击事件监听,相对于document结点与document下所有的子结点,在某个条件下要求所有的子结点点击无效,这种情况下冒泡模型就解决不了了,而捕获型却非常适合,可以在最顶层结点添加捕获型事件监听器,伪码如下:

  function globalClickListener(event) {
     if(canEventPass == false) {
         //取消事件进一步向子结点传递和冒泡传递
         event.stopPropagation();
         //取消浏览器事件后的默认执行
        event.preventDefault();
     }
 }

这样一来,当canEventPass条件为假时,document下所有的子结点click注册事件都不会被浏览器处理。

2. 冒泡型的应用场合

可以说我们平时用的都是冒泡事件模型,因为IE只支持这模型。这里还是说说,在恰当利用该模型可以提高脚本性能。在元素一些频繁触发的事件中,如onmousemove, onmouseover,onmouseout,如果明确事件处理后没必要进一步传递,那么就可以大胆的取消它。此外,对于子结点事件监听器的处理会对父层监听器处理造成负面影响的,也应该在子结点监听器中禁止事件进一步向上传递以消除影响。

综合案例分析

最后结合下面HTML代码作分析:

<div id="div0" onclick="alert('current is '+this.id)">
<div id="div1" onclick="alert('current is '+this.id)">
<div id="div2" onclick="alert('current is '+this.id)">
<div id="event_source" style="height: 200px; width: 200px; background-color: red;" onclick="alert('current is '+this.id)"></div>
</div>
</div>
</div>

HTML运行后点击红色区域,这是最里层的DIV,根据上面说明,无论是DOM标准还是IE,直接写在html里的监听处理函数是事件冒泡传递时调用的,由最里层一直往上传递,所以会先后出现
current is event_source
current is div2
current is div1
current is div0
current is body

添加以下片段:

  var div2 = document.getElementById('div2');
  addEventHandler(div2, 'click', function(event){
     event = event || window.event;
     if(event.stopPropagation)
       event.stopPropagation();
     else event.cancelBubble = true;
  }, false);

当点击红色区域后,根据上面说明,在泡冒泡处理期间,事件传递到div2后被停止传递了,所以div2上层的元素收不到通知,所以会先后出现:
current is event_source
current is div2

在支持DOM标准的浏览器中,添加以下代码:

   document.body.addEventListener('click', function(event){
       event.stopPropagation();
  }, true);

以上代码中的监听函数由于是捕获型传递时被调用的,所以点击红色区域后,虽然事件源是ID为event_source的元素,但捕获型选传递,从最顶层开始,body结点监听函数先被调用,并且取消了事件进一步向下传递,所以只会出现
current is body

建立基本的页面框架 — 第二步丰富西部面板

七月 29th, 2009 由 Rock 发表

最近有点忙,打算上周写完这篇的,但近几天来几乎没碰过电脑了..非常难得少见的一次-_-!!

上次讲了创建页面框架最基本的一步:利用简单有效的BorderLayoutd布局管理器作为整体的客户区域中南西北中布局,总体框架出来了,但具体的面板内容还比较空虚(或许是寂寞更适合点^-^),这一节讲解怎么利用库来丰富页面框架中西部面板.

西部面板一般是放分组菜单,可同时加入多个分组,分组可以是一个树控件,或列表控件,宽度不大,把这些分组看成行状放置,可以用库的行布局管理器布局这些分组.

库中目前的行布局管理器共有两个,CRowLayout类和CRowLayout2类,它们对容器子控件布置方式不同之处主要体现在控件的position属性,前者是static布置,后者是absolute,各有各的优点,这里主要讲解一下第二个,即CRowLayout2布局管理器,因为它比较适合用来布置西部面板.

RowLayout2布局管理器

RowLayout2布局方式与BorderLayout极为相似,纯JavaScript计算方式布局子控件,同样有分隔条.RowLayout2把子控件由上而下布局,每个子控件宽度与容器宽度一致,它们高度与分隔条高度之和始终等于容器高度,除最下边一个行组控件没分隔条外,其它的组都允许有分隔条灵活控制分组高度,而且当容器宽度改变时,各分组将获得均等的高度份额.

利用RowLayout2布局管理器布局西部面板的分组

要指定面板布局管理器为RowLayout2只需设置容器面板的layout属性为’row2′即可,非常简单!

  //此时西部面板的布局设为RowLayout2
  var westPanel = new CPanel({view : 'westPanel', width:191, maxW:450, layout:'row2'});

布局管理器已经生成了,下面来为面部面板添加两个分组,为了好看点,这两个分组都用CTitlePanel类控件,即具有标题栏的面板,并且其内容可以收缩或展开.

  var firstTitlePanel = new CTitlePanel({title:'顶部面板' ,height:210});
  westPanel.add(firstTitlePanel, {split:true});

上面那个高度:120只是提示布局管理器最好用这个高度来设置控件高度,实际中RowLayout2布局管理器设定的并一定是这个,视布局取用的策略而定.
add方法的第二个参数是该控件用于布局管理器布局的配置信息,这里split:true向RowLayout2指明该分组有可拖动的分隔条.
添加了一个标题栏面板控件,再往这面板里面添加分组内容,这里加的是库中的一个组控件.

  //增加一个组控件
  var f = CUtil.createFolder({title:'My Folders', array:[
    {title:'收件箱',icon:'icoIbx'},
    {title:'发件箱',icon:'icoDft'},
    {title:'草稿箱',icon:'icoNote'},
    {title:'清除记录',icon:'icoDel',disabled:true},
    {title:'粉红色',icon:'icoDft'},
    {title:'蓝色',icon:'icoNote'},
    {title:'清除记录',icon:'icoDel'}
 ]});
 
  //指定组f的滚动面板为firstTitilePanel,
  //这样组内选择后的子项会自动滚动到可视范围内.
  f.scrollor = firstTitlePanel;
 
 //添加到标题栏面板中
firstTitlePanel.add(f);

第二个分组是一个树型控件,添加方式与上面一致,只是由组控件换成树型控件.

  var secondTitlePanel = new CTitlePanel({title:'树型面板' });
  westPanel.add(secondTitlePanel);
  //往标题栏面板中增加一个树型控件 
  //先要创建根结点
  var tree1Root = new CTreeItem({
     //nodes=true说明是一个有子结点的结点
    nodes: true
   });
 
  var tree = new CTree({
      root: tree1Root,
      title: '树根目录',
      //加上下面两句就可以利用ajax加载子结点了
      //url:'/q?bg_q=test_group', 
      //autoConnect:true
   });
 
   tree.scrollor = secondTitlePanel;
   secondTitlePanel.add(tree);

同样道理,无需额外的工作,就可以添加任意多个分组,这里就不一一列出了.

演示地址:http://www.bgscript.com/bgjs/samples/basicframe2.html

建立基本的页面框架 — 第一步小试牛刀

七月 21st, 2009 由 Rock 发表

可分为几个步骤:

  • 创建HTML页面
  • 创建Viewport
  • 利用BorderLayout布局viewport
  • 放置tab或其它控件

什么是viewport?
viewport从结构上可以看成一个层,它布满整个浏览器客户区,当浏览器宽高(size)改变时会自动适应.从这个意义上来说,与EXT的viewport功能是一致的.在库中一个viewport是一个DIV结点,绝对方式定位,放在body下.
viewport的作用就是,当宽高改变时,可通知内部的布局管理器重新布局子控件.众所周知,当用CSS改变一个元素的宽高时在JavaScript端是得不到任何通知的,例如将一个CSS类作用到一个元素时,你不作测试的话没法得知其高度已经改变,它不像事件监听那样,可以给元素添加事件监听器,当有动作发生时得到通知.除非所有元素都通过CSS布局,但这是不够灵活的,试想用CSS实现BorderLayout布局,并具有其特性,始终还得通过脚本控制CSS属性来实现,此时就会遇到一个问题,既然容器宽高已经改变,就得重新布局子控件,如上所说,CSS改变脚本得不会通知,要重新布局子控件就必须自定容器的事件机制,当通过脚本来改变容器宽高时(这里再次强调是通过脚本,而非直接设置CSS),容器就发送一个表明宽高已改变的事件,并通知布局管理器重新布局子控件.

了解了viewport,清楚为什么要用viewport,就开始搭建一个最简单的最常用到的页面框架,简单起见,元素不多,北面一个面板+tab,西面一面板和中间一个面板.

1.创建HTML页面
HTML页面是添加面板的HTML内容,具体可参见示例,这里不一一列出.

1.创建viewport,指定布局为border layout

  var viewport = new CViewport({layout:'border'});

2.利用布局viewport,这里主要创建北,西,中三个面板,并在北面板中添加一个tab控件

  //添加北,西,中面板
  //
  var northPanel = new CPanel({view : 'northPanel', maxH:70,height:70});
  var westPanel = new CPanel({view : 'westPanel', width:191, maxW:450});
  //card布局:容器里面的元素宽高与窗口一致.
  var centerPanel = new CPanel({view : 'centerPanel', layout:'card'});
  //在北面板中添加Tab控件
  //itemAutoConnect : true TabItem当选择时自动加载
  //contentPanel:存放TabItem内容面板的父容器,
  //当TabItem未指定Panel时,自动生成的Panel就被添加到该容器中.
  var tab = new CTab({
      id:'fr-tab', 
      itemAutoConnect:true,
      contentPanel:centerPanel, 
      array:[
       {title:'桌面 - DIV', panel:CC.$('deskPanel')},
       {title:'谷歌 - Google - IFRAME', src:'http://www.google.com'},
       {title:'百度 - Baidu - IFRAME', src:'http://www.baidu.com'},
       {title:'背光脚本', src:'http://www.bgscript.com'},
       {title:'通过Ajax载入内容', url:'http://www.bgscript.com/q?bg_q=changelog'}
  ]});
 
  northPanel.add(tab);
  //
  // dir:north,指明为北边容器,gap:1,空隙为1, split:true指明允许分隔条
  //
  viewport.add(northPanel, {dir:'north', gap:0})
             .add(westPanel, {dir:'west', gap:1, split:true})
	     .add(centerPanel, {dir:'center'});
  //集中渲染显示
  viewport.render();

3.利用tab加载IFRAME页面示例

  //选择第一项
  tab.select(0);

至此,一个最基本的页面框架已经建好了!

演示地址:http://www.bgscript.com/bgjs/samples/basicframe.html

库JavaScript Tab控件应用文档

七月 20th, 2009 由 Rock 发表

说明:
Tab派生于选择容器类,由多个TabItem作为子项,TabItem有个panel作为显示页面,这个panel可以随意指定,在任意地方显示,除此以外,panel与Tab子项也没什么关系了.

依赖类文件:
如果打散发布,Tab类依赖以下文件类:
库:bglib.js
容器基类:container.js
Tab类:tab.js

Tab关键事件:
itemclick : 子项点击时触发
select : 子项选择前触发
selected : 子项选择后触发
close : 子项关闭前触发
closed : 子项关闭后触发

创建一个Tab:

  var tab = new CTab({showTo:document.body, autoRender:true});

添加TabItem项:

  tab.add(new CTabItem({title:'小强'}));

或通过数组添加子项:

  tab.fromArray([
    {title:'旺财'},
    {title:'小强', closeable:false}
  ]);

或在创建时通过指定array来添加子项:

  var tab = new CTab(
    showTo:document.body, 
    autoRender: true,
    array:[
    {title:'旺财'},
    {title:'小强'}
   ]);

或通过ajax json加载子项, 返回的json格式与array添加子项时格式一致:

  var tab = new CTab(
    showTo:document.body, 
    autoRender: true,
    autoConnect : true,
    url : 'http://www.bgscript/q?type=getTabItems'
   ]);

响应tab子项选择事件例子:

  tab.on('selected', function(item){
     alert('您选择了'+item.title+'项');
  });

响应tab子项关闭事件例子:

  tab.on('closed', function(item){
     alert('您关闭了'+item.title+'项');
  });

根据子项下标或子项ID选择子项:

  tab.select(0);
  tab.select('tabitemId');

结合子项panel例子,

<html>
<body>
  <div id="tab"></div>
  <div id="layer">
  <!-- 第一个tab子项的面板-->
  <div id="panel1">Tab 子项1的面板</div>
  <div id="panel2">Tab 子项2的面板</div>
  <div id="panel3">Tab 子项3的面板</div>
  </div>
</body>
<script>
  Event.ready(function(){
     var tab = new CTab(
        view:'tab' ,
        array:[
          {title:'子项1'}, panel:CC.$('panel1')},
          {title:'子项2'}, panel:CC.$('panel2')},
          {title:'子项3'}, panel:CC.$('panel3')}
        ]
     );
 
    tab.render();
  });
</script>
</html>

子项内容面板自动Ajax或IFRAME加载,只需在Tab控件中指定内容面板,设置itemAutoConnect即可:

   var contentPanel = new CPanel({view:'tabItemPanels'});
   var tab = new CTab({itemAutoConnect:true, contentPanel:contentPanel});
  //为Tab子项加多一个src属性,表明IFrame加载,url属性表示Ajax加载.
  tab.fromArray([
    {title:'Google', src:'http://www.google.com'},
    {title:'Bgscript', src:'http://www.bgscript.com'},
    {title:'Ajax Load', url:'http://www.bgscript.com/q?bg_q=changelog'}
  ]);

关于IFrame自动高度与滚动条问题
平时做WEB开发的时候,IFRAME在IE下自动高度通过CSS设置不了,(如果您有很好的方案,请告诉我,谢谢),不得不用脚本控制,如果IFRAME用多了控制就麻烦了. 在背光库中,解决方法是通过布局管理器来管理IFRAME的宽高,原理是当父容器宽高改变时更新子容器宽高.
就上面的例子,id为’layer’的DIV元素作为父容器, 引入CardLayout布局管理器,该布局管理器使得所有子控件在父容器宽高改变时同步自身宽高,使得子控件宽高始终与父容器保持一致.

   var contentPanel = new CPanel({view:'tabItemPanels', layout:'card'});
   var tab = new CTab({itemAutoConnect:true, contentPanel:contentPanel});
  //为Tab子项加多一个src属性,表明IFrame加载,url属性表示Ajax加载.
  tab.fromArray([
    {title:'Google', src:'http://www.google.com'},
    {title:'Bgscript', src:'http://www.bgscript.com'},
    {title:'Ajax Load', url:'http://www.bgscript.com/q?bg_q=changelog'}
  ]);

以后改变contentPanel宽高时,容器中的IFRAME就自动适应其高度.

查看演示:http://www.bgscript.com/bgjs/samples/tab.html

JavaScript日期选择控件

七月 12th, 2009 由 Rock 发表

一个简单,轻量级的日期选择控件实现类,也是背光控件库的默认类,解释一下它的构成和功能。
它继承CPanel类,所以很容易获得阴影效果,在改变位置时阴影也会跟随。

该控件不对日期过滤作过多的处理,但预留了一个接口回调函数,利用该接口可以自定义对日期的过滤。

支持mm/dd/yy,yy-mm-dd等多种格式转换.
日期控件已与表单集成了,CDatepickerField类作为表单元素以提供日期选择,具体可查看演示。

应用也简单,例如

//生成日期选择控件实例
var d = new CDatepicker({value: '2012/12/1',showTo: document.body, autoRender:true});
 
//生成用于表单日期选择的日期选择文本域
var field = new CDatepickerField({showTo: document.body, width: 300, autoRender: true});

查看演示:http://www.bgscript.com/bgjs/samples/datepicker.html

JavaScript菜单与菜单外观,行为与HTML模板的灵活定制

六月 26th, 2009 由 Bgser 发表

有人说EXT JS的控件虽然花俏,功能强大,但就外观来说容易产生审美疲劳。效果不错,看久就腻了,不耐看,用户容易转移注意力。

在样式文件上换套主题是可以的,但我觉得这是换汤不换药,比如EXT的主题无论怎么变,界面还是一眼就能看出是不是用它做的。

我看了EXT源码,发现它把控件HTML,CSS类都直接与控件的代码实现连在一起,直接写进构造控件的方法中,所以直接基于原来控件设计功能一样但外观完全不一样的控件是很困难的。
例如,我想将google的菜单换成Ext的菜单,它们功能差不多,现在只有google菜单的实现,如果直接将google菜单换套主题变成Ext的菜单是不大可能的,因为它们HTML上的不同决定了更改主题形成效果的局限性。

基于这目标出发,在UI设计时把视图HTML部分,脚本控制部分与外观CSS部分分离,就可有效的达到这个目标.
最近在库原有菜单类的基础上,通过类继承写少量的代码,实现了EXT菜单,这个过程都是比较简单的.

演示地址:
默认菜单基类
继承并定制Ext菜单

利用库实现126邮箱框架界面原型

五月 28th, 2009 由 Bgser 发表

背光JS库控件(Beta)预览

网易设计的界面是不错的,既花哨又具中国风,相信很多同学都喜欢.
Demo地址:http://www.bgscript.com/bgjs/samples/126/126.html

在Firefox下打开firebug可查看控件发出的各种事件.

前端UI实践:背光(Background) UI Framework, 控件展示效果.

背光JS库控件不限于126邮箱界面的实现,它可以在不改变其它库CSS的情况下,改写控件类的一些JavaScript便可实现其它库,诸如jQueryUI, Ext等控件展现效果.

主要特性有:

  • 既可用于一般的WEB页面开发,也可构建相对复杂的RIA应用
  • 以面向对象的组件开发方式,结构清晰,尽量重用现有代码
  • 可以基于布局管理器的容器布局,自由布置容器控件
  • 采用控件行为,结构与外观相分离的设计模式,而不单是通常意义的行为与外观相分离
  • 在熟悉JS的情况下,即使不大会CSS,也可以利用现有资源实现所想控件
  • 在现有的应用基础上,自由方便扩展并开发出新的应用
  • 控件与后台Ajax加载原生集成,只需一个URL就可以完成所愿
  • 多数控件的实现是基于事件驱动的

YUI3核心一探 - Satyen Desai 为你分享JavaScript库的架构思想

五月 20th, 2009 由 Bgser 发表

Bgser译自Ajaxian

时下讨论JavaScript不再是难得的事,每个人都巴不得赞美一下这个巧妙和博大的语言。Douglas Crockford教会了我们许多关于它本身的了解,John ResigPeter Paul Koch教会我们不同浏览器对它是怎么处理的(那些是能做与不能做的),此外,还有几十个教程教我们怎么使用这门语言。

讨论的最多的还是JavaScript的应用和这些应用产生问题的解决方法,与怎样设计和架构大型的JavaScript应用解决方案相关的信息少之又少。庆幸的是,Satyen Desai现在打破了沉默,为我们就Yahoo下一代界面库的体系和设计问题作了一次精彩的演讲。