如何动态创建 Ractive 的子组件并以编程方式更改它们
How to create Ractive's subcomponents dynamically and change them programmatically
我可以使用标签手动实例化(子)组件,但我不知道如何动态地做到这一点,或者,如何使用标签在同一区域插入和删除不同的组件。
今天我以这种方式实例化每个(子)组件:
Ractive.load( '/templates/global/example.html' ).then( function ( Example )
{
ractive.components.example = new Example( { el : 'aside' } );
});
但是新的(子)组件在 mustache 中看不到它的父实例的数据,只能看到他自己的数据。
这是一个动态组件:
Ractive.components.dynamic = Ractive.extend({
template: '<component/>',
components: {
component: function() {
return this.get('name');
}
},
oninit: function(){
this.observe('name', function(){
this.reset();
}, { init: false});
}
});
只需传入它应该实现的组件的名称:
<dynamic name='{{name}}'/>
在下方查看实际效果
Ractive.components.a = Ractive.extend({ template: 'I am A {{foo}}' });
Ractive.components.b = Ractive.extend({ template: 'I am B {{foo}}' });
Ractive.components.c = Ractive.extend({ template: 'I am C {{foo}}' });
Ractive.components.dynamic = Ractive.extend({
template: '<component/>',
components: {
component: function() {
return this.get('name');
}
},
oninit: function(){
this.observe('name', function(){
this.reset();
}, { init: false});
}
});
var r = new Ractive({
el: document.body,
template: '#template',
data: {
foo: 'foo',
list: ['a', 'b', 'c'],
name: 'a'
}
});
<script src="http://cdn.ractivejs.org/latest/ractive.js"></script>
<script id='template' type='text/ractive'>
{{#each list}}
<input type='radio' name='{{name}}' value='{{.}}'>{{.}}
{{/each}}
<br>
<dynamic name='{{name}}'/>
</script>
想不止一次对@martypdx 的回答投赞成票。受到他的回答的启发,我想出了一些我想分享的东西。它添加了以下内容:
创建一个组件类型的多个实例(Ractive.extend)
组件实例是活动的并且可以接收来自外部侦听器的消息,即使它们已被取消渲染。
这是我的fiddle:https://jsfiddle.net/vikikamath/z5otgzpL/9/
// Inspired by
var mapper = {
'A': function(instanceId){
var handleAData;
return Ractive.extend({
template: 'I am A this is my data: <ul>{{#datas}}<li>{{.}}</li>{{/datas}}</ul>',
data: {
datas:[]
},
onrender: function() {
handleAData = function(txt){
this.push('datas', txt);
}.bind(this);
r.on(instanceId, handleAData);
},
onunrender: function() {
r.off(instanceId, handleAData);
}
});
}
,'B': function(instanceId){
var handleBData;
return Ractive.extend({
template: 'I am B this is my data: <ul>{{#datas}}<li>{{.}}</li>{{/datas}}</ul>',
data: {
datas:[]
},
onrender: function() {
handleBData = function(txt){
this.push('datas', txt);
}.bind(this);
r.on(instanceId, handleBData);
},
onunrender: function() {
r.off(instanceId, handleBData);
}
});
}
,'C': function(instanceId){
var handleCData;
return Ractive.extend({
template: 'I am C this is my data: <ul>{{#datas}}<li>{{.}}</li>{{/datas}}</ul>',
data: {
datas:[]
},
onrender: function() {
handleCData = function(txt){
this.push('datas', txt);
}.bind(this);
r.on(instanceId, handleCData);
},
onunrender: function() {
r.off(instanceId, handleCData);
}
});
}
,'D': function(instanceId){
var handleDData;
return Ractive.extend({
template: 'I am D this is my data: <ul>{{#datas}}<li>{{.}}</li>{{/datas}}</ul>',
data: {
datas:[]
},
onrender: function() {
handleDData = function(txt){
this.push('datas', txt);
}.bind(this);
r.on(instanceId, handleDData);
},
onunrender: function() {
r.off(instanceId, handleDData);
}
});
}
}
/* arbitrarily select a component */
function pickRandomComponent() {
return String.fromCharCode(Math.floor(Math.random() * Object.keys(mapper).length) + 65);
}
var DynamicComponent = Ractive.extend({
template: '<component/>',
components: {
component: function() {
return this.get('name');
}
},
oninit: function(){
this.observe('name', function(){
this.reset();
}, { init: false});
}
});
var r = new Ractive({
el: 'main',
template: '#template',
components: {
dummy: Ractive.extend({ template: 'Welcome message' }),
dynamic: DynamicComponent
},
data: {
foo: 'foo',
list: ['dummy'],
name: 'dummy',
textdata: ''
},
oninit: function() {
this.on("sendDataToCurrentComponent", function() {
r.fire(this.get('name'), this.get('textdata'))
}.bind(this));
this.on('addComponent', function(){
var rndComponent = pickRandomComponent();
var now = Date.now();
var componentInstanceName = rndComponent + '-' + now
this.components[componentInstanceName] = mapper[rndComponent](componentInstanceName)
this.push('list', componentInstanceName);
}.bind(this));
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/ractive/0.7.3/ractive.min.js"></script>
<script id='template' type='text/ractive'>
<button on-click="addComponent">Add</button>
<div>
<input type="text" value="{{textdata}}" placeholder="Send Text to current component" width="900" on-blur="sendDataToCurrentComponent"/>
</div>
{{#each list}}
<input type='radio' name='{{name}}' value='{{.}}'>{{.}}
{{/each}}
<br>
<dynamic name='{{name}}'/>
</script>
<main></main>
我可以使用标签手动实例化(子)组件,但我不知道如何动态地做到这一点,或者,如何使用标签在同一区域插入和删除不同的组件。
今天我以这种方式实例化每个(子)组件:
Ractive.load( '/templates/global/example.html' ).then( function ( Example )
{
ractive.components.example = new Example( { el : 'aside' } );
});
但是新的(子)组件在 mustache 中看不到它的父实例的数据,只能看到他自己的数据。
这是一个动态组件:
Ractive.components.dynamic = Ractive.extend({
template: '<component/>',
components: {
component: function() {
return this.get('name');
}
},
oninit: function(){
this.observe('name', function(){
this.reset();
}, { init: false});
}
});
只需传入它应该实现的组件的名称:
<dynamic name='{{name}}'/>
在下方查看实际效果
Ractive.components.a = Ractive.extend({ template: 'I am A {{foo}}' });
Ractive.components.b = Ractive.extend({ template: 'I am B {{foo}}' });
Ractive.components.c = Ractive.extend({ template: 'I am C {{foo}}' });
Ractive.components.dynamic = Ractive.extend({
template: '<component/>',
components: {
component: function() {
return this.get('name');
}
},
oninit: function(){
this.observe('name', function(){
this.reset();
}, { init: false});
}
});
var r = new Ractive({
el: document.body,
template: '#template',
data: {
foo: 'foo',
list: ['a', 'b', 'c'],
name: 'a'
}
});
<script src="http://cdn.ractivejs.org/latest/ractive.js"></script>
<script id='template' type='text/ractive'>
{{#each list}}
<input type='radio' name='{{name}}' value='{{.}}'>{{.}}
{{/each}}
<br>
<dynamic name='{{name}}'/>
</script>
想不止一次对@martypdx 的回答投赞成票。受到他的回答的启发,我想出了一些我想分享的东西。它添加了以下内容:
创建一个组件类型的多个实例(Ractive.extend)
组件实例是活动的并且可以接收来自外部侦听器的消息,即使它们已被取消渲染。
这是我的fiddle:https://jsfiddle.net/vikikamath/z5otgzpL/9/
// Inspired by
var mapper = {
'A': function(instanceId){
var handleAData;
return Ractive.extend({
template: 'I am A this is my data: <ul>{{#datas}}<li>{{.}}</li>{{/datas}}</ul>',
data: {
datas:[]
},
onrender: function() {
handleAData = function(txt){
this.push('datas', txt);
}.bind(this);
r.on(instanceId, handleAData);
},
onunrender: function() {
r.off(instanceId, handleAData);
}
});
}
,'B': function(instanceId){
var handleBData;
return Ractive.extend({
template: 'I am B this is my data: <ul>{{#datas}}<li>{{.}}</li>{{/datas}}</ul>',
data: {
datas:[]
},
onrender: function() {
handleBData = function(txt){
this.push('datas', txt);
}.bind(this);
r.on(instanceId, handleBData);
},
onunrender: function() {
r.off(instanceId, handleBData);
}
});
}
,'C': function(instanceId){
var handleCData;
return Ractive.extend({
template: 'I am C this is my data: <ul>{{#datas}}<li>{{.}}</li>{{/datas}}</ul>',
data: {
datas:[]
},
onrender: function() {
handleCData = function(txt){
this.push('datas', txt);
}.bind(this);
r.on(instanceId, handleCData);
},
onunrender: function() {
r.off(instanceId, handleCData);
}
});
}
,'D': function(instanceId){
var handleDData;
return Ractive.extend({
template: 'I am D this is my data: <ul>{{#datas}}<li>{{.}}</li>{{/datas}}</ul>',
data: {
datas:[]
},
onrender: function() {
handleDData = function(txt){
this.push('datas', txt);
}.bind(this);
r.on(instanceId, handleDData);
},
onunrender: function() {
r.off(instanceId, handleDData);
}
});
}
}
/* arbitrarily select a component */
function pickRandomComponent() {
return String.fromCharCode(Math.floor(Math.random() * Object.keys(mapper).length) + 65);
}
var DynamicComponent = Ractive.extend({
template: '<component/>',
components: {
component: function() {
return this.get('name');
}
},
oninit: function(){
this.observe('name', function(){
this.reset();
}, { init: false});
}
});
var r = new Ractive({
el: 'main',
template: '#template',
components: {
dummy: Ractive.extend({ template: 'Welcome message' }),
dynamic: DynamicComponent
},
data: {
foo: 'foo',
list: ['dummy'],
name: 'dummy',
textdata: ''
},
oninit: function() {
this.on("sendDataToCurrentComponent", function() {
r.fire(this.get('name'), this.get('textdata'))
}.bind(this));
this.on('addComponent', function(){
var rndComponent = pickRandomComponent();
var now = Date.now();
var componentInstanceName = rndComponent + '-' + now
this.components[componentInstanceName] = mapper[rndComponent](componentInstanceName)
this.push('list', componentInstanceName);
}.bind(this));
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/ractive/0.7.3/ractive.min.js"></script>
<script id='template' type='text/ractive'>
<button on-click="addComponent">Add</button>
<div>
<input type="text" value="{{textdata}}" placeholder="Send Text to current component" width="900" on-blur="sendDataToCurrentComponent"/>
</div>
{{#each list}}
<input type='radio' name='{{name}}' value='{{.}}'>{{.}}
{{/each}}
<br>
<dynamic name='{{name}}'/>
</script>
<main></main>