CSS样式在JS中的巧用

上一篇里使用css样式虚类nonie(实际属性是定义给了yui3-panel-hidden而不是nonie)解决了在不同浏览器下的样式兼容问题

其实,css虚类(未在CSS文件中定义具体属性)还有很多巧用,在大量使用JS脚本和AJAX的系统中,巧用css虚类,可以实现很多功能

下面以我实际的开发例子介绍

第一:使用代理时,可以通过css虚类作为类选择器

例如,我在YUI的表格里,每一行上都有一列操作列,里面都是以<a>标签形式显示操作,此列都是通过模板动态生成的,所以这些<a>标签没有id,而指定这些<a>标签的响应方法,必须通过代理方式,而对应的<a>标签则通过一个虚类来指定。其实可以在生成标签时指定onclick事件,但是显然没有代理来的好,代理不用给每个标签写click方法。

下面是某table(yui3的DataTable widget)的操作列的定义:

                                {
                                    key: 'id',
                                    label: '<center>操作</center>',
                                    sortable: false,
                                    width: '180px',
                                    allowHTML: true,
                                    formatter: function(o) {
                                        return '<center><a class="update" href="#"><img src="../image/modify.gif">修改信息</a><a class="delete" href="#"><img src="../image/delete.gif">删除</a></center>';
                                    }
                                }

 而该table可以定义代理并可以使用<a>上的虚类类型来指定响应对象

                    table.delegate('click', showUpdatePanel, '.yui3-datatable-data tr .update', table);
                    table.delegate('click', deleteData, '.yui3-datatable-data tr .delete, table);

 第二,可以使用虚类定义隐藏的信息

我在某项目里,需要在鼠标移动到表格里时浮动显示tooltip并根据用户当前选择动态显示不同的信息,这些信息包括:用户填写的备注,领导的批复,历史修改记录,逻辑验证错误提示等,有的是数据载入时一次性载入的(当然也可以选择根据需要通过ajax加载),有的是根据用户填写动态生成的。对此,我的处理办法是,把这些信息各自塞到一个指定了hidden样式的span标签里,然后把span都隐藏到相关的td里,这样,在鼠标移动时,就通过查找对应的span标签里的信息,然后将这些信息拷贝到tooltip里,而判断当前显示哪样信息,就是通过span标签额外的虚类样式了

鼠标移动的代码是这样的:

  

        warningMouseMove: function(e) {
            if (e.currentTarget.hasClass('warning') || e.currentTarget.hasClass('viewnote') || e.currentTarget.hasClass('viewaudit') || e.currentTarget.hasClass('viewmodify') || e.currentTarget.hasClass('viewhelp')) {
                if (e.currentTarget.hasClass('warning')) {
                    var m = '';
                    e.currentTarget.all('.warningmessage').each(function(k, v) {
                        if (m != '') {
                            m += '<br>---------<br>';
                        }
                        m += k.get('text').replace(/\n/g, "<br>");
                    });
                    tooltip.setStdModContent('body', m);
                }
                else if (e.currentTarget.hasClass('viewnote')) {
                    tooltip.setStdModContent('body', e.currentTarget.one('.notecontent').get('text').replace(/\n/g, "<br>"));
                }
                else if (e.currentTarget.hasClass('viewmodify')) {
                    tooltip.setStdModContent('body', e.currentTarget.one('.modifycontent').get('text').replace(/\n/g, "<br>"));
                }
                else if (e.currentTarget.hasClass('viewhelp')) {
                    tooltip.setStdModContent('body', e.currentTarget.one('.helpcontent').get('text').replace(/\n/g, "<br>"));
                }
                else if (e.currentTarget.hasClass('viewaudit')) {
                    var c = '';
                    if (e.currentTarget.one('.auditcontent') != null) {
                        c = e.currentTarget.one('.auditcontent').get('text');
                    }
                    if (e.currentTarget.one('.addauditcontent') != null) {
                        if (c != '') {
                            c += '<br>';
                        }
                        c += e.currentTarget.one('.addauditcontent').get('text').replace(/\n/g, "<br>");
                    }

                    tooltip.setStdModContent('body', c);
                }
                var posx = e.pageX > screen.width * 0.8 ? e.pageX - 200 : e.pageX + 10;
                tooltip.move([posx, (e.pageY + 20)]);
                if (tooltip.get('visible') === false) {
                    Y.one('#tooltip').setStyle('opacity', '0');
                }
                if (waitingToShow === false) {
                    setTimeout(function() {
                        Y.one('#tooltip').setStyle('opacity', '1');
                        tooltip.show();
                    }, 500);
                    waitingToShow = true;
                }
            }
            else if (waitingToShow == true) {
                tooltip.hide();
                waitingToShow = false;
            }
        },

 解释下:这个方法运行的对象是一个<table>表格里的td,如果是正常状态,则用户输入后会进行校验,有错误的情况下会产生warning样式,并动态生成错误信息,而错误信息涉及的对象并不一定只是输入数据的td。在用户点击了查看备注时,则会移除其它样式,为相关td添加viewnotes样式,点击查看批示,则会添加viewaudit样式等。而用户鼠标移动到格子上,则会根据当前样式判定获取哪个样式span里的信息并显示

 第三,这是我编写的统计网站里的一个校验功能,报表有很多项输入,这里面有很多限制,包括:

1、允许空或非空

2、只允许整数

3、必须是数字(可以是浮点数)

4、必须大于0

5、有的项和同期相比不能超过20%(超过的必须填写备注)

6、众多勾稽关系比较,例如a必须大于b,c必须等于d+e等等

用户输入时应当即时提示,并且,用户输入完毕后必须进行全部校验通过方可提交

最初的一个版本,是将逻辑校验写在配置文件里,然后通过读取配置文件的数学公式进行运算

后来推翻重写时,放弃了此项,直接将逻辑编写在代码里,原因么,主要是维护那个配置文件太复杂,每次报表改动要折腾死人,而且里面的项和数据库字段以及表格表格上的代码不匹配

于是解决方法是:非空项上添加虚样式,统一校验逻辑里通过判断样式来进行处理

例如:

<td id="q2014-H02" class="tdinput numeric noteable blankenabled rule compare">

 tdinput为该td的正式样式,numeric代表此td必须输入浮点数,blankenabled说明此td允许空着不填,rule说明此td有逻辑校验关系(具体是哪条则由逻辑校验代码通过td的id来判断了),noteable则代表此td允许用户输入备注信息,compare说明此td项应当和去年同期的进行比对,如果超过指定比例(20%),则需要提示用户必须输入原因(备注)

当用户结束某td内的输入时,执行checkNode方法

    function compareToLastYear(lnode) {
        var pspan = lnode.one('.previous');
        if (pspan == null)
            return true;

        removeWarning('comparewarning', lnode);
        var lastvalue = parseFloat(pspan.get('text'));
        var thisvalue = parseFloat(lnode.one('.current').get('text'));

        if (isNaN(lastvalue))
            return true;

        if (lnode.one('.notecontent') != null && lnode.one('.notecontent').get('text') != '')
            return true;

        if (thisvalue > lastvalue * 1.2) {
            appendWarning('此项与上一期相比增长率超过了20%,上一期数值为' + lastvalue + ',请核对或填写备注!', 'comparewarning', lnode);
            return false;
        }
        if (thisvalue < lastvalue * 0.8) {
            appendWarning('此项与上一期相比下降超过了20%,上一期数值为' + lastvalue + ',请核对或填写备注!', 'comparewarning', lnode);
            return false;
        }
        return true;
    };

    function removeWarning(classname) {
        for (var i = 1; i < arguments.length; i++) {
            var lnode = arguments[i];
            lnode.all('.' + classname).each(function(k, v) {
                k.remove();
            });
            if (lnode.one('.warningmessage') == null) {
                lnode.removeClass('warning');
            }
        }
    };

    function appendWarning(message, classname) {
        for (var i = 2; i < arguments.length; i++) {
            lnode = arguments[i];
            if (reportviewitem == 'warning' && !lnode.hasClass('warning')) {
                lnode.addClass('warning');
            }
            lnode.appendChild(Y.Node.create('<span class="warningmessage ' + classname + '"></span>').set('text', message));
        }
    };

    function checkZero(lnode) {
        var v = lnode.one('.current').get('text');
        removeWarning('zerowarning', lnode);
        if (parseFloat(v) <= 0) {
            appendWarning('此项必须大于0!', 'zerowarning', lnode);
            return false;
        }
        return true;
    };

    function checkInput(lnode) {
        var v = lnode.one('.current').get('text');
        removeWarning('inputwarning', lnode);
        if (!lnode.hasClass('blankenabled') && v == '') {
            appendWarning('此项必须填写!', 'inputwarning', lnode);
            return false;
        }
        return true;
    };

    //如果有规则,优先检测规则
    function checkNode(lnode) {
        checkInput(lnode);
        if (lnode.hasClass('rule')) {
            checkRule(lnode);
        }
        if (lnode.hasClass('nonzero')) {
            checkZero(lnode);
        }
        if (lnode.hasClass('compare')) {
            compareToLastYear(lnode);
        }
    };

 checkRule方法就不贴了,里面涉及到报表的具体勾稽关系,numberic和number项,则是写在用户输入完毕后,不在统一的校验逻辑里,因为这些项可能允许空

第四,通过css样式来进行多语言切换

其实这是个偷懒方法,在页面里用了多种方法显示多语言,然后呢,有一部分页面上不太好通过多语言资源配置的,例如中文和英文顺序不一样(中间还有其它东西),这时可以用<span class="en hidden">english</span><span class="zh">中文</span>这种模式,然后呢,在脚本里判断下,如果是英文呢,就执行

Y.all('.zh').addClass('hidden');
Y.all('.en').removeClass('hidden');

 

 

posted @ 2014-04-02 10:37  Zux  阅读(350)  评论(0编辑  收藏  举报