封装内容和功能 – YUI TabView使用小记

简介: 本文主要内容取自 Caridy Patino 在2008年发布的文章,原文中使用的是YUI2,笔者对例子做了一些更新,均使用了YUI3.1.1,文章中讨论的这个问题,在Ajax满天飞的现在具有典型意义,所以拿出来重新重新炒了一下。
 

本文主要内容取自 Caridy Patino 在2008年发布的文章,原文中使用的是YUI2,笔者对例子做了一些更新,均使用了YUI3.1.1,文章中讨论的这个问题,在Ajax满天飞的现在具有典型意义,所以拿出来重新重新炒了一下。

通常的应用场景中,为了节省和有效利用页面空间,会使用Tab。如果我们有一个Tab,每个Tab展示后提供不同的功能,功能较少时,我会选择将处理用户事件的JS代码写在页面中。例如,在使用YUI的情况下:

构建页面DOM

构建符合要求的页面DOM(当然我们也可以使用YUI来动态的创建DOM,但这样就丧失了搜索引擎友好的特性)。

<div id="demo">
    <ul>
        <li><a href="#foo">foo</a></li>
        <li><a href="#bar">bar</a></li>
        <li><a href="#baz">baz</a></li>
    </ul>
    <div>
        <div id="foo">
            foo content
            <p><a href="javascript:void(0);" id="fooLink">Click Me</a></p>
        </div>
        <div id="bar">
            bar content
            <p><a href="javascript:void(0);" id="barLink">Click Me</a></p>
        </div>
        <div id="baz">
            baz content
            <p><a href="javascript:void(0);" id="bazLink">Click Me</a></p>
        </div>
    </div>
</div>

Javascript代码

//Create YUI Instance
YUI({base:'../lib/yui/build/',combine:true}).use('tabview', function(Y){
    var tabview = new Y.TabView({
        srcNode:"#demo"
    });

    tabview.render();

    //public message function
    function message(e){
        var node = e.currentTarget;
        alert(node.get("id") + " Clicked ");
    }

    // attach event handler
    Y.one("#fooLink").on("click", message);
    Y.one("#barLink").on("click", message);
    Y.one("#bazLink").on("click", message);
});

通过这种方式,我们创建了一个TabView,并且为Tabview中的每个连接赋予了一个处理事件(当然,例子中用了一个来代替)。在Tab内容中元素和事件较少时没什么问题,但是当内容增多,并且都是通过Ajax动态加载的时候,问题就出现了。

The Problem

But this approach can introduce certain dependencies and complexity within our code, because the actions for a certain tab’s content will be defined at the page level, which means that if you want change the content of tab, you probably need to change something at the application level as well — the functionality of the tab’s content is not encapsulated with that content.

由于这种方法将tab内容变化的响应事件定义在了页面级别,因此增加了程序的依赖和复杂性。如果想要更改tab的内容的话,就不得不修改程序的很多东西——也就是说tab的内容和他的功能性没有能很好的封装到一起。

使用Ajax来动态加载内容可以通过YUI的插件机制来实现, 这个时候,如果想在返回内容后触发一些操作,或者为返回内容中的一些元素绑定一些事件。直接再返回的结果中嵌入<script>代码是不行的,因为浏览器默认解析执行这些内容,这也是为了安全性的考虑(想想跨站攻击)。

经过笔者的实验,发现YUI3.1.1中这个问题已经不存在了,在返回内容中包含的脚本也能够正常的执行,这是一个非常棒的特性,这意味着我们可以将内容和逻辑处理封装在一起,从而让我们的代码结构更加清晰。下面是试验过的代码,大部分是YUI Tabview上的源码。

<script type="text/javascript">
    //Create YUI Instance
    YUI({base:'../lib/yui/build/',combine:true}).use('yui', 'tabview', 'gallery-widget-io', function(Y){
        var feeds = {
                Chrome: './server.php?query=chrome',
                Firefox: './server.php?query=firefox',
                Safari: './server.php?query=safari',
                Explorer: './server.php?query=explorer'
            },

        TabIO = function(config) {
            TabIO.superclass.constructor.apply(this, arguments);
        };

        Y.extend(TabIO, Y.Plugin.WidgetIO, {
            initializer: function() {
                var tab = this.get('host');
                tab.on('selectedChange', this.afterSelectedChange);
                tab.on('contentUpdate', this.contentUpdate);
                tab.get('panelNode').on('contentUpdate', this.contentUpdate);
            },
            contentUpdate:function(e){
                alert("test");
            },
            afterSelectedChange: function(e) { // this === tab
                if (e.newVal) { // tab has been selected
                    this.io.refresh();
                }
            },

            setContent: function(content) {
                var tab = this.get('host');
                tab.set('content', content);
            },

            _toggleLoadingClass: function(add) {
                this.get('host').get('panelNode')
                    .toggleClass(this.get('host').getClassName('loading'), add);
            }

        }, {
            NAME: 'tabIO',
            NS: 'io'
        });

        var tabview = new Y.TabView({
            srcNode:"#demo"
        });
        Y.each(feeds, function(src, label) {
            tabview.add({
                label: label,
                plugins: [{
                    fn: TabIO,
                    cfg: {
                        uri: src
                    }
                }]
            });
        });

        tabview.render();

        //public message function
        function message(e){
            var node = e.currentTarget;
            alert(node.get("id") + " Clicked ");
        }

        // attach event handler
        Y.one("#fooLink").on("click", message);
        Y.one("#barLink").on("click", message);
        Y.one("#bazLink").on("click", message);
    });
</script>

 

更好的是,如果返回结果中包含了对外部脚本的引用,引用的脚本同样也会执行,下面是服务端的代码。

<?php

$html = '';
if( isset($_GET['query']) ){
    switch($_GET['query']){
        case "chrome":
            $html .= "<a href='http://www.baidu.com'>Chrome</a><br />";
            $html .= "<a href='http://www.baidu.com'>Chrome</a><br />";
            $html .= "<a href='http://www.baidu.com'>Chrome</a><br />";
            $html .= time();
            break;   
        case "firefox":
            $html .= "<a href='http://www.baidu.com'>Firefox</a><br />";
            $html .= "<a href='http://www.baidu.com'>Firefox</a><br />";
            $html .= "<a href='http://www.baidu.com'>Firefox</a><br />";
            $html .= time();
            break;   
        case "safari":
            $html .= "<a href='http://www.baidu.com'>Safari</a><br />";
            $html .= "<a href='http://www.baidu.com'>Safari</a><br />";
            $html .= "<a href='http://www.baidu.com'>Safari</a><br />";
            $html .= time();
            break;   
        case "explorer":
            $html .= "<a href='http://www.baidu.com'>Explorer</a><br />";
            $html .= "<a href='http://www.baidu.com'>Explorer</a><br />";
            $html .= "<a href='http://www.baidu.com'>Explorer</a><br />";
            $html .= time();
            break;   
    }
    $html .= "<p><a href='javascript:void(0);' id='delegateId'>Delegate Event</a></p>";
    $html .= "<script type='text/javascript'>alert('test');</script>";
    $html .= "<script type='text/javascript' src='../server/external.js'></script>";
    echo $html;
}

 

目前Tab中处理返回内容的情况比两年的Caridy遇到的时候,处理要简单的很多,但是还有很多情况我们不能使用Tab的,YUI 3.1中,单独的使用 node.set(‘content’)并不会将内容中的脚本进行解析,这时,有两个可以使用的非常有用的工具,分别是”Dispatcher”和node.delegate。

前者是 Bubbling Library 中的一员,而后者是YUI提供的一个非常有用的工具。

今天先写到这里,后面会继续探讨再不是Tab的情况下,如果解析执行返回内容中的脚本。

参考资料:

1、Useing the TabView Control with My Dispatcher Plugin

2、YUI Tabview

3、Progressive Enhancemeng

4、YUI Plugin

相关文章
|
监控 物联网 编解码
流媒体方案之FFmpeg——实现物联网视频监控项目
流媒体方案之FFmpeg——实现物联网视频监控项目
流媒体方案之FFmpeg——实现物联网视频监控项目
|
Dubbo Java 应用服务中间件
项目中引进这玩意,排查日志又快又准
随着微服务盛行,很多公司都把系统按照业务边界拆成了很多微服务,在排错查日志的时候,因为业务链路贯穿着很多微服务节点,导致定位某个请求的日志以及上下游业务的日志会变得有些困难。
|
设计模式 负载均衡 网络协议
【分布式技术专题】「分布式技术架构」实践见真知,手把手教你如何实现一个属于自己的RPC框架(架构技术引导篇)
【分布式技术专题】「分布式技术架构」实践见真知,手把手教你如何实现一个属于自己的RPC框架(架构技术引导篇)
646 0
|
Web App开发 JavaScript 数据可视化
ElasticSearch安装
ElasticSearch安装
197 1
ModuleNotFoundError: No module named ‘openai.error‘
这篇文章讨论了在使用OpenAI库时遇到的`ModuleNotFoundError: No module named ‘openai.error'`错误,并提供了两种解决方案:将OpenAI版本降级到0.28.0或修改代码以去掉对`openai.error`的引用并将异常处理放置到`openai`模块下。
ModuleNotFoundError: No module named ‘openai.error‘
|
9月前
|
搜索推荐 物联网 PyTorch
Qwen2.5-7B-Instruct Lora 微调
本教程介绍如何基于Transformers和PEFT框架对Qwen2.5-7B-Instruct模型进行LoRA微调。
10113 34
Qwen2.5-7B-Instruct Lora 微调
|
11月前
|
数据可视化 IDE 开发工具
【Python篇】PyQt5 超详细教程——由入门到精通(中篇二)
【Python篇】PyQt5 超详细教程——由入门到精通(中篇二)
785 13
|
搜索推荐 数据挖掘 数据管理
ClkLog埋点分析系统-支持自定义事件分析
6 月,<自定义分析>千呼万唤始出来,同时我们还增加了<书签管理>、<权限管理>模块
ClkLog埋点分析系统-支持自定义事件分析
|
监控 安全
zabbix测试发邮件报错–连接到Zabbix主机 “localhost“ 失败
zabbix测试发邮件报错–连接到Zabbix主机 “localhost“ 失败
380 0
|
前端开发 Java 数据库连接
【1024程序员节】RestFul,mvc拦截器,SSM基本整合-学习笔记
【1024程序员节】RestFul,mvc拦截器,SSM基本整合-学习笔记
149 1