Install NodeJS
https://nodejs.org/en/download/
Install Git
https://git-scm.com/downloads
Install Vue CLI
npm install -g @vue/cli
Install Vuex
npm install vuex --save
Install Vue Router
npm install vue-router --save
Create a Project
vue create vue-workshop
Dialog Option Selection:
- Default (Vue 2)
- Default (Vue 3)
Note: Use Vue 2 if you plan to use Vuex and/or Vue Router
Run Project
cd vue-workshop
Edit package.json (line 6)
vue-cli-service serve --host localhost
npm run serve
VueJS Basics
Reactivity
Reactivity.vue
<template>
<div class="pad-top">
The time is: {{ date }}
</div>
</template>
<script>
export default {
name: "Reactivity",
data() {
return {
date: null,
}
},
mounted() {
setInterval(() => {
this.date = (new Date()).toLocaleString()
}, 1000);
},
}
</script>
<style scoped>
</style>
Input Binding
InputBinding.vue
<template>
<div class="pad-top">
<span>Type your name:</span>
<input
class="margin-right"
v-model="name"
/>
</div>
<div class="pad-top">
Your name is {{ name }}!
</div>
</template>
<script>
export default {
name: "InputBinding",
data() {
return {
name: ‘’,
}
},
}
</script>
<style scoped>
.pad-top {
padding-top: 15px;
}
</style>
Element Visibility based on Input Binding
InputBindingVisibility.vue
<template>
<div class="pad-top">
<span>Type your name:</span>
<input
class="margin-right"
v-model="name"
/>
</div>
<div class="pad-top" v-show="name !== ''">
Your name is {{ name }}!
</div>
</template>
<script>
export default {
name: "InputBindingVisibility",
data() {
return {
name: ‘’,
}
},
}
</script>
<style scoped>
.pad-top {
padding-top: 15px;
}
</style>
Event Handling
EventHandling.vue
<template>
<div>
<button @click="toggleMe">Click me!</button>
</div>
</template>
<script>
export default {
name: "EventHandling",
methods: {
toggleMe() {
alert(‘I was clicked!’);
}
}
}
</script>
<style scoped>
</style>
Conditional Rendering
ConditionalRendering.vue
<template>
<div class="pad-top">
<button @click="toggleMe">Click me!</button>
</div>
<div class="pad-top" v-if="toggleDiv">
HOLA!
</div>
</template>
<script>
export default {
name: "ConditionalRendering",
data() {
return {
toggleDiv: false,
}
},
methods: {
toggleMe() {
this.toggleDiv = !this.toggleDiv
}
}
}
</script>
<style scoped>
.pad-top {
padding-top: 15px;
}
</style>
List Rendering
ListRendering.vue
<template>
<div>
<div>
Things to do:
</div>
<div>
<ul>
<li v-for="listItem in sampleList" :key="listItem.text">
{{ listItem.text }}
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: "ListRendering",
data() {
return {
sampleList: [
{ text: 'Eat' },
{ text: 'Sleep' },
{ text: 'Be awesome' }
]
}
},
}
</script>
<style scoped>
</style>
Vue Component Lifecycle
Vue Lifecycle Hooks
Vue Lifecycle Hooks
Hooks.vue
<template>
<div>
<h1>Hello!</h1>
</div>
</template>
<script>
export default {
name: "Hooks",
beforeCreate() {
// Called after the instance has been initialized
alert(‘beforeCreate triggered.’);
},
created() {
// Called after the instance is created
alert(‘created triggered.’);
},
beforeMount() {
// Called right before the mounting begins
alert(‘beforeMount triggered.’);
},
mounted() {
// Called after the instance has been mounted
alert(‘mounted triggered.’);
},
beforeUpdate() {
// Called when data changes, before the DOM is patched
alert(‘beforeUpdate triggered.’);
},
updated() {
/**
* Called after a data change causes the virtual DOM
* to be re-rendered and patched.
*/
alert(‘updated triggered.’);
},
beforeUnmount() {
// Called right before a component instance is unmounted
alert(‘beforeUnmount triggered.’);
},
unmounted() {
// Called after a component instance has been unmounted
alert(‘unmounted triggered.’);
}
}
</script>
<style scoped>
</style>
Computed vs Methods: What to use?
Computed Properties:
cached based on their reactive dependencies
only re-evaluates when some of its reactive dependencies have changed
Methods:
no caching occurs
will always run the function whenever a re-render happens
TL:DR
Use Computed Properties when functionality reacts to DOM changes
Use Methods when functionality is triggered by a user event
ComputedProperties.vue
<template>
<div>
<div>Do I have things to do? {{ thingsToDo }}</div>
<div>Things to do:</div>
<ul>
<li v-for="listItem in sampleList" :key="listItem.text">
{{ listItem.text }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "ComputedProperties",
computed: {
thingsToDo() {
/**
* This statement’s result is cached and will only
* re-evaluate when sampleList changes content,
* saving computational power.
*/
return this.sampleList.length > 0 ? 'Yes' : 'No'
}
},
data() {
return {
sampleList: [
{ text: 'Eat' },
{ text: 'Sleep' },
{ text: 'Be awesome' }
]
}
},
}
</script>
<style scoped>
</style>
v-if vs v-show: What to use?
v-if:
is "real" conditional rendering
event listeners and child components are properly destroyed and re-created
DOM elements are properly destroyed and re-created
is “lazy”; i.e. DOM elements WILL NOT render unless condition is true on first load
v-show:
is always rendered regardless of condition
uses CSS to toggle elements ON and OFF
event listeners and child components stay rendered regardless of condition
DOM elements stay rendered when toggling ON and OFF
TL:DR
Use v-show if you need to toggle something very often
Use v-if if the condition is unlikely to change at runtime
ConditionalSample.vue
<template>
<div>
<div>
<button @click=”toggleContent”>Click Me!</button>
</div>
<div v-if=”showContent”>
<span>I am v-if rendered!</span>
</div>
<div v-show=”showContent”>
<span>I am v-show rendered</span>
</div>
</div>
</template>
<script>
export default {
name: "ConditionalSample",
data() {
return {
showContent: false
}
},
methods: {
toggleContent() {
this.showContent = !this.showContent
}
}
}
</script>
<style scoped>
</style>
Components
When to use components:
Repeated functionality across multiple pages
Decoupling of long, mangled, spaghetti codebase
Component Data Flow:
To pass data from parent component to child component, use props
To pass data from child component back to parent component, use emit
How to use components
ParentComponent.vue
<template>
<div>
<div>Hi! I am a parent component.</div>
<div>
<ChildComponent />
<div>
<div>
</template>
<script>
import ChildComponent from “./ChildComponent”;
export default {
name: “ParentComponent”,
components: {
ChildComponent
}
}
</script>
<style scoped>
</style>
ChildComponent.vue
<template>
<div>
<div>Hi! I am a child component. {{ message }}</div>
<div>
</template>
<script>
export default {
name: “ChildComponent”,
data() {
return {
message: ‘yay!’
}
}
}
</script>
<style scoped>
</style>
How to pass data to child component
ParentComponent.vue
<template>
<div>
<div>Hi! I am a parent component.</div>
<div>
<ChildComponent :message=”message”/>
<div>
<div>
</template>
<script>
import ChildComponent from “./ChildComponent”;
export default {
name: “ParentComponent”,
components: {
ChildComponent
},
data() {
return {
message: ‘yay!’
}
}
}
</script>
<style scoped>
</style>
ChildComponent.vue
<template>
<div>
<div>Hi! I am a child component. {{ message }}</div>
<div>
</template>
<script>
export default {
name: “ChildComponent”,
props: [
'message'
],
}
</script>
<style scoped>
</style>
How to pass data to parent component
ParentComponent.vue
<template>
<div>
<div>Hi! I am a parent component.</div>
<div>
<ChildComponent
:message=”message”
@pass-message=”parseChildMessage”
/>
<div>
<div>
</template>
<script>
import ChildComponent from “./ChildComponent”;
export default {
name: “ParentComponent”,
components: {
ChildComponent
},
data() {
return {
message: ‘yay!’
}
},
methods: {
parseChildMessage(message) {
alert(‘Yay! Child component says ’ + message);
}
}
}
</script>
<style scoped>
</style>
ChildComponent.vue
<template>
<div>
<div>Hi! I am a child component. {{ message }}</div>
<div>
<button @click=”sendBack”>Click Me!</button>
</div>
<div>
</template>
<script>
export default {
name: “ChildComponent”,
props: [
'message'
],
methods: {
sendBack() {
this.$emit(‘passMessage’, ‘Hello!’);
}
}
}
</script>
<style scoped>
</style>
Vuex
What it is:
a state-management pattern + library
a centralized store for all components
has rules ensuring that the state can only be mutated in a predictable fashion
used in building large-scale Single-Page Applications
Vuex Core Concepts
State
Vuex uses a single state tree
a single object contains all application-level state
serves as the "single source of truth."
Vuex follows the same rules as the data in a Vue instance
reactive
Getters
considered as computed properties for stores
result is cached based on its dependencies
will only re-evaluate when some of its dependencies have changed
Mutations
the only way to actually change state in a Vuex store
mutations are very similar to events
each mutation has a string type and a handler.
handler function is where actual state modifications are performed
handler function receives state as the first argument
Actions
are similar to mutations, with key differences
actions commit mutations instead of mutating the state
actions can contain arbitrary asynchronous operations
mutations have to be synchronous, while actions does not have to be
Modules
allows Vuex to divide store into modules
each module can contain its own state, mutations, actions, getters
References:
https://vuex.vuejs.org/guide/state.html
https://vuex.vuejs.org/guide/getters.html
https://vuex.vuejs.org/guide/mutations.html
https://vuex.vuejs.org/guide/actions.html
https://vuex.vuejs.org/guide/modules.html
How to Setup Vuex in a Project
src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({})
export default store
src/main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store/index'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store
}).$mount('#app')
How to add store state
src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
todoList: [
{ value: ‘Code’ }
]
},
})
export default store
SampleComponent.vue
<template>
<div>
<tr v-for="(item, index) in todoList" :key="index">
<td>{{ item.value }}</td>
</tr>
</div>
</template>
<script>
export default {
name: ‘SampleComponent’,
computed: {
todoList() {
return this.$store.state.todoList
}
}
}
</script>
<style scoped>
</style>
How to add store getters
src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
todoList: [
{ value: ‘Code’ }
]
},
getters: {
todoList: state => {
return state.todoList
}
},
})
export default store
SampleComponent.vue
<template>
<div>
<tr v-for="(item, index) in todoList" :key="index">
<td>{{ item.value }}</td>
</tr>
</div>
</template>
<script>
export default {
name: ‘SampleComponent’,
computed: {
todoList() {
return this.$store.getters.todoList
}
}
}
</script>
<style scoped>
</style>
How to add store mutations
src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
todoList: [
{ value: ‘Code’ }
]
},
getters: {
todoList: state => {
return state.todoList
}
},
mutations: {
addTodoItem(state, value) {
state.todoList.push({value: value})
},
removeTodoItem(state, value) {
state.todoList.splice(value, 1)
}
}
})
export default store
SampleComponent.vue
<template>
<div>
<div>
<span>Add Item: </span>
<input v-model="todoInput" />
<button @click="addItem">Add Item</button>
</div>
<div>
<tr v-for="(item, index) in todoList" :key="index">
<td>
<button @click="removeItem(index)">X</button>
</td>
<td>{{ item.value }}</td>
</tr>
<div>
</div>
</template>
<script>
export default {
name: ‘SampleComponent’,
computed: {
todoList() {
return this.$store.getters.todoList
}
},
data() {
return {
todoInput: ‘’
}
},
methods: {
addItem() {
this.$store.commit('addTodoItem', this.todoInput)
},
removeItem(index) {
this.$store.commit(‘removeTodoItem’, index)
}
}
}
</script>
<style scoped>
</style>
How to add store actions
src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
todoList: [
{ value: ‘Code’ }
]
},
getters: {
todoList: state => {
return state.todoList
}
},
mutations: {
addTodoItem(state, value) {
state.todoList.push({value: value})
},
removeTodoItem(state, value) {
state.todoList.splice(value, 1)
}
},
actions: {
addItem (context, item) {
context.commit('addTodoItem', item)
},
removeItem(context, itemIndex) {
context.commit('removeTodoItem', itemIndex)
}
}
})
export default store
SampleComponent.vue
<template>
<div>
<div>
<span>Add Item: </span>
<input v-model="todoInput" />
<button @click="addItem">Add Item</button>
</div>
<div>
<tr v-for="(item, index) in todoList" :key="index">
<td>
<button @click="removeItem(index)">X</button>
</td>
<td>{{ item.value }}</td>
</tr>
<div>
</div>
</template>
<script>
export default {
name: ‘SampleComponent’,
computed: {
todoList() {
return this.$store.getters.todoList
}
},
data() {
return {
todoInput: ‘’
}
},
methods: {
addItem() {
this.$store.dispatch('addItem', this.todoInput)
},
removeItem(index) {
this.$store.dispatch(‘removeItem’, index)
}
}
}
</script>
<style scoped>
</style>
How to setup store into modules
src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const moduleA = {
state: () => ({
todoList: [
{ value: ‘Code’ }
]
}),
getters: {
todoList: state => {
return state.todoList
}
},
mutations: {
addTodoItem(state, value) {
state.todoList.push({value: value})
},
removeTodoItem(state, value) {
state.todoList.splice(value, 1)
}
},
actions: {
addItem (context, item) {
context.commit('addTodoItem', item)
},
removeItem(context, itemIndex) {
context.commit('removeTodoItem', itemIndex)
}
}
}
const store = new Vuex.Store({
modules: {
moduleA: moduleA
}
})
export default store
SampleComponent.vue
<template>
<div>
<div>
<span>Add Item: </span>
<input v-model="todoInput" />
<button @click="addItem">Add Item</button>
</div>
<div>
<tr v-for="(item, index) in todoList" :key="index">
<td>
<button @click="removeItem(index)">X</button>
</td>
<td>{{ item.value }}</td>
</tr>
<div>
</div>
</template>
<script>
export default {
name: ‘SampleComponent’,
computed: {
todoList() {
return this.$store.getters.todoList
}
},
data() {
return {
todoInput: ‘’
}
},
methods: {
addItem() {
this.$store.dispatch('addItem', this.todoInput)
},
removeItem(index) {
this.$store.dispatch(‘removeItem’, index)
}
}
}
</script>
<style scoped>
</style>
Vue Router
What it is:
a routing mechanism for switching components
used in building Single Page Applications
useful for changing components using URL paths
Reference: https://router.vuejs.org/guide/#html
How to Setup Vue Router in a Project
src/routes/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import HelloWorld from './../components/HelloWorld.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
component: HelloWorld,
},
]
const router = new VueRouter({
routes
})
export default router
src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './routes/index.js'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
router
}).$mount('#app')
src/App.vue
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<div>
<router-link :to="{ path: '/'}">Home</router-link>
</div>
<router-view />
</div>
</template>
<script>
export default {
name: 'App',
}
</script>
<style scoped>
</style>
How to add routes
src/routes/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import HelloWorld from './../components/HelloWorld.vue'
import TodoComponent from './../components/TodoComponent.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
component: HelloWorld,
},
{
path: '/todolist',
component: TodoComponent
},
]
const router = new VueRouter({
routes
})
export default router
src/components/TodoComponent.vue
<template>
<div>
Todo Component
</div>
</template>
<script>
export default {
name: 'TodoComponent'
}
</script>
<style scoped>
</style>
src/App.vue
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<div>
<router-link :to="{ path: '/'}">Home</router-link>
<router-link
:to="{ path: '/todolist'}"
>
TodoComponent
</router-link>
</div>
<router-view />
</div>
</template>
<script>
export default {
name: 'App',
}
</script>
<style scoped>
</style>
Dynamic Routes
What it is:
useful for components which depends on certain parameters before rendering
allows passing values in between routes
How to add dynamic routes
To see it in action, type the following URL:
http://localhost:8080/#/person/1
src/routes/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import HelloWorld from './../components/HelloWorld.vue'
import TodoComponent from './../components/TodoComponent.vue'
import PersonComponent from './../components/PersonComponent.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
component: HelloWorld,
},
{
path: '/todolist',
component: TodoComponent
},
{
path: ‘/person/:id’,
component: PersonComponent
}
]
const router = new VueRouter({
routes
})
export default router
src/components/PersonComponent.vue
<template>
<div>
Person Component
{{ $route.params.id }}
</div>
</template>
<script>
export default {
name: 'PersonComponent'
}
</script>
<style scoped>
</style>
Programmatic Navigation
When to use:
route needs to be navigated using function
route requires dynamic parameters
route needs to be navigated after a certain process occurs
**Reference: **https://router.vuejs.org/guide/essentials/navigation.html
How to programmatically navigate a route
ProgrammaticRouting.vue
<template>
<div>
<button @click=”navigate”>Navigate to somewhere</button>
</div>
</template>
<script>
export default {
name: 'ProgrammaticRouting',
methods: {
navigate() {
// The path must be the same as the path declared in routes
this.$router.push({path: ‘somewhere’})
}
}
}
</script>
<style scoped>
</style>
Top comments (2)
It'll make a great difference if you could format your code.
Use "
html" and "
javascript".
You can also format npm commands as code blocks.
oh yeah thanks will apply these changes!