计算 属性、过滤并更新 DOM

Computed property, filters and updates to DOM

我有一个包含很多元素的计算 属性。 根据用户输入,我需要过滤掉它所基于的一些元素。

[
    {name:'hal',    display: false},
    {name:'john',   display: true },
    {name:'jack',   display: false},
    {name:'george', display: true },
    {name:'tom',    display: false},
    {name:'rick',   display: false},
    {name:'paul',   display: true },
    {name:'ringo',  display: true },
]

在我的示例中,我希望能够随意过滤掉具有 display:false 的元素。

发生的事情是,由于 Ractive 对数据更改的反应效率,只有特定的更改才会在 DOM 上执行,触发不需要的转换。

一个fiddle顶一千字: http://jsfiddle.net/7kubqbba/4/ (edited, see old version)

如果单击切换按钮,您会注意到在左侧的计算元素上执行了转换。

我相信这是因为 Ractive 没有更新整个 <li>....</li> 标签,而是只更新了应该受影响的特定部分。在这种特定情况下:名称和 class.

<li class="animateme animateme-{{display}}">{{name}}</li>

我想做的是:

关于如何做到这一点的任何提示?

(我完全有可能以错误的方式处理这个问题,如果是这样,请告诉我)


编辑:

tl;dr. 视觉转换应该在任何 'display' 属性 被修改时触发(即 ),而不是 'display:false'正在过滤掉元素。

已更新 fiddle:http://jsfiddle.net/7kubqbba/4/

参见 http://jsfiddle.net/7kubqbba/5/ 下面的示例。

我实际上认为内联过滤示例是更好的方法,如果它变得复杂,您可以将逻辑移到一个函数中:

{{#if show(this) }} ... {{/if}}

...

data: {
    show ( item ) {
        const active = this.get( 'active' );
        return active !== true || item.display;
    }
}

否则,您需要使用 ractive.observeractive.merge 来实现与计算 属性 相同的效果,但具有身份感知 DOM 节点语义:

this.observe('active', active => {
    const entries = this.get('entries');
    const merge = active ? entries.filter( entry => entry.display ) : entries;
    this.merge( 'filtered', merge );
});

请注意,这突出了一个事实,即 ractive 不会跟踪不同数组中相同对象引用之间的变化(除非使用魔术模式),这是 "hidden" 通过重新计算 filteredElements 发生的事实在原始示例中的每个数据更改上。

如果您需要这种行为,您可以设置观察者在数组之间进行映射:

    this.observe('filtered.*.display', ( display, o, k, index ) => {
        this.update('entries.'+index+'.display' );
    });
    this.observe('entries.*.display', ( display, o, k, index ) => {
        this.update('filtered.'+index+'.display' );
    });

或者在下一版本的 ractive (0.8) 中,您可能会使用 link 方法。

编辑:我想到的另一种选择是在过滤器更改时禁用转换。见 http://jsfiddle.net/7kubqbba/6/:

    <li on-click="changeDisplay:{{i}},{{display}}" class="animateme animateme-{{display}} {{#if noTransition}}noTransition{{/if}}">{{name}}</li>

    // in component:
    self.observe('filteredElements', (n, o) => {
        if ( n!==o ) {
            this.set( 'noTransition', true );
        }
    })

    self.observe('filteredElements', (n, o) => {
        setTimeout( () => this.set( 'noTransition', false ) );
    }, { defer: true });