Difficulty Level: Intermediate
Prerequisite: You should be familiar with Vue.js options and component-based architecture.
Takeaway: This article gives you an understanding of assumptions and shorthands used in Vue.js.
In this article we cover the below topics with example
- 1. Component name casing
- 2. V-bind in template
- 3. V-on in template
- 4. Function call with event
- 5. Event emit with event
- 6. Watch to get the old state and new state
- 7. Filters with multiple props
- 8. Props declaration
- 9. Dynamic Component Props
- 10. Object as props
- 11. Style binding in template
Let's create a simple Vue application using Vue CLIcommand, we use this application to demonstrate all the items listed below.
To create Vue application, run the commands below:
1
2
3
4
5
6
7
8
| > npm init vue@latest
// Enter <your-project-name>
// Select the required options
> cd <your-project-name>
> npm install
> npm run dev
|
1. Component name casing
Vue components are independent and reusable pieces in the web page. Let's create a component named “WelcomeToVue.vue” and import the component to the“HomeView.vue” page.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| <template>
<main>
<!-- Component name casing accepts camelCase, PascalCase, kebab-case -->
<welcomeToVue /> <!-- camelCase -->
<WelcomeToVue /> <!-- PascalCase -->
<welcome-to-vue /> <!-- kebab-case -->
<!-- similar to HTML dom elements, component with no attributes can be self closing component -->
<welcome-to-vue />
<!-- instead of -->
<welcome-to-vue></welcome-to-vue>
<!-- Since there are many ways of writing components in templates, which one to use? -->
<!-- Unfortunately, due to HTML's case insensitivity, DOM templates must still use kebab-case. -->
<welcome-to-vue />
<!-- or -->
<welcome-to-vue></welcome-to-vue>
<!-- Alias name for component name -->
<custom-component-name />
</main>
</template>
<script>
import WelcomeToVue from '@/components/WelcomeToVue.vue'
export default {
name: 'home-view',
components: {
WelcomeToVue,
CustomComponentName: WelcomeToVue,
}
}
</script>
|
2. Data binding in template
To create dynamic content of the web page, we can use javascript variables directly in the HTML element using v-bind.
The javascript variables are nothing but reactive data properties or computed properties declared in Vue options.
To render javascript variables directly in HTML content we can use mustache syntax, it's the most basic form of data binding.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| <template>
<main>
<p>Raw content in HTML</p>
<!-- The mustache tag will be replaced with the value of message property from component instance -->
<!-- It will also be updated whenever message property changes -->
<p>{{ message }}</p>
<!-- Mustache syntax also renders valid javascript expression -->
<span>{{ firstName + ' ' + lastName }}</span>
<p>{{ true ? fullName : lastName }}</p>
<!-- we can use function call while rendering template, it sets the returned value, if not set to undefined -->
<p>{{ reverseName(firstName) + ' ' + reverseName(lastName) }}</p>
<!-- Computed property is just like data property, it updates automatically when dependent property is updated -->
<p>{{ fullName }}</p>
</main>
</template>
<script>
export default {
name: 'HomeView',
data () {
return {
message: 'Hello World',
firstName: 'Evan',
lastName: 'You'
}
},
computed: {
fullName () {
return this.firstName + ' ' + this.lastName
}
},
methods: {
reverseName(text) {
return text.split('').reverse().join('')
}
}
}
</script>
|
To render Javascript variable directly in a valid HTML attribute we use v-bind directive. It takes the advantage of binding dynamic data directly to any attribute just by prepending the directive v-bind: to the attribute, the shorthand representation for v-bind: is just prepend the attribute with(colon): alone. Because attributes are used in each tag and throughout the template
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
| <template>
<main>
<!-- v-bind: is prepend to any valid HTML attribute -->
<div v-bind:id="dynamicId"></div>
<!-- Instead of v-bind the shorthand representation is -->
<div :id="dynamicId"></div>
<!-- the html output rendered is -->
<div id="homePage"></div>
<!-- the common usages of v-bind in web application development -->
<a :href="redirectLink.path" :target="redirectLink.target">
{{redirectLink.label}}
</a>
<!-- similar to mustache syntax v-bind also accepts valid javascript expression -->
<p :title="dynamicTitle"></p>
<p :title="true ? dynamicTitle : 'some title'"></p>
<p :title="dynamicTitle + ' append title name'"></p>
<img :src="image.path" :alt="image.altText">
<form :action="form.submitPath" :method="form.method">
<label :for="form.nameField.name">{{form.nameField.label}}:</label>
<input :type="form.nameField.type" :id="form.nameField.username" :name="form.nameField.inputName" :value="form.nameField.value">
<input type="submit" value="Submit">
</form>
</main>
</template>
<script>
export default {
name: 'HomeView',
data () {
return {
dynamicId: 'homePage',
redirectLink: {
target: '_self',
path: 'https://somelink.com',
label: 'click here'
},
image: {
path: 'https://somelink.com/image.jpg',
altText: 'some alternate text to image'
},
form: {
submitPath: 'https://somelink.com',
method: 'post',
nameField: {
label: 'Name',
labelFor: 'name',
type: 'text',
id: 'username',
inputName: 'name',
value: ''
}
}
}
}
}
</script>
|
3. V-on in template
We can listen to user events in HTML templates and trigger javascript methods or expressions. The events can be native HTML DOM events or user-defined custom events.
The usage would be v-on:click="javascriptExpression"
or with the shorthand representation, @click="handler"
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| <template>
<main>
<!-- v-on: is prepend to any native HTML DOM event -->
<div v-on:click="userClicked"></div>
<!-- Instead fo v-on the shorthand representation is -->
<div @click="userClicked"></div>
<!-- On event trigger, we can also have valid javascript expression -->
<div @click="alert('user clicked')"></div>
<div @click="true ? alert('truthy') : alert('falsy')"></div>
</main>
</template>
<script>
export default {
name: 'HomeView',
methods: {
userClicked() {
alert('user clicked')
}
}
}
</script>
|
4. Function call with event
On a user event, the method handler receives native DOM event as the first argument by default. Here we can see different use cases of method handler with event.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| <template>
<main>
<!-- when event method handler triggers without any argument, by default the first argument of calling function is the DOM native event -->
<button @click="clickHandlerWithoutArguments">Click here</button>
<!-- when event method handler triggers with argument, the native DOM event is overridden with the argument passed -->
<button @click="clickHandlerWithArguments(1)">Click here</button>
<!-- what if we want to preserve events and pass additional arguments? -->
<!-- we can use $event on method handler -->
<button @click="clickHandlerWithEventAndArguments($event, 1)">Click here</button>
</main>
</template>
<script>
export default {
name: 'HomeView',
methods: {
clickHandlerWithoutArguments(event) {
console.log(event)
},
clickHandlerWithArguments(payload) {
console.log(payload)
},
clickHandlerWithEventAndArguments(event, payload) {
console.log(event, payload)
}
}
}
</script>
|
5. Event emits with event
Similar to native DOM events, we can also emit custom-defined events from the child component to the parent component, these custom events cannot be defined in native DOM elements. Here we can see different use cases of method handlers with custom events emitting from the child component to the parent component.
Child Component
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| <template>
<div>
<button @click="userClicked">Click Here</button>
</div>
</template>
<script>
export default {
name: 'WelcomeToVue',
methods: {
userClicked() {
this.$emit('customEvent', 1, 2)
}
}
}
</script>
|
Parent Component
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| <template>
<main>
<!-- when no arguments is defined, by default it take the list of arguments from child -->
<welcome-to-vue @custom-event="methodToCall" />
<!-- output is // 1, 2 -->
<!-- when arguments is defined, it resets the arguments received from child -->
<welcome-to-vue @custom-event="methodToCall(5)" />
<!-- output is // 5, undefined -->
<!-- To preserve the argument from child and add extra argument in parent -->
<welcome-to-vue @custom-event="methodToCall($event, 5)" />
<!-- output is // 1, 5 -->
<!-- The expected output is // 1, 2, 5 -->
<!-- To preserve the arguments from child and add extra arguments in parent -->
<!-- To preserve the argument from child and add extra argument in parent, use object -->
<!-- this.$emit('custom-event', { a: 1, b: 2 }) in child component-->
<welcome-to-vue @custom-event="methodToCall({ ...$event, c: 5 })" />
<!-- output is // { a: 1, b: 2, c: 5 } -->
</main>
</template>
<script>
import WelcomeToVue from '@/components/WelcomeToVue.vue'
export default {
name: 'HomeView',
components: {
WelcomeToVue
},
methods: {
methodToCall(arg1, arg2) {
console.log(arg1, arg2)
}
}
}
</script>
|
6. Watch to get old state and new state
Watchers acts as observers in Vue. when a data property is set with a new value watcher is called. We can take this advantage and perform some actions, it also maintains the old state and new state of the data change.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| <template>
<main>
<!-- on click message is updated, in watcher we can listen to old value and new value changed -->
<button @click="updateMessage">update Message</button>
<!-- similarly on update of nested object old and new value will be the same.
Deep watch requires traversing all nested properties in the watched object,
and can be expensive when used on large data structures.
Use it only when necessary and beware of the performance implications. -->
<button @click="updateObject">update Object</button>
</main>
</template>
<script>
export default {
name: 'HomeView',
data () {
return {
message: 'Old',
jsonObject: {
name: 'Vue',
age: 5
}
}
},
methods: {
updateMessage () {
this.message = 'New'
},
updateObject () {
this.jsonObject.age = 6
}
},
watch: {
message(newValue, oldValue) {
console.log(oldValue, newValue)
},
jsonObject: {
handler(newValue, oldValue) {
console.log(oldValue, newValue)
},
deep: true
}
}
}
</script>
|
7. Filters with multiple props
A Filter is a simple javascript function used to format the data property or computed property in a template. Here we can see the different usages of filters.
Note: Filter option is available only in Vue 2 and removed in Vue 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| <template>
<main>
<!-- Filters are used in two places: mustache interpolations and v-bind: expressions -->
<!-- Filters should be append to the end of javascript expression with 'PIPE' symbol -->
<div>{{ message | uppercase }}</div>
<div v-bind:id="message | kebabCase">{{ message}}</div>
<!-- By Default first argument is the value evaluated from javascript expression -->
<!-- what if we want to send additional arguments -->
<div>{{ message | filterWithArguments(1, 2) }}</div>
<!-- output is 'Hello Vue 1 2' -->
<!-- Filters can be chained with another filter -->
<!-- The output of javascript expression is passed to filterWithArguments and the result of first filter is passed to kebabCase -->
<div>{{ message | filterWithArguments(1, 2) | kebabCase }}</div>
<!-- the final output is 'Hello-Vue-1-2' -->
</main>
</template>
<script>
export default {
name: 'HomeView',
data () {
return {
message: 'Hello Vue'
}
},
filters: {
uppercase (value) {
return value.toUpperCase()
},
kebabCase (value) {
return value.split(' ').join('-')
},
filterWithArguments (value, arg1, arg2) {
return value + ' ' + arg1 + ' ' + arg2
}
}
}
</script>
|
8. Props declaration
Props stands for properties in Vue. The data properties of the parent component can be accessed by the child component via props. Props are read-only properties (one way data flow form parent to child). If data property in the parent component updates, it automatically updates the child component. Here we can see the different ways of declaring props in child component.
Parent Component:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| <template>
<main>
<!-- The naming convention for props in parent component is kebab-case to align with HTML attributes -->
<WelcomeToVue :welcome-message="welcomeMessage" />
<!-- we can also pass props as static values to child component -->
<WelcomeToVue :welcome-message="'Hello Vue'" />
<!-- Static value of string can be passed without v-bind expression -->
<WelcomeToVue welcome-message="Hello Vue" />
<!-- Other than string static value requires v-bind expression got Vue to evaluate -->
<WelcomeToVue :id="12" />
<!-- The boolean value prop is true by default if value is not set -->
<WelcomeToVue is-active />
<!-- To explicitly set boolean value dynamically v-bind can be used -->
<WelcomeToVue :is-active="isActive" />
</main>
</template>
<script>
import WelcomeToVue from '@/components/WelcomeToVue.vue'
export default {
name: 'HomeView',
components: {
WelcomeToVue
},
data () {
return {
welcomeMessage: 'Hello Vue',
name: 'some product',
id: 11,
isActive: true
}
}
}
</script>
|
Child Component:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| <template>
<div>
<div>{{ id }}</div>
<div>{{ name }}</div>
<div>{{ isActive }}</div>
</div>
</template>
<script>
export default {
name: 'WelcomeToVue',
// props can be decalred using array of string
props: ['id', 'name', 'isActive']
// props can be declared along with datatype
props: {
id: Number,
name: String,
isActive: Boolean
}
// props can be declared along with datatype and default value
props: {
id: {
type: Number,
default: 0
}
}
// props can also be declared with multiple data type
props: {
id: [Number, Boolean]
}
// props can also be declared as a mandatory prop
props: {
id: {
type: Number,
default: 0,
required: true
}
}
}
</script>
|
9. Dynamic Component Props
Vue has in build component name 'component', which has ability to mount the component dynamically in runtime using component name as string.
1
2
| <!-- Its not mandatory that child component should declare all props passed from parent -->
<component :is="dynamicComponentName" :id="id" :name="name" />
|
Let's take two child component names childA and childB. The component childA has props (id, name) declared and childB has no props.
The props can be passed from dynamic components to children. Child component looks for props from the parent component. If additional props are present in parent component but not declared in child then it just ignore those props.
10. Object as props
Object can be passed directly to child component without passing individual property.
1
2
3
4
5
| <!-- we're passing user object to child component { id: 1, name: 'username', isActive: true } -->
<WelcomeToVue v-bind="user" />
<!-- In child component we can directly access the properties of user as props -->
props: ['id', 'name', 'isActive']
|
11. Style binding in template
We can dynamically render styles and classes using v-bind: expression. Here we can see different ways of rendering styles and classes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
| <template>
<main>
<!-- Style can be binding as object with key value pair as css properties and corresponding values -->
<div :style="{'background-color': 'red'}">Hello Vue</div>
<!-- output -->
<div style="background-color: red;">Hello Vue</div>
<!-- The css property can be given as camel casing instead of kebab-case for javascript json keys without quotes -->
<div :style="{backgroundColor: 'red'}">Hello Vue</div>
<!-- output -->
<div style="background-color: red;">Hello Vue</div>
<!-- Styles can be a valid javascript expression -->
<div :style="'background-color: ' + styleObj.backgroundColor">Hello Vue</div>
<!-- output -->
<div style="background-color: red;">Hello Vue</div>
<div :style="{ ...styleObj, color: 'white' }">Hello Vue</div>
<!-- output -->
<div style="background-color: red;color: white;">Hello Vue</div>
<!-- Classes are dynamically set with v-bind directive -->
<div :class="className">Hello Vue</div>
<!-- output -->
<div class="text-danger">Hello Vue</div>
<div :class="multipleClassNames">Hello Vue</div>
<!-- output -->
<div class="text-danger font-bold">Hello Vue</div>
<div :class="[...multipleClassNames, 'class-name']">Hello Vue</div>
<!-- output -->
<div class="text-danger font-bold class-name">Hello Vue</div>
<div :class="{'text-danger': true, 'font-bold': false}">Hello Vue</div>
<!-- output -->
<div class="text-danger">Hello Vue</div>
<div :class="['text-danger', 'font-bold']">Hello Vue</div>
<!-- output -->
<div class="text-danger font-bold">Hello Vue</div>
<div :class="[{'text-danger': true}, 'font-bold', ...multipleClassNames]">Hello Vue</div>
<!-- output -->
<div class="text-danger font-bold text-danger font-bold">Hello Vue</div>
<div :class="'text-danger' + ' font-bold'">Hello Vue</div>
<!-- output -->
<div class="text-danger font-bold">Hello Vue</div>
<div :class="true ? 'text-danger' : 'font-bold'">Hello Vue</div>
<!-- output -->
<div class="text-danger">Hello Vue</div>
</main>
</template>
<script>
export default {
name: 'HomeView',
data () {
return {
styleObj: {
backgroundColor: 'red'
},
className: 'text-danger',
multipleClassNames: ['text-danger', 'font-bold']
}
}
}
</script>
<style type="text/css">
.text-danger {
background-color: red;
color: white;
}
.font-bold {
font-weight: bold;
}
</style>
|
You need a help building a web application? Drop us a line here.
Written by:
Chandra Sekar
Senior Frontend Developer
Chandra is an exceptional Vue.js frontend developer who consistently delivers outstanding results. With a keen eye for detail and a deep understanding of Vue.js, Chandra transforms design concepts into seamless and visually captivating user interfaces.
Chandra is an exceptional Vue.js frontend developer who consistently delivers outstanding results. With a keen eye for detail and a deep understanding of Vue.js, Chandra transforms design concepts into seamless and visually captivating user interfaces.