Prop | desc. |
---|---|
this.view | shadow host |
this.shadow | shadow root |
this.root | component root based on template
|
this.view
, this.shadow
and this.root
are Craft.UI.View's basic property that is defined by Craft.Core.Component the top level class of all views.
this.view
is the top level DOM element of your component, having unique componentId. This is the Shadow Host of your component.
this.shadow
is Shadow Root of your component, attached to this.view
(Shadow Host) by open mode.
this.root
is the first child of your template, and it is appended to the this.shadow
(Shadow Root).
Your template is under the Shadow Root. Therefore CSS class name and DOM ID never conflict across the craftkit application. This is the first key technology of craftkit to enable comfortable OOP by encapsulating Component definition.
For example:
class Vehicle extends Craft.UI.View {
whoami(){
return this.shadow.getElementById('text').innerHTML;
}
style(componentId){
return `
.root { color:red; }
`;
}
template(componentId){
return `
<div id="root" class="root">
<span id="text">I'm Vehicle</span>
</div>
`;
}
}
class Bike extends Vehicle {
style(componentId){
return super.style(componentId) + `
.root { color:blue; }
`;
}
template(componentId){
return `
<div id="root" class="root">
<span id="text">I'm Bike.</span>
</div>
`;
}
}
class Car extends Vehicle {
style(componentId){
return super.style(componentId) + `
.root { color:purple; }
`;
}
template(componentId){
return `
<div id="root" class="root">
<span id="text">I'm Car.</span>
</div>
`;
}
}
Bike and Car both cascade .root
CSS class from Vehicle, but both root
class independently applied and never conflict.
By the principle of Shadow DOM specification, you cannot access inside of your component DOM element via its ID from out side of your component.
But your can access inside of your component's element via componentId from any where you want.
Instantiated component is registered to the Craft.Core.ComponentStack
by its unique componentId
. If you set Craft.Core.Defaults.ALLOW_COMPONENT_SHORTCUT
to true at boot time, you can also use the componentId
as global variable. This is the second key technology of craftkit.
This feature is used to call instance method from rendered template.
class DangerousTruck extends Car {
ignite(){
this.shadow.getElementById('text').innerHTML = "🚛🔥🔥🔥";
}
cooldown(){
this.shadow.getElementById('text').innerHTML = "I'm COOL Truck 😄";
}
style(componentId){
return super.style(componentId) + `
.root { color:purple; }
`;
}
template(componentId){
return `
<div id="root" class="root">
<span id="text" onclick="${componentId}.ignite()">
I'm dangerous Truck.
</span>
</div>
`;
}
}
When you click the text, it ignites the truck!
Of course, you can call ignite method from global by something like this:
Object.keys(Craft.Core.ComponentStack.container)
.filter( id => id.match('Dangerous') )
.map( danger => window[danger].cooldown() )
※ Object.keys for Craft.Core.ComponentStack.container returns array of componentId. This is String. So it is accessing from window object.
NOTE
Above examples are runnable on playground.
var bike_view = new Bike();
bike_view.loadView();
Craft.Core.Context.getRootViewController().appendSubView(bike_view);
var car_view = new Car();
car_view.loadView();
Craft.Core.Context.getRootViewController().appendSubView(car_view);
bike_view.shadow.getElementById('text').innerHTML; //-> I'm Bike
bike_view.whoami(); //-> I'm Bike
car_view.root.style.color = 'purple' //-> make 'I'm Car.' purple
var truck_view = new DangerousTruck();
truck_view.loadView();
Craft.Core.Context.getRootViewController().appendSubView(truck_view);
truck_view.ignite(); //-> 🚛🔥🔥🔥
🛺 Try CraftKit Playground:
https://github.com/craftkit/craftkit-playground
Top comments (0)