使用Ractive.extend()时如何引用DOM元素?

时间:2016-05-12 07:59:31

标签: javascript dom ractivejs

因此,如果我使用Ractive.extend()来实例化自定义类的对象,那么我将如何引用该类中的DOM元素?我显然不能像往常一样使用document.getElementById(),因为DOM还没有被渲染,并且将Ractive.findComponent()传递给我的构造函数返回" Ractive.findComponent不是函数。 #34;我想做的是这样的事情:

class myClass {
    constructor(id /*,...*/) {
        this.element = document.getElementById(id); //how do I do this??
    };
};

var Extended = Ractive.extend( {
    oninit() {
        var myObject = new myClass(id /*,...*/);
        this.set({myObject});
    } 
});

var ractiveExtended = new Extended({
    el: document.body,
    template: '#template',
    data: { id: myId}
});

ETA:这不起作用......

class myClass {
    constructor(id /*,...*/) {
        this.element = document.getElementById(id);
    };
};

var Extended = Ractive.extend( {
    onrender() {
        var myObject = new myClass(id /*,...*/);
        this.set({myObject});
    } 
});

var ractiveExtended = new Extended({
    el: document.body,
    template: '#template',
    data: { id: myId}
});

这也不是......

class myClass {
    constructor(id /*,...*/) {
        this.element = id;
        this.element.innerHTML = 'Hello world!';
    };
};

var Extended = Ractive.extend( {
    onrender() {
        var myObject = new myClass(document.getElementById(id) /*,...*/);
        this.set({myObject});
    } 
});

var ractiveExtended = new Extended({
    el: document.body,
    template: '#template',
    data: { id: myId}
});

2 个答案:

答案 0 :(得分:0)

更新了评论中澄清的问题的答案

你这里有一点鸡蛋问题:

{{#each sprites}}
    <canvas id={{.id}}></canvas>
{{/each}}

表示Ractive会为<canvas>中的每个项目创建sprites,并为其指定相应的ID。但是,sprites在初始渲染时未定义,因此不会创建<canvas>个元素。

然后,在onrender()内部创建您的类的实例,假设<canvas>元素已经存在。只有在此之后,您才将实例添加到sprites,告诉Ractive渲染元素:

this.set({ sprites });

有几种可能的解决方案。 (我认为)最好的方法是在你的类中添加一个render()方法,并从构造函数中移除任何与DOM相关的东西。然后,您的代码将更改为以下内容:

onrender () {
    var sprites = this.get('repeaters').map(function(repeater){    
        return new CanvasSprite(repeater.id);
    });

    this.set({ sprites });

    sprites.forEach(function (sprite) {
        sprite.render();
    });
}

但是,如果您不想修改类,则只需将现有repeaters数组用于{{each}}循环即可。在这里演示:http://jsfiddle.net/9xLzj3zd/1/

关键是,您需要一种方法来告诉Ractive在使用<canvas>或类似方法之前呈现document.getElementsById()元素。

原始回答

如果您需要访问DOM,请将初始化代码从oninit移至onrender。然后,您可以使用document.getElementById()ractive.find()documentation here)来获取所需的元素。

class myClass {
    constructor(id) {
        this.element = document.getElementById(id);
        this.element.innerHTML = 'Hello world!';
    };
};

var Extended = Ractive.extend( {
    onrender() {
        // use this.get('id') to get ID from Ractive's data
        var myObject = new myClass(this.get('id'));
        this.set({myObject});
    } 
});

var ractiveExtended = new Extended({
    el: document.body,
    template: '#template',
    data: { id: 'content' },
});

演示:http://jsfiddle.net/Lgpe2h5L/1/

答案 1 :(得分:0)

编辑:完整运行示例:http://jsbin.com/vuziyepeku/edit?html,js,output

我会将每个CanvasSprite封装在其自己的组件中:

const CanvasSpriteComponent = Ractive.extend({

    template: '#sprite',

    // Using onrender, not oninit, because we need DOM canvas node
    onrender(){
        const canvas = this.find('canvas');
        const repeater = this.get('repeater');

        var sprite = new CanvasSprite(canvas, repeater.width, repeater.height, repeater.spriteSheetURL, repeater.rows, repeater.columns, repeater.totalFrames);
        sprite.left = repeater.left; //add variables *not* in the constructor
        sprite.setFrame(0);

        this.on('setFrame', function (event) {
            var offsetY = event.original.clientY - event.node.getBoundingClientRect().top;
            var relY = offsetY/sprite.height;
            sprite.setFrame(relY);
        });
    }
});

然后在主实例中使用它:

var CanvasAnimation = Ractive.extend( {
    template: '#animation',
    components: {
        'canvas-sprite': CanvasSpriteComponent
    }   
});

var canvasAnimation = new CanvasAnimation({
    el: 'main',
    data: { repeaters: repeater }
});

可以说,你的CanvasSprite类更有意义采用画布节点,因为它不再依赖于该节点所在的 (当前document.getElementById)。

如果您根本不愿意更改该类,则只需要编写一个唯一的ID(如果转发器集合不会变异,则使用索引)。在这种情况下,我重复使用该组件的唯一ID:

const CanvasSpriteComponent = Ractive.extend({
    // ...
    onrender(){
        const canvas = this.find('canvas');
        canvas.id = `canvas-${this._guid}`
        const repeater = this.get('repeater');

        var sprite = new CanvasSprite(canvas.id, repeater.width, repeater.height, repeater.spriteSheetURL, repeater.rows, repeater.columns, repeater.totalFrames);
        sprite.left = repeater.left; //add variables *not* in the constructor
        sprint.setFrame(0);

        this.on('setFrame', function (event) {
            var offsetY = event.original.clientY - event.node.getBoundingClientRect().top;
            var relY = offsetY/sprite.height;
            sprite.setFrame(relY);
        });
    }
});