Custom Components
In simple applications, the window consists of just one component. However, when the window becomes complex, it may be a good idea to split it into a few separate child components. For example:
<template>
<Window title="Example" width="640" height="480" margined>
<Box padded>
<WindowHeader/>
<WindowFooter/>
</Box>
</Window>
</template>
<script>
import WindowHeader from './WindowHeader'
import WindowFooter from './WindowFooter'
export default {
components: {
WindowHeader,
WindowFooter
}
}
</script>
This creates a window component which contains two child components, one under another.
The child components must be imported and declared using the
components
option of the parent component. Custom components declared like this can be used just like built-in components.The root element of a child component can be a container, or even a single widget. For example:
<template>
<Box padded>
<Button>OK</Button>
<Button>Cancel</Button>
</Box>
</template>
Some components are used in many different places in the application, for example in different windows. Instead of importing them into every parent component that needs to use them, you can declare a global component.
This can be done by calling
Vue.component()
in the main script of the application:main.js
import libui from 'libui-node'
import Vue from 'vuido'
import ButtonGroup from './ButtonGroup'
import MainWindow from './MainWindow'
Vue.component( 'ButtonGroup', ButtonGroup );
const window = new Vue( {
render: h => h( MainWindow )
} );
window.$mount();
libui.startLoop();
Now you can place the custom ButtonGroup component inside any other component.
You can use properties to pass data from the parent component to the child component. For example, let's define a custom component like this:
ButtonGroup.vue
<template>
<Box padded>
<Button>{{ okText }}</Button>
<Button>{{ cancelText }}</Button>
</Box>
</template>
<script>
export default {
props: {
okText: String,
cancelText: String
}
}
</script>
The
props
section specifies that this component has two properties, okText
and cancelText
, and their values must be strings. You can use other JavaScript types, like Boolean
, Numeric
, Array
or Object
to validate the property.Now you can use the ButtonGroup component like this:
<ButtonGroup ok-text="OK" cancel-text="Cancel"/>
Note that the kebab-cased names of attributes are mapped to the corresponding camelCased names of properties.
A property can have a default value:
props: {
okText: { type: String, default: 'OK' },
cancelText: { type: String, default: 'Cancel' }
}
It also can be marked as required:
props: {
items: { type: Array, required: true }
}
You can pass a dynamic value to a property using
v-bind
:<ButtonGroup v-bind:ok-text="okText" v-bind:cancel-text="cancelText"/>
When using a boolean or numeric property, you must use the
v-bind
directive even if you pass a constant value. Otherwise the value would be interpreted as a string. For example:<BlogPost v-bind:likes="42" v-bind:is-published="true"/>
You can also omit the value to pass
true
to a boolean property:<BlogPost is-published/>
Child components can use custom events to notify their parent:
ButtonGroup.vue
<template>
<Box padded>
<Button v-on:click="okClick">OK</Button>
<Button v-on:click="cancelClick">Cancel</Button>
</Box>
</template>
<script>
export default {
methods: {
okClick() {
this.$emit( 'ok-click' );
},
cancelClick() {
this.$emit( 'cancel-click' );
}
}
}
</script>
The parent component can listen to these events using the
v-on
directive:<ButtonGroup v-on:ok-click="accept" v-on:cancel-click="reject"/>
You can also use events to pass data to the parent component:
NameInput.vue
<template>
<Box>
<Text>Enter your name:</Text>
<TextInput v-bind:value="value" v-on:input="emitInput"/>
<Box>
</template>
<script>
export default {
props: {
value: String
},
methods: {
emitInput( newValue ) {
this.$emit( 'input', newValue );
}
}
}
</script>
The parent component can use the following code to update the value of its data property:
<NameInput v-bind:value="name" v-on:input="name = $event"/>
Note that the child component cannot simply modify the
value
property, because that will not automatically update the data in the parent component.The
v-model
directive can also be used with custom components. By default, it binds the value
property and the input
event to the specified property of the parent component, so the above code is equivalent to:<NameInput v-model="name"/>
When your window contains a complex hierarchy of custom components, passing data around using properties and events may become difficult to manage. In such case consider using a state management library, such as Vuex.
You can use slots to pass contents from the parent component to a child component. For example, let's assume that we have this simple child component:
NavigationButton.vue
<template>
<Button v-on:click="navigate">
<slot></slot>
<Button>
<template>
We can use it like this:
<NavigationButton>About</NavigationButton>
The "About" text is inserted in place of the
<slot>
element. The slot contents can include not just text, but also other elements, including built-in components and custom components.The special
<component>
element can be used to dynamically switch between components. For example, you can replace the entire contents of a window without having to close it and create a new window:<template>
<Window title="Example" width="640" height="480" margined>
<component v-bind:is="currentComponent"/>
</Window>
</template>
The
currentComponent
property can contain either the name of a registered component, or the options object which defines a component.Last modified 4yr ago