aralejs / aralejs.github.io

开放、简单、易用的前端基础类库
http://aralejs.github.io
MIT License
1.37k stars 321 forks source link

handlebars模版没有过滤器支持, 如何轻松实现数据格式化展示? #321

Closed wonderbeyond closed 11 years ago

wonderbeyond commented 11 years ago

对于seajs生态系统, 我目前还在探索阶段, 还没有真正投入使用.

我现在最纠结的就是 handlebars 模版没法优雅的做数据的 格式化 展示.

下面的是我的一个用例, 定制一个MyWidget, 用来展示产品信息. 产品数据通过ajax获取, 然后通过 Templatable 提供的模版渲染到DOM中.

ajax返回的json数据格式:

[
    {
        "netvalue": 0.9503,
        "cnetvalue": 0.9503,
        "valuedate": 1383840000
    },
    {
        "netvalue": 1.0855,
        "cnetvalue": 1.7039,
        "valuedate": 1383840000
    }
]

数据是一个列表结构, 包含多个产品信息, 具体信息包括: 净值日期、单位净值、累计净值。净值日期是一个UNIX时间戳。

Widget定义与调用代码:

        $.ajax({
            dataType: 'jsonp',
            url: 'xxxx'
        }).done(function(data){
            var MyWidget = Widget.extend({
                Implements: Templatable
            });
            var mywidget = new MyWidget({
                template: $('#products-template').html(),
                model: {'products': data},
                parentNode: '#products'
            });
            mywidget.render();
        });

模版代码片段:

<div id="products">
<script id="products-template" type="text/x-handlebars-template">
        <table>
        <tr>
            <th>净值日期</th>
            <th>单位净值</th>
            <th>累计净值</th>
        </tr>
        {{#each products}}
        <tr>
            <td>{{ valuedate }}</td>
            <td>{{ netvalue }}</td>
            <td>{{ cnetvalue }}</td>
        </tr>
        {{/each}}
        </table>
</script>
</div>

其实,使用以上模版渲染出来的结果并不是我想要的,真正展示需求是:

我觉得后端没有义务为你返回格式化好的数据,这是个纯粹的展示需求, 后端接口返回的数据应该是原始、通用、利于转换的格式。

但是,在handlebars中实现过滤器逻辑太麻烦了,好像要 register helpers ,这样写浪费的时间比较多,也不直观。 难道就不能把变量传给一个在其它模块中定义的函数处理?

我正在认真考虑利用arale生态系统中的组件来提升开发效率,但是这个handlebars模版体验让我很受挫。

对于目前这个例子,我应该如何实践呢?希望能得到指点。

edokeh commented 11 years ago

用 helper 做很正常啊,这个属于展示的逻辑嘛,为啥觉得不直观呢? 而且你说的这两个需求都是通用性需求,注册好 helper 以后其他地方也可以用嘛,为啥会觉得浪费呢?

wonderbeyond commented 11 years ago

可能我有点强迫症,我看到文档中介绍的helper,顿时就感觉这东西很不爽,我甚至都没有在我的测试代码中写一个自己的helper去体验一下。

我还是强迫自己去接受这个东西吧。

afc163 commented 11 years ago

功课做的很赞,这个帖子看的舒服。

正如楼主所说,handlebars 本身的逻辑非常简单,逻辑需要通过 Helpers 来注册。不过我觉得这个 helpers 的写法还是很直观的,楼主可以在一个公共模块里统一定义 helpers 便于复用。

templateHelpers: {
  'list': require('./helplers').list,
  'filter': require('./helplers').filter
}

至于 Sea.js 和 Arale 的生态圈,其实我们没有限定用哪套模板模块,只是团队内保持统一和持续性,就一直使用 handlerbars。如果楼主对其他模板系统有深入研究,不妨也可以实践并引入到这个生态圈里来(比如 https://github.com/aui/artTemplate )。其实我们最近也在考察其他模板系统,希望能够引入到支付宝的前后端统一开发中来,做到一套模板前后台共用。

wonderbeyond commented 11 years ago

我是觉得,这样使用filter是最理想的:

{{ cnetvalue|date:"YY-mm-dd" }}

date是一个可以找到的函数,cnetvalue是date()的第一个参数,"YY-mm-dd"是date()的第二个参数,表示生成的日期格式。

edokeh commented 11 years ago

helper 这种东西在各种框架里面都很常见啊,通常用来存放数据的展示逻辑(非业务逻辑) 前端的 Angular 里面叫做 filter,后端的 Rails 里面就叫做 Helper

edokeh commented 11 years ago

看来是用过 Angular 的同学,handlerbar 里面目前做不到这么好看的写法。。。 顶多这样子吧 {{ dateFormat topic.created_at 'YY-mm-dd' }}

wonderbeyond commented 11 years ago

这是我用django模版留下的思维模式。

helper还是第一次听说,终于知道了,它也是用来格式化数据的。

wonderbeyond commented 11 years ago

@afc163, 您好

我按照你的提示把helpers定义到了一个模块中:

define(function(require){
    return {
        'toFixed': function(value, digits){
            return Number(value).toFixed(digits||2);
        },

        'formatDate': function(dateValue, format){
            //dateValue以秒为单位
            return new Date(dateValue*1000).toLocaleDateString();
        }
    }
});

然后实例化Widget的时候,把模块返回的对象作为 templateHelpers 选项的值:

            var mywidget = new MyWidget({
                template: $('#products-template').html(),
                templateHelpers: require('common-handlebars-helpers.js'),
                model: {'products': data},
                parentNode: '#products'
            });

但是模版中还是不支持这样的写法:

<td>{{ toFixed netvalue 2 }}</td>

Uncaught Error: Could not find property 'toFixed'

不知我哪里用错了,我根据 这里 的示例,没发现哪里使用不当啊。

templateHelpers是一个包含多个普通方法的对象,而我的模块正好也返回这样的对象。

wonderbeyond commented 11 years ago

@afc163, 不好意思. 我看例子看偏了, templateHelpers选项是定义Widget的时候传入的, 我搞成实例化的时候传入了.

应该:

        var MyWidget = Widget.extend({
            Implements: Templatable,
            templateHelpers: require('zlfund/common-handlebars-helpers.js')
        });
popomore commented 11 years ago

选择一个模板只能使用他固有的方式,如果想做一个自己的解决方案的话可以自己选择一个模板,widget 也是支持的。

lizzie commented 10 years ago

{{ cnetvalue|date:"YY-mm-dd" }} 这种写法确实很舒服. 你可以试下 (swig)[http://paularmstrong.github.io/swig/]

ps: 又看到 @lepture 的影子了. https://npmjs.org/package/jinja

google 了下, 貌似很多 https://github.com/ericclemmons/jinja.js

lepture commented 10 years ago

You can also try: https://github.com/jlongster/nunjucks