You are on page 1of 144

1

2
:key

3
:key v-for

4
v-if

v-if

template v-if

<template>
<my-component v-if="renderComponent" />
</template>

script nextTick

5
<script>
export default {
data() {
return {
renderComponent: true,
};
},
methods: {
forceRerender() {
// Remove my-component from the DOM
this.renderComponent = false;

this.$nextTick(() => {
// Add the component back in
this.renderComponent = true;
});
}
}
};
</script>

renderComponent true my-component

forceRerender renderComponent

false

my-component v-if

false

renderComponent true

6
v-if true

my-component

renderComponent

my-component

created mounted

7
nextTick

forceRerender() {
// Remove my-component from the DOM
this.renderComponent = false;

// If you like promises better you can


// also use nextTick this way
this.$nextTick().then(() => {
// Add the component back in
this.renderComponent = true;
});
}

forceUpdate

8
forceUpdate

9
// Globally
import Vue from 'vue';
Vue.forceUpdate();

// Using the component instance


export default {
methods: {
methodThatForcesUpdate() {
// ...
this.$forceUpdate(); // Notice we have to use a $ here
// ...
}
}
}

forceUpdate

key

10
key

created mounted

11
key

const people = [
{ name: 'Evan', age: 34 },
{ name: 'Sarah', age: 98 },
{ name: 'James', age: 45 },
];

<ul>
<li v-for="(person, index) in people" :key="index">
{{ person.name }} - {{ index }}
</li>
</ul>

// Outputs
Evan - 0
Sarah - 1
James - 2

Evan - 0
James - 1

12
const people = [
{ id: 'this-is-an-id', name: 'Evan', age: 34 },
{ id: 'unique-id', name: 'Sarah', age: 98 },
{ id: 'another-unique-id', name: 'James', age: 45 },
];

<ul>
<li v-for="person in people" :key="person.id">
{{ person.name }} - {{ person.id }}
</li>
</ul>

13
<template>
<component-to-re-render :key="componentKey" />
</template>

14
export default {
data() {
return {
componentKey: 0,
};
},
methods: {
forceRerender() {
this.componentKey += 1;
}
}
}

forceRerender componentKey

15
16
Data

data

data

17
<template>

<template>
<my-component cool-prop="hello world"></my-component>
</template>

18
cool-prop

"hello world"

my-component

data

count data

19
<template>
<div>
{{ count }}
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
</template>

export default {
name: 'Counter',
data() {
return {
// Initialized to zero to begin
count: 0,
}
},
methods: {
increment() {
this.count += 1;
},
decrement() {
this.count -= 1;
}
}
}

20
setState

data

methods: {
increment() {
this.count += 1;
},
decrement() {
this.count -= 1;
}
}

21
count

export default {
props: ['propA', 'propB'],
data() {
return {
dataA: 'hello',
dataB: 'world',
};
},
};

22
this.props.propA this.data.dataA props data

this.propA this.dataA

methods: {
coolMethod() {
// Access a prop
console.log(this.propA);

// Access our data


console.log(this.dataA);
}
}

props

data

23
export default {
props: ['secret'],
data() {
return {
secret: '1234',
};
},
methods: {
printSecret() {
// Which one do we want?
console.log(this.secret);
}
}
};

data

ContactInfo

24
// ContactInfo
<template>
<div class="container">
<div class="row">
Email: {{ emailAddress }}
Twitter: {{ twitterHandle }}
Instagram: {{ instagram }}
</div>
</div>
</template>

export default {
name: 'ContactInfo',
props: ['emailAddress', 'twitterHandle', 'instagram'],
};

ContactInfo emailAddress

twitterHandle instagram

ProfilePage

// ProfilePage
<template>
<div class="profile-page">
<div class="avatar">
<img src="user.profilePicture" />
{{ user.name }}
</div>
</div>
</template>

25
export default {
name: 'ProfilePage',
data() {
return {
// In a real app we would get this data from a server
user: {
name: 'John Smith',
profilePicture: './profile-pic.jpg',
emailAddress: 'john@smith.com',
twitterHandle: 'johnsmith',
instagram: 'johnsmith345',
},
}
}
};

ProfilePage

ProfilePage

ContactInfo

ContactInfo ProfilePage

26
// Import the component
import ContactInfo from './ContactInfo.vue';

export default {
name: 'ProfilePage',

// Add it as a dependency
components: {
ContactInfo,
},

data() {
return {
user: {
name: 'John Smith',
profilePicture: './profile-pic.jpg',
emailAddress: 'john@smith.com',
twitterHandle: 'johnsmith',
instagram: 'johnsmith345',
},
}
}
};

<template>

27
// ProfilePage
<template>
<div class="profile-page">
<div class="avatar">
<img src="user.profilePicture" />
{{ user.name }}
</div>

<!-- Add component in with props -->


<contact-info
:email-address="emailAddress"
:twitter-handle="twitterHandle"
:instagram="instagram"
/>

</div>
</template>

ContactInfo

ContactInfo ProfilePage

ProfilePage ContactInfo

28
29
deep

watch

30
immediate handler

colour

export default {
name: 'ColourChange',
props: ['colour'],
watch: {
colour()
console.log('The colour has changed!');
}
}
}

31
computed

32
data

<template>

data

watch

33
const array = [1, 2, 3, 4];
// array = [1, 2, 3, 4]

array.push(5);
array.push(6);
array.push(7);
// array = [1, 2, 3, 4, 5, 6, 7]

array

array array

34
deep true

export default {
name: 'ColourChange',
props: {
colours: {
type: Array,
required: true,
},
},
watch: {
colours: {
// This will let Vue know to look inside the array
deep: true,

// We have to move our method to a handler field


handler()
console.log('The list of colours has changed!');
}
}
}
}

handler

35
MovieData

movie

36
export default {
name: 'MovieData',
props: {
movie: {
type: String,
required: true,
}
},
data() {
return {
movieData: {},
}
},

watch: {
// Whenever the movie prop changes, fetch new data
movie(movie) {
// Fetch data about the movie
fetch(`/${movie}`).then((data) => {
this.movieData = data;
});
}
}
}

movie

movie

37
immediate

watch: {
// Whenever the movie prop changes, fetch new data
movie: {
// Will fire as soon as the component is created
immediate: true,
handler(movie) {
// Fetch data about the movie
fetch(`/${movie}`).then((data) => {
this.movieData = data;
});
}
}
}

handler

immediate

deep

38
handler

handler

immediate deep

watch: {
movie: {
handler(movie) {
// Fetch data about the movie
fetch(`/${movie}`).then((data) => {
this.movieData = data;
});
}
}
}

39
watch: {
movie(movie) {
// Fetch data about the movie
fetch(`/${movie}`).then((data) => {
this.movieData = data;
});
}
}

String

movie actor

40
watch: {
// Whenever the movie prop changes, fetch new data
movie {
handler: 'fetchData'
},
// Whenever the actor changes, we'll call the same method
actor: {
handler: 'fetchData',
}
},

methods: {
// Fetch data about the movie
fetchData() {
fetch(`/${this.movie}/${this.actor}`).then((data) => {
this.movieData = data;
});
}
}

41
42
43
colour

export default {
name: 'ColourChange',
props: ['colour'],
watch: {
colour()
console.log('The colour has changed!');
}
}
}

data()

localstorage

44
firstName

lastName fullName

export default {
name: 'FullName',
props: ['firstName', 'lastName'],
computed: {
fullName() {
return this.firstName + ' ' + this.lastName;
}
}
}

firstName lastName

fullName

45
export default {
name: 'FullName',
props: ['firstName', 'lastName'],
data() {
return {
fullName: this.firstName + ' ' + this.lastName,
};
},
watched: {
firstName() {
this.fullName = this.firstName + ' ' + this.lastName;
},
lastName() {
this.fullName = this.firstName + ' ' + this.lastName;
}
}
}

data()

46
47
MovieData

movie

export default {
name: 'MovieData',
props: {
movie: {
type: String,
required: true,
}
},
data() {
return {
movieData: {},
}
},

watch: {
// Whenever the movie prop changes, fetch new data
movie(movie) {
// Fetch data about the movie
fetch(`/${movie}`).then((data) => {
this.movieData = data;
});
}
}
}

movie

48
watch

49
data.nested.really.deeply.importantValue

computed() {
importantValue() {
return this.data.nested.really.deeply.importantValue;
},
}

this.importantValue

50
51
52
53
54
this is undefined

fetch axios

lodash underscore

55
this

methods: {
regularFunction: function() {
// Do some stuff
}
}

56
methods: {
shorthandFunction() {
// Do some stuff
}
}

this

this

57
methods: {
arrowFunction: () => {
// Do some stuff
}
}

this

this

this

this

this

58
data() {
return {
text: 'This is a message',
};
},
methods: {
arrowFunction: () => {
console.log(this.text); // ERROR! this is undefined
}
}

this

computed: {
location: () => window.location,
}

59
fetch axios

filter map reduce

// Fetching data
fetch('/getSomeData').then((data) => {
this.data = data;
});

// Functional methods
const array = [1, 2, 3, 4, 5];
const filtered = array.filter(number => number > 3);
const mapped = array.map(number => number * 2);
const reduced = array.reduce((prev, next) => prev + next);

60
this

this

this

this

61
data() {
return {
match: 'This is a message',
};
},
computed: {
filteredMessages(messages) {
console.log(this); // Our Vue component

const filteredMessages = messages.filter(


// References our Vue Component
(message) => message.includes(this.match)
);

return filteredMessages;
}
}

this.match

filteredMessages

axios

fetch

62
fetch axios

this

export default {
data() {
return {
dataFromServer: undefined,
};
},
methods: {
fetchData() {
fetch('/dataEndpoint')
.then(data => {
this.dataFromServer = data;
})
.catch(err => console.error(err));
}
}
};

63
.then(data => {
this.dataFromServer = data;
})

fetchData() this

this

this

dataFromServer

lodash

underscore

this is undefined

64
created() {
this.methodToDebounce = _.debounce(this.methodToDebounce, 500);
},
methods: {
methodToDebounce() {
// Do some things here
}
}

this.methodToDebounce()

65
window

this

this this

this

66
// This variable is in the window's scope
window.value = 'Bound to the window';

const object = {
// This variable is in the object's scope
value: 'Bound to the object',
arrowFunction: () => {
// The arrow function uses the window's scope for `this`
console.log(this.value); // 'Bound to the window'
},
regularFunction() {
// The regular function uses the object's scope for `this`
console.log(this.value); // 'Bound to the object'
}
};

this

this

const boundFunction = unboundFunction.bind(this);

67
68
69
v-model

70
71
export default {
props: {
movies: Array,
user: Object,
searchQuery: String,
}
}

movies user searchQuery

export default {
props: {
movies: Array,
user: Object,
searchQuery: String,
},
methods: {
sortMovies() {
this.movies = this.movies.sort();
}
}

72
export default {
props: {
movies: Array,
user: Object,
searchQuery: String,
},
methods: {
sortMovies() {
this.movies = this.movies.sort();
},
search(query) {
this.searchQuery = query;
}
}
}

73
export default {
props: {
movies: Array,
user: Object,
searchQuery: String,
},
methods: {
sortMovies() {
this.movies = this.movies.sort();
},
search(query) {
this.searchQuery = query;
},
addToFavourites(movie) {
this.user.favourites.push(movie);
}
}
}

74
75
76
ReversedList

77
<template>
<ul>
<li v-for="item in list" />
</ul>
</template>

export default {
name: 'ReversedList',
props: {
list: {
type: Array,
required: true,
}
},
created() {
// Mutating the prop :(
this.list = this.list.reverse();
}
};

78
<template>
<ul>
<li v-for="item in reversedList" />
</ul>
</template>

export default {
name: 'ReversedList',
props: {
list: {
type: Array,
required: true,
}
},
computed: {
reversedList() {
return this.list.reverse();
}
}
};

reversedList

li

reversedList

list

79
<template>
<div>
<!-- Add in a button that toggles our `reversed` flag -->
<button @click="reversed = !reversed">Toggle</button>
<ul>
<li v-for="item in reversedList" />
</ul>
</div>
</template>

80
export default {
name: 'ReversedList',
props: {
list: {
type: Array,
required: true,
}
},
data() {
return {
// Define a reversed data property
reversed: false,
};
},
computed: {
reversedList() {
// Check if we need to reverse the list
if (this.reversed) {
return this.list.reverse();
} else {
// If not, return the plain list passed in
return this.list;
}
}
}
};

reversed

reversed

true false

81
reversedList

reversed

reversedList

reversed list

v-model

v-model

v-model

82
<template>
<input v-model="firstName" />
</template>

export default {
props: {
firstName: String,
}
}

v-model

83
84
85
86
prop prop

data

87
<template>
<div>
{{ messag }}
</div>
</template>

export default {
data() {
return {
message: "Hello, world!"
};
}
};

88
<!-- Template for the Page component -->
<template>
<ul>
<link-item url="google.com" text="Google" />
<link-item url="yahoo.com" text="Yahoo" />
<link-item url="facebook.com" text="Facebook" />
</ul>
</template>

89
// Clean up some code by using another component
const LinkItem = {
props: ['url', 'text'],
template: `
<li>
<a
:href="url"
target="_blank"
>
{{ text }}
</a>
</li>
`
};

// Define the Page component


export default {
name: 'Page',
components: { LinkItem },
};

<li>

LinkItem

Page

methods: {
forceHTTPS(url) {
// ...
}
}

90
forceHTTPS

LinkItem

const LinkItem = {
props: ['url', 'text'],
template: `
<li>
<a
- :href="url"
+ :href="forceHTTPS(url)"
target="_blank"
>
{{ text }}
</a>
</li>
`
};

forceHTTPS LinkItem

Page

91
const LinkItem = {
props: ['url', 'text'],
+ methods: {
+ forceHTTPS(url) {
+ // Do some stuff...
+ }
+ },
template: `
<li>
<a
:href="forceHTTPS(url)"
target="_blank"
>
{{ text }}
</a>
</li>
`
};

92
93
94
95
hover :hover

.item {
background: blue;
}

.item:hover {
background: green;
}

96
mouseenter mouseenter

mouseover mouseenter

mouseover

97
v-on

v-on:event @event

<template>
<div
@mouseover="hover = true"
@mouseleave="hover = false"
/>
</template>

98
export default {
data() {
return {
hover: false,
};
}
}

hover

<template>
<div>
<span
@mouseover="hover = true"
@mouseleave="hover = false"
>
Hover me to show the message!
</span>
<span v-if="hover">This is a secret message.</span>
</div>
</template>

99
export default {
data() {
return {
hover: false,
};
}
}

Hover me to show the message!

<template>
<div>
<span
@mouseover="hover = true"
@mouseleave="hover = false"
:class="{ active: hover }"
>
Hover me to change the background!
</span>
</div>
</template>

100
export default {
data() {
return {
hover: false,
};
}
}

.active {
background: green;
}

<template>
<span>
Hover me to change the background!
</span>
</template>

span:hover {
background: green;
}

101
mouseover mouseleave

.native

<template>
<my-custom-component
@mouseover.native="hover = true"
@mouseleave.native="hover = false"
/>
</template>

export default {
data() {
return {
hover: false,
};
}
}

102
.native

103
104
105
<template>
<ChildComponent :function="myFunction" />
</template>

export default {
methods: {
myFunction() {
// ...
}
}
};

106
107
// ChildComponent
export default {
created() {
this.$emit('created');
}
}

<template>
<ChildComponent @created="handleCreate" />
</template>

export default {
methods: {
handleCreate() {
console.log('Child has been created.');
}
}
};

108
109
<!-- Parent -->
<template>
<ChildComponent :method="parentMethod" />
</template>

// Parent
export default {
methods: {
parentMethod() {
// ...
}
}
}

110
// Child
export default {
props: {
method: { type: Function },
},
mounted() {
// Use the parent function directly here
this.method();
}
}

111
<!-- Parent -->
<template>
<ChildComponent :method="parentMethod" />
</template>

// Parent
export default {
methods: {
parentMethod(valueFromChild) {
// Do something with the value
console.log('From the child:', valueFromChild);
}
}
}

112
// Child
export default {
props: {
method: { type: Function },
},
data() {
return { value: 'I am the child.' };
},
mounted() {
// Pass a value to the parent through the function
this.method(this.value);
}
}

<!-- Parent -->


<template>
<ChildComponent @send-message="handleSendMessage" />
</template>

113
// Parent
export default {
methods: {
handleSendMessage(event, value) {
// Our event handler gets the event, as well as any
// arguments the child passes to the event
console.log('From the child:', value);
}
}
}

// Child
export default {
props: {
method: { type: Function },
},
data() {
return { value: 'I am the child.' };
},
mounted() {
// Instead of calling the method we emit an event
this.$emit('send-message', this.value);
}
}

114
115
116
:class="classname" classname

117
<template>
<span class="description">
This is how you add static classes in Vue.
</span>
</template>

v-bind

118
<template>
<span v-bind:class="'description'">
This is how you add static classes in Vue.
</span>
</template>

v-bind

v-bind

<template>
<span :class="'description'">
This is how you add static classes in Vue.
</span>
</template>

119
<template>
<span
class="description"
:class="theme"
>
This is how you add static classes in Vue.
</span>
</template>

export default {
data() {
return {
theme: 'blue-theme',
};
}
};

.blue-theme {
color: navy;
background: white;
}

theme

v-bind

120
&&

<template>
<span
class="description"
:class="useTheme && theme"
>
This is how you add dynamic classes in Vue.
</span>
</template>

useTheme theme

false

true true

false

false

121
useTheme false false

useTheme theme

theme

theme

const result = expression ? ifTrue : ifFalse;

const result = expression


? ifTrue
: ifFalse;

122
expression true ifTrue

ifFalse

<template>
<span
class="description"
:class="darkMode ? 'dark-theme' : 'light-theme'"
>
This is how you add dynamic classes in Vue.
</span>
</template>

darkMode true dark-theme

light-theme

123
<template>
<span
class="description"
:class="[
fontTheme,
darkMode ? 'dark-theme' : 'light-theme',
]"
>
This is how you add dynamic classes in Vue.
</span>
</template>

fontTheme

darkMode

124
true

<template>
<span
class="description"
:class="{
'dark-theme': darkMode,
'light-theme': !darkMode,
]"
>
This is how you add dynamic classes in Vue.
</span>
</template>

dark-theme light-theme

darkMode

darkMode true dark-theme

light-theme !darkMode

125
false

darkMode light-theme

dark-theme

<template>
<MovieList
:movies="movies"
:genre="genre"
/>
</template>

126
:class

<template>
<MovieList
:movies="movies"
:genre="genre"
:class="darkMode ? 'dark-theme' : 'light-theme'"
/>
</template>

class

MovieList

props

MovieList class

127
Button

128
<template>
<span
class="description"
:class="theme"
>
This is how you add static classes in Vue.
</span>
</template>

export default {
data() {
return {
theme: 'blue-theme',
};
}
};

.blue-theme {
color: navy;
background: white;
}

Button

129
<template>
<button
@click="$emit('click')"
class="button"
:class="theme"
>
{{ text }}
</button>
</template>

export default {
props: {
theme: {
type: String,
default: 'default',
}
}
};

.default {}

.primary {}

.danger {}

Button theme

.default

primary .primary

130
<template>
<MovieList
:movies="movies"
:genre="genre"
:class="class"
/>
</template>

export default {
computed: {
class() {
return darkMode ? 'dark-theme' : 'light-theme';
}
}
};

131
132
133
mounted

mounted created

134
data

135
136
export default {
created() {
console.log('Component has been created!');
}
};

export default {
destroyed() {
console.log('Component has been destroyed!');
}
};

created mounted

137
mounted

mounted

mounted

data

created mounted

138
created mounted

created

created

created

export default {
data() {
cars: {},
},
created() {
fetch('/cars').then(cars => {
this.cars = cars;
});
}
};

created mounted created

139
created

mounted

created() {
console.log(this.$el);
},
mounted() {
console.log(this.$el);
}

undefined

this.$el

created

140
mounted

141

You might also like