etaoux/brix

brix 的模板解析问题

Closed this issue · 6 comments

问题

我们最早讨论brix对于获取子模板,实现局部刷新功能时候,定下的@逸才同学提出的在内存中创建dom结构,用操作dom的方式获取innerHTML来实现获取子模板。
在brix的具体实现中碰到了蛮多问题,主要是不同浏览器下对mustache模板解析成html结构时的不同处理,比如src,href等会编码、"{{/"这个会认为是一个html标签的结束等等坑,这些都在tmpler.js中一一解决了,然而,昨天,我们又遇到坑了,比如:

    <div bx-tmpl="list" bx-datakey="list">
        <table>
            <tbody>
            {{#list}}
                <tr>
                    <td>{{name}}<td>
                </tr>
            {{/list}}
            </tbody>
        </table>
    </div>

上面这个代码创建成dom时候,浏览器直接过滤了{{#list}}和{{/list}},我们无法取到正确的模板代码。

分析

那么,我们想从上面代码拿到什么样的信息呢?

首先是模板代码:

    <table>
        <tbody>
        {{#list}}
            <tr>
                <td>{{name}}<td>
            </tr>
        {{/list}}
        </tbody>
    </table>

然后是模板对应的数据key值,即:bx-datakey自定义属性

最后后是模板代码对应于哪个节点

    <div bx-tmpl="list" bx-datakey="list">
    </div>

有了这三个,我们就能在数据发生变化的时候重新渲染模板,实现局部刷新。

解决

既然innerHTML有这么多坑,而且已经碰到一个我无能为力的坑,那就换种思路。

我们能不能通过直接分析字符串的方式来获取?

如果模板变成:

    <div bx-tmpl="list" bx-datakey="list">
    {{#bx-tmpl="list" bx-datakey="list"}}
        <table>
            <tbody>
            {{#list}}
                <tr>
                    <td>{{name}}<td>
                </tr>
            {{/list}}
            </tbody>
        </table>
    {{/bx-tmpl="list"}}
    </div>

我们写一个这样的正则:

    /\{\{#bx-tmpl="(.*)?".*?bx-datakey="(.+)?"\}\}(\s*([\s\S]*)?\s*)\{\{\/bx-tmpl="\1"\}\}/ig

就能解决问题了。

坏处

看上面的代码就知道了,我们重复定义了两遍bx-tmpl和bx-datakey,似乎有点不优雅,暂时我也不知道要怎么改造:

    <div bx-tmpl="list" bx-datakey="list">
    {{#bx-tmpl="list" bx-datakey="list"}}
    {{/bx-tmpl="list"}}
    </div>

讨论

大家看看,这样的方案是否可行?

防止自动转义或过滤,可以用注释吧,比如

<div bx-tmpl="list" bx-datakey="list">
<!--
        <table>
            <tbody>
            {{#list}}
                <tr>
                    <td>{{name}}<td>
                </tr>
            {{/list}}
            </tbody>
        </table>
-->
    </div>

这样应该没什么问题,解析时稍微麻烦点

注释会和原生的html注释冲突吧,你怎么知道是模板还是真的注释。

limu commented

用handlebars来结构化模板,联系下基德看看。。

用 xtemplate parse 模板可以解决,
但代码会大不少,handlebar 也一样,你看下吧

发自我的 iPhone

在 2012-10-30,下午4:47,"左莫" notifications@github.com 写道:

问题

我们最早讨论brix对于获取子模板,实现局部刷新功能时候,定下的@逸才同学提出的在内存中创建dom结构,用操作dom的方式获取innerHTML来实现获取子模板。
在brix的具体实现中碰到了蛮多问题,主要是不同浏览器下对mustache模板解析成html结构时的不同处理,比如src,href等会编码、"{{/"这个会认为是一个html标签的结束等等坑,这些都在tmpler.js中一一解决了,然而,昨天,我们又遇到坑了,比如:

<div bx-tmpl="list" bx-datakey="list">
    <table>
        <tbody>
        {{#list}}
            <tr>
                <td>{{name}}<td>
            </tr>
        {{/list}}
        </tbody>
    </table>
</div>

上面这个代码创建成dom时候,浏览器直接过滤了{{#list}}和{{/list}},我们无法取到正确的模板代码。
分析

那么,我们想从上面代码拿到什么样的信息呢?

首先是模板代码:

<table>
    <tbody>
    {{#list}}
        <tr>
            <td>{{name}}<td>
        </tr>
    {{/list}}
    </tbody>
</table>

然后是模板对应的数据key值,即:bx-datakey自定义属性

最后后是模板代码对应于哪个节点

<div bx-tmpl="list" bx-datakey="list">
</div>

有了这三个,我们就能在数据发生变化的时候重新渲染模板,实现局部刷新。
解决

既然innerHTML有这么多坑,而且已经碰到一个我无能为力的坑,那就换种思路。

我们能不能通过直接分析字符串的方式来获取?

如果模板变成:

<div bx-tmpl="list" bx-datakey="list">
{{#bx-tmpl="list" bx-datakey="list"}}
    <table>
        <tbody>
        {{#list}}
            <tr>
                <td>{{name}}<td>
            </tr>
        {{/list}}
        </tbody>
    </table>
{{/bx-tmpl="list"}}
</div>

我们写一个这样的正则:

/\{\{#bx-tmpl="(.*)?".*?bx-datakey="(.+)?"\}\}(\s*([\s\S]*)?\s*)\{\{\/bx-tmpl="\1"\}\}/ig

就能解决问题了。
坏处

看上面的代码就知道了,我们重复定义了两遍bx-tmpl和bx-datakey,似乎有点不优雅,暂时我也不知道要怎么改造:

{{#bx-tmpl="list" bx-datakey="list"}}
{{/bx-tmpl="list"}}
讨论

大家看看,这样的方案是否可行?


Reply to this email directly or view it on
GitHubhttps://github.com//issues/39.

最后定下的方案是,模板的写法为

<div bx-tmpl="list" bx-datakey="list" class="table">
<!--bx-tmpl="list" bx-datakey="list"-->
    <table>
        <tbody>
        {{#list}}
            <tr>
                <td>{{name}}<td>
            </tr>
        {{/list}}
        </tbody>
    </table>
<!--bx-tmpl="list">
</div>

注释写法可以不破坏原有模板的语义。