2. ● Created by Evan You - A former Google
employee
● Vue Introduced as “progressive frontend
framework”
● First released on Oct 2015
● Latest release is 2.5.x
5. Vue.js is declarative and reactive
<div id="app">
{{ message }}
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
<div id="app-2">
<span v-bind:title="message">
Hover your mouse over me for a few
seconds
to see my dynamically bound title!
</span>
</div>
var app2 = new Vue({
el: '#app-2',
data: {
message: 'You loaded this page on ' +
new Date().toLocaleString()
}
})
6. The Vue Instance
<div id="app">
{{ message }}
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
● Vue Components is a Vue instance
● Root component must declare the el option, which is the css selector of
the HTML element in the a page that will contain the Vue rendered
artifacts
● The Vue constructor get an options object which contains the component
configuration, some of the main configurations:
○ name
○ data
○ props
○ methods
○ computed
○ el
○ template
○ Lifecycle hooks
○ events
○ watch
○ ...
8. The Vue Component
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count
}} times.</button>'
})
<div id="components-demo">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
● Components are reusable
Vue instances with a name
● The data option MUST be a
function (otherwise is will
affect ALL the instances of
the component)
● Components are organized in
a tree structure
9. template and directives
<span>Message: {{ msg }} </span>
<span>Message: {{ message. split('').reverse().join('') }}</span>
<p v-if="seen">Now you see me </p>
<a v-bind:href="url">Click me</a>
<a v-on:click="doSomething">Click me</a>
<form v-on:submit.prevent="onSubmit"></form>
<a :href="url">Click me</a>
<a @click="doSomething">Click me</a>
<a v-mycoolcustomdirective="cooldata">Click me</a>
● Based on the Mustache
syntax
● Common directives:
○ v-if
○ v-for
○ v-show
○ v-once
○ v-html
○ v-bind for data binding
(use : for shorthand)
○ v-on for events (use @
for shorthand)
● You can also implement your
own custom directives
10. Conditional Rendering
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
<h1 v-show="ok">Hello!</h1>
● Use v-if directive for
conditional rendering
● Use v-else-if and v-else for
if-else logic
● Use v-show directive for
conditional visibility
● v-if will render the element
only if the condition is met,
v-show will render the
element anyway but will
toggle its visibility.
As a thumb rule it is better to
use v-if
Use v-show only for a reason.
e.g. the component state
should be preserved
11. List Rendering
<ul id="example-1">
<li v-for="item in items">
{{ item.message }}
</li>
</ul>
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }}: {{ value }}
</div>
<ul id="v-for-object" class="demo">
<!--{firstName: 'John',lastName: 'Doe',age: 30}-->
<li v-for="value in object">
{{ value }}
</li>
</ul>
<div v-for="item in items" :key="item.id">
<!-- content -->
</div>
<!-- v-if will run for each v-for integration -->
<li v-for="item in items" v-if="item.exists">
<!-- content -->
</div>
● Use v-for directive for list
rendering
● Syntax is:
v-for="item in items"
Where items is the data
array and item is the
element alias
● As Vue uses the “in-place
patch” strategy it is best to
bind the key attribute with
unique key.
This will allow Vue to
optimize the list rendering
when reacting to data
changes
Starting 2.2.0 it is required for
looping over components
12. v-for and v-if
Bad:
<!-- v-if will run for each v-for integration -->
<li v-for="item in items" v-if="item.exists">
<!-- content -->
</li>
Good:
<ul v-if="items.length">
<li v-for="item in items">
<!-- content -->
</li>
</ul>
● v-for as higher priority than
v-if, meaning the v-if
calculation will take place for
each item on the list
● Optimize it by wrapping the
entire loop with v-if
13. Events
<div>
<button v-on:click= "counter += 1" >Add 1</button>
<p>The button above has been clicked {{ counter }} times.</p>
</div>
<div>
<!-- `greet` is the name of a method defined in the component -->
<button v-on:click= "greet">Greet</button>
</div>
<div>
<button @click= "say('hi')" >Say hi</button>
<button @click= "say('what')" >Say what</button>
</div>
<input v-on:keyup.enter= "submit">
this.$emit('myEvent')
<my-component v-on:my-event= "doSomething" ></my-component>
● Use v-on directive to listen to
DOM and custom events
● A listener can be both
method or inline handler
● Vue provides Event Modifiers
for handling a specific variant
of event (for instance: keyup
of the Enter key)
● A component may also emit a
custom event using the
this.$emit method - use the
name of the event in camel
case
● You can use @ as a
shorthand for Events
14. Data distribution: parent to child
Parent:
new Vue({
el: '#blog-post-demo',
data: {
posts: [
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' },
]
}
})
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:title="post.title">
</blog-post>
● A parent component passes
the data to its child
component using props
● A component should declare
its own props
● props declaration has many
useful capabilities such as
type declaration, validators,
default value etc.
Component:
Vue.component('blog-post', {
props: {
title: {
type: String,
required: true,
}
},
template: '<h3>{{ title }}</h3>'
})
15. Data distribution: child to parent
Parent:
new Vue({
el: '#blog-post-demo',
data: {
posts: [...],
postFontSize: 1
},
methods: {
onEnlargeText: (enlargeAmount) => {
this.postFontSize += enlargeAmount
}
}
})
<div :style="{ fontSize: postFontSize + 'em' }">
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
v-on:enlarge-text="onEnlargeText">
</blog-post>
</div>
● Sometime we would like the child component to pass data to is parent - for this we will use Events
Component:
Vue.component('blog-post', {
props: {
post: {
type: Object,
required: true,
}
},
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>
<button
v-on:click="$emit('enlarge-text', 0.1)">
Enlarge text
</button>
<div v-html="post.content"></div>
</div>
`
})
16. Data distribution: v-model
● v-model is a directive that allows two way data binding for component
● v-model is automatically supported for components that implements the value prop and the input event
Native elements:
<input
v-bind:value="searchText"
v-on:input="searchText =
$event.target.value">
Is the same as:
<input v-model= "searchText" >
Custom elements:
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input',
$event.target.value)">
`
})
Usage:
<custom-input v-model="searchText"></custom-input>
17. Slots
● Slots allows to inject free content into your component (text, html and other components)
Template of <navigation-link> component:
<a
v-bind:href="url"
class="nav-link">
<slot></slot>
</a>
Usage:
<navigation-link url="/profile">
Your Profile
</navigation-link>
<a href="/profile" class="nav-link">
Your Profile
</a>
Usage:
<navigation-link url="/profile">
<!-- Use a component to add an icon -->
<font-awesome-icon name="user"></font-awesome-icon>
Your Profile
</navigation-link>
<a href="/profile" class="nav-link">
<span class="fs fs-user"></span>
Your Profile
</a>
18. Named Slots
● Allows a component to have multiple slots
Template of <base-layout>
component:
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer">Default
footer</slot>
</footer>
</div>
Usage 1:
<base-layout>
<template slot="header">
<h1>Here might be a page
title</h1>
</template>
<p>A paragraph for the main
content.</p>
<p>And another one.</p>
<template slot="footer">
<p>Here's some contact
info</p>
</template>
</base-layout>
Usage 2:
<base-layout>
<h1 slot="header">Here might
be a page title</h1>
<p>A paragraph for the main
content.</p>
<p>And another one.</p>
<p slot="footer">Here's some
contact info</p>
</base-layout>
19. Scope of the Slots
As the content of the slot is declared in the parent component - it
inherits the parent scope, for example:
In this example user if declared in the parent component and
navigation-link cannot access it.
But what if you do want to the slot to access the child component
data?
<navigation-link url="/profile" :class="user.class">
Logged in as {{ user.name }}
</navigation-link>
20. Scoped Slots
● Introduced on v2.1.0
● Scoped Slots allows to define the scope of the slot
Template of <todo-list> component:
<ul>
<li
v-for="todo in todos"
v-bind:key="todo.id">
<!-- passing the todo as slot
prop -->
<slot v-bind:todo="todo">
<!-- Fallback content -->
{{ todo.text }}
</slot>
</li>
</ul>
Usage:
<todo-list v-bind:todos="todos">
<!-- Define `slotProps` as the name of our slot scope -->
<template slot-scope="slotProps">
<!-- Define a custom template for todo items, using -->
<!-- `slotProps` to customize each todo. -->
<span v-if="slotProps.todo.isComplete">✓</span>
{{ slotProps.todo.text }}
</template>
</todo-list>
21. Dynamic Components
● Sometimes, it’s useful to
dynamically switch between
components
● In this example the content is
changes on the selected tabs
● currentTabComponent prop can
hold either the component name
or object
<!-- Component changes when currentTabComponent changes
-->
<component v-bind:is= "currentTabComponent" ></component>
22. Computed properties
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
● Instead of using complex logic in the
template - use computed props
● they are considered as read only
properties of the component, therefore
you refer it as property, not as a
function ( no () )
● Computed props are cached - it will not
be re-evaluated if no dependency has
changed (as opposed to methods)
● Although computed props are enough
in most of the use cases, Vue offers
also a watch mechanism for handling
special cases.
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// a computed getter
reversedMessage: function () {
// `this` points to the vm instance
return this.message.split('').reverse().join('')
}
}
})
23. Reactivity rules
● Vue listen to changes only for properties
that were defined in the data option -
under the hoods it uses
Object.defineProperty for tracking
changes
● You cannot dynamically add properties to
data - declare empty placeholders for
future usage
● Vue cannot identify deep changes on data
- use Vue.set or re-assign the changes
property
var vm = new Vue({
data: {
// declare message with an empty value
message: ''
},
template: '<div>{{ message }}</div>'
})
vm.message = 'Hello!'
vm.message2 = 'Hello!' // not reactive
this.someObject.b = 2 // not recative
// following are recative
this.$set(this.someObject, 'b', 2) // alias of Vue.set
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2
})
25. Single File Components
● *.vue extension
● All the component assets are on the same
file - no jumping between template/js/css
files
● IDE plugins for syntax highlighting
● As the project got bigger it keeps it more
organized and reduce the amount of files
and layers.