使用Ractive.extend()时如何引用DOM元素?
How to refer to DOM Elements When Using Ractive.extend()?
因此,如果我使用 Ractive.extend() 来实例化自定义 class 的对象,那么我将如何引用 class 中的 DOM 元素?我显然不能像往常一样使用 document.getElementById() 因为 DOM 还没有被渲染并将 Ractive.findComponent() 传递给我的构造函数 returns "Ractive.findComponent is not a function."我想做的是这样的:
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}
});
预计到达时间:这也行不通...
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}
});
更新了对评论中阐明的问题的回答
你这里遇到了一个先有鸡还是先有蛋的小问题:
{{#each sprites}}
<canvas id={{.id}}></canvas>
{{/each}}
意味着 Ractive 将为 sprites
中的每个项目创建一个 <canvas>
并为其分配适当的 ID。但是,sprites
在初始渲染时未定义,因此不会创建 <canvas>
元素。
然后,在 onrender()
中创建 class 的实例,它假定 <canvas>
元素已经存在。只有在那之后你将实例添加到 sprites
,告诉 Ractive 渲染元素:
this.set({ sprites });
有几种可能的解决方案。 (我认为)最好的方法是将 render()
方法添加到 class 并将任何与 DOM 相关的内容移出构造函数。然后您的代码将更改为如下所示:
onrender () {
var sprites = this.get('repeaters').map(function(repeater){
return new CanvasSprite(repeater.id);
});
this.set({ sprites });
sprites.forEach(function (sprite) {
sprite.render();
});
}
但是,如果您不想修改 class,您可以简单地使用现有的 repeaters
数组作为 {{each}}
循环。此处演示:http://jsfiddle.net/9xLzj3zd/1/
重点是,在使用 document.getElementsById()
或类似方法之前,您需要一种方法告诉 Ractive 渲染 <canvas>
元素。
原回答
如果您需要访问 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://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
class 使用 canvas 节点更有意义,因为它不再与 how 相关联该节点位于(当前 document.getElementById
)。
如果您根本不想更改 class,您只需要构建一个唯一的 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);
});
}
});
因此,如果我使用 Ractive.extend() 来实例化自定义 class 的对象,那么我将如何引用 class 中的 DOM 元素?我显然不能像往常一样使用 document.getElementById() 因为 DOM 还没有被渲染并将 Ractive.findComponent() 传递给我的构造函数 returns "Ractive.findComponent is not a function."我想做的是这样的:
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}
});
预计到达时间:这也行不通...
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}
});
更新了对评论中阐明的问题的回答
你这里遇到了一个先有鸡还是先有蛋的小问题:
{{#each sprites}}
<canvas id={{.id}}></canvas>
{{/each}}
意味着 Ractive 将为 sprites
中的每个项目创建一个 <canvas>
并为其分配适当的 ID。但是,sprites
在初始渲染时未定义,因此不会创建 <canvas>
元素。
然后,在 onrender()
中创建 class 的实例,它假定 <canvas>
元素已经存在。只有在那之后你将实例添加到 sprites
,告诉 Ractive 渲染元素:
this.set({ sprites });
有几种可能的解决方案。 (我认为)最好的方法是将 render()
方法添加到 class 并将任何与 DOM 相关的内容移出构造函数。然后您的代码将更改为如下所示:
onrender () {
var sprites = this.get('repeaters').map(function(repeater){
return new CanvasSprite(repeater.id);
});
this.set({ sprites });
sprites.forEach(function (sprite) {
sprite.render();
});
}
但是,如果您不想修改 class,您可以简单地使用现有的 repeaters
数组作为 {{each}}
循环。此处演示:http://jsfiddle.net/9xLzj3zd/1/
重点是,在使用 document.getElementsById()
或类似方法之前,您需要一种方法告诉 Ractive 渲染 <canvas>
元素。
原回答
如果您需要访问 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://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
class 使用 canvas 节点更有意义,因为它不再与 how 相关联该节点位于(当前 document.getElementById
)。
如果您根本不想更改 class,您只需要构建一个唯一的 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);
});
}
});