My cheat sheet for vue.js most basic stuff. The goal wasn't to make another Vue documentation, because the official one is already badass. Big thank you to boussadjra for making this cheat sheet available as a website
Contributions and PRs are very welcome.
"You must type each of these exercises in, manually. If you copy and paste, you might as well not even do them. The point of these exercises is to train your hands, your brain, and your mind in how to read, write, and see code. If you copy-paste, you are cheating yourself out of the effectiveness of the lessons." - Zed A.
Sources:
Useful Chrome extensions:
Stuff that might get handy in almost every Vue.js project:
<html>
<head>
<meta charset="utf8">
<title>VueJS example</title>
<link href="style.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="vue-app">
<p> {{ hello() }} </p>
<p> {{ name }} </p>
<p> {{ age + 1 }} </p>
<p> {{ age < 18 ? "Youngster" : "Adult"}} </p>
</div>
<script src="app.js"></script>
</body>
</html>
new Vue({
el: '#vue-app', // contoled element
data: {
name: "Matej",
age: 27,
sleepy: true
},
methods: {
hello: function () {
return "Hello";
},
computed:{}
}
});
Show / hide div
Hides the element (display none), doesn't delete it
where available is a boolean variable in the js
<div v-show="available">Stuff</div>
Toggle show / hide div
where available is a boolean variable in the js
<div v-show="available = !available">Stuff</div>
Render div
Deletes the element, doesn't hide it
where available is a boolean variable in the js
<div v-if="available">Stuff</div>
<div v-else>Smth else</div>
Looping
array of strings
Remember to check if the element exists with v-if before looping over it
<ul>
<li v-for="(element, index) in elements">{{index}} {{element}}</li>
</ul>
array of objects
<ul v-if="emplyee">
<li v-for="employee in employees">{{employee.name}} - {{employee.age}}</li>
</ul>
nested arrays
<table>
<tr>
<th>Amount</th>
<th>Asset</th>
<th>Created</th>
</tr>
<template v-for="u in users">
<tr v-for="t in u.transfers">>
<td>{{ t.amount }}</td>
<td>{{ t.asset }}</td>
<td>{{ t.timestamp }}</td>>
</tr>
</template>
</table>
variables in v-for
<li v-for="id in users" :key="id" :set="item = getUserData(id)">
<img :src="item.avatar" /><br />
{{ item.name }}<br />
{{ item.homepage }}
</li>
Set text for element from a variable name
<span v-text="name"></span>
Set html for element from a variable name
<span v-html="name"></span>
<input v-model="name" type="text" />
<p>My name is: {{name}}</p>
...
data:{
name: ""
}
...
Computed properties are cached, and only re-computed on reactive dependency changes. Note that if a certain dependency is out of the instance’s scope (i.e. not reactive), the computed property will not be updated. In other words, imagine a computed property as a method (but it's not really a method) in the
data()
that always returns a value. That "method" will be called whenever a property (variable fromdata()
) used in that method is changed.
<html>
<head>
<meta charset="utf8">
<title>VueJS example</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="vue-app">
<button v-on:click="a++">Counter 1++</button>
<button v-on:click="a--">Counter 1--</button>
<button v-on:click="b++">Counter 2++</button>
<p>Counter 1: {{ a }}</p>
<p>Counter 2: {{ b }}</p>
<!--The result() method is invoked whenever the Counter 1 button is clicker or the Counter 2 button is clicked-->
<!--The output() method is invoked only when the Counter 2 button is clicked-->
<p>Result: {{ result() }} | {{ output }}</p>
</div>
<script src="main.js"></script>
</body>
</html>
new Vue({
el: '#vue-app',
data: {
a: 0,
b: 0
},
methods: {
result: function () {
// this function is not interested in the "b" variable, yet it runs every time when the result needs to be changed
console.log("methods");
return this.a < 0 ? "Negative" : "Positive";
}
},
computed: {
// these methods are invoked like attributes, without ()
// this method runs only when the "a" variable is changed
output: function () {
console.log("computed");
return this.a < 0 ? "Negative" : "Positive";
}
}
});
Computed property methods can also have getters and setters
var vm = new Vue({
data: { a: 1 },
computed: {
// get only
aDouble: function () {
return this.a * 2
},
// both get and set
aPlus: {
get: function () {
return this.a + 1
},
set: function (v) {
this.a = v - 1
}
}
}
})
vm.aPlus // => 2
vm.aPlus = 3
vm.a // => 2
vm.aDouble // => 4
<p v-bind:style="{ property: value }">...</p>
this div will have the red class if the userFound variable is set to true
<div v-bind:class="{ red: userFound }">...</div>
this div will have the red class if the isAdmin variable is set to true
<div :class="[isAdmin ? 'red' : 'blue']">...</div>
Call method on click event
where method is a custom method in the js
<button v-on:click="method">Add</button>
or shorthand
where method is a custom method in the js
<button @click="method">Add</button>
method is called when ALT+ENTER is pressed
<input ref="name" v-on:keyuop.alt.enter="method" type="text" />
Conditional event binding (as of Vue 2.6)
The method sendModey
will be called only if the condition amount > 0
has been met.
<button @click="amount > 0 && sendMoney()">Send money</button>
// fire custom event
this.$emit("eventName", data);
<!--
$event == event data
when _eventName_ event happens, call _functionName_ function
-->
<p v-on:eventName="functionName($event)"></p>
communicate between child components without the parent component
consider using Vuex instead
// main.js
// create new event bus
export const bus = new Vue();
// Header.vue
import {bus} from "../main";
// Footer.vue
import {bus} from "../main";
// listen to bus event in first component
// usually in .created() function
bus.$on("eventName", (data) => {
// callback
// use data
})
// fire bus event in second component
bus.$emit("eventName", data);
reusable inside the html
<div id="app">
<!-- <component is="signature"></component> -->
<signature></signature>
<signature></signature>
</div>
// global registration
Vue.component('signature', {
template: '<p>Regards. Matej.</p>'
});
Props - passing data from parent component to child component
<!--App.vue-->
<template>
<div>
<app-header></app-header>
<app-ninjas v-bind:ninjas="ninjas"></app-ninjas>
<app-footer></app-footer>
</div>
</template>
<script>
// import
import Header from './components/Header.vue';
import Footer from './components/Footer.vue';
import Ninjas from './components/Ninjas.vue';
export default {
// register components
components:{
// added app- prefix
// because header and footer tags already exist
"app-header": Header,
"app-footer": Footer,
"app-ninjas": Ninjas
},
data () {
return {
ninjas:[
{name: "ninja1", speciality: "vuejs", show: false},
{name: "ninja2", speciality: "nodejs", show: false},
{name: "ninja3", speciality: "react", show: false},
{name: "ninja4", speciality: "js", show: false},
{name: "ninja5", speciality: "css3", show: false},
{name: "ninja6", speciality: "ps", show: false}
]
}
}
}
</script>
<!--Ninjas.vue-->
<template>
<div id="ninjas">
<ul>
<li v-for="ninja in ninjas" v-on:click="ninja.show = !ninja.show">
<h2>{{ninja.name}}</h2>
<h3 v-show="ninja.show">{{ninja.speciality}}</h3>
</li>
</ul>
</div>
</template>
<script>
export default {
// what is it receiving
props: ["ninjas"],
data: function () {
return {
}
}
}
</script>
<!--Header.vue-->
<template>
<header>
<h1>{{title}}</h1>
</header>
</template>
<script>
export default {
data: function () {
return {
title: "Welcome!"
}
}
}
</script>
<!--Footer.vue-->
<template>
<footer>
<p>{{copyright}}</p>
</footer>
</template>
<script>
export default {
data: function () {
return {
copyright: "Copyright 2017 "
}
}
}
</script>
export default {
props:{
ninjas:{
type: Array,
required: true
}
}
}
Change the output data to the browser. They do not change the data directly.
<h1>{{title | to-uppercase}}</h1>
// main.js
Vue.filter("to-uppercase", function ( value ) {
return value.toUpperCase();
});
Reuse some piece if code (or function) so that it doesn't need to be written in more separate files.
An object of DOM elements and component instances
<input ref="name" type="text" />
var name = this.$refs.name;
dynamically change component based on variable component value rememberto use keep-alive tag to remember data from the destroyed component
<template>
<div>
<component> v-bind:is="componentName"></component>
</div>
</template>
import formOne from "./components/formOne.vue";
import formTwo from "./components/formTwo.vue";
...
data: function() {
return {
component: "form-two"
}
}
make new project
$ vue init webpack-simple my-project
$ cd project-name
install dependencies and start local server
$ npm install
$ npm run dev
build app for production
this will make a dist folder with minified js
$ npm run build
with v-model, the categories array will be appended with the values
<div>
<label for="">Newsletters</label>
<input type="checkbox" value="newsletter" v-model="categories">
<label for="">New posts</label>
<input type="checkbox" value="post" v-model="categories">
<label for="">New DMs</label>
<input type="checkbox" value="dm" v-model="categories">
<label for="">New pokes</label>
<input type="checkbox" value="pokes" v-model="categories">
</div>
data: function () {
categories: []
}
hardcoded and looped select
<div>
<select v-model="town">
<option value="osijek">Osijek</option>
<option value="zagreb">Zagreb</option>
<option value="varazdin">Varazdin</option>
</select>
<select v-model="town">
<option v-for="t in towns">{{ t }}</option>
</select>
</div>
data: function () {
town: "",
towns: ["Zagreb", "Osijek", "Varazdin", "Split", "Rijeka", "Dubrovnik"]
}
Important: if sending nested objects, be sure to JSON.stringify first!
Register it in main.js
import VueResource from 'vue-resource'
Vue.use(VueResource);
Usage in custom function
post: function () {
this.$http.post("http://localhost:3000/users", {
title: this.blog.title,
body: this.blog.body,
userId: 1
}).then( res => {
// promise
console.log("Response: ", res);
}, error => {
console.log("Error: ", error);
});
}
Usage in custom function
post: function () {
this.$http.get("http://localhost:3000/users").then( function ( res ){
// promise
console.log("Response: ", res)
});
}
// router.js
import login from "./components/login.vue";
import registration from "./components/Registration.vue";
import user from "./components/user.vue";
// main.js
import VueRouter from 'vue-router';
import { routes } from "./routes";
Vue.use(VueRouter);
const router = new VueRouter({
routes
});
new Vue({
el: '#app',
router: router,
render: h => h(App)
})
// routes.js
import Login from "./components/Login.vue";
import Registration from "./components/Registration.vue";
import User from "./components/User.vue";
export const routes = [
{ path: "", component: Login },
{ path: "/registration", component: Registration },
{ path: "/users/", component: Users, children: [
{ path: "", component: UserStart },
{ path: ":id", component: UserDetail },
{ path: ":id/edit", component: UserEdit }
] },
{path: "*", redirect: "/"} // handle all uncovered routes
]
mark the place with router-view where the component of the currently active route will be loaded
<template>
<router-view></router-view>
</template>
handling route parameters
<!-- user.vue -->
<template>
<div id="user">
<h1></h1>
<div></div>
</div>
</template>
<script>
export default {
data: function () {
return {
id: this.$route.params.id,
user: {}
}
},
created(){
this.$http.get("http://url/user/" + this.id).then(function(res){
this.user = res.body;
});
}
}
</script>
navigating around
<ul class="nav">
<router-link to="/" tag="li" active-class="active" exact><a>Home</a></router-link>
<router-link to="/users" tag="li" active-class="active" ><a>Users</a></router-link>
</ul>
dynamically route over user details
<router-link v-bind:to='"/user/" + user.id' tag="li" v-for="(user, index) in users"> {{ user.username }}</router-link>
navigate home
this.$router.push({ path: "/home"});
watch for route changes
watch: {
"$route": function (to, form){
this.id = to.params.id
}
}
watch if object is changed
watch: {
picked: {
handler(val, oldVal) {
console.log('changed: ', oldVal);
console.log('new: ', val);
},
deep: true,
immediate: true
}
}
To not let someone access e.g. /dashboard if the user is not logged in.
// add requiresAuth to certain components
export const routes = [
{ path: "", component: Login },
{ path: "/dashboard", component: Dashboard, meta: {requiresAuth: true} }
];
// configure vue-router
// important: do not turn on history mode
const router = new VueRouter({
routes,
// mode: "history"
})
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if ( CHECK_FOR_USER_IN_LOCALSTORAGE_ETC ) {
// handle restricted access
next({
path: '/login',
});
} else {
next();
}
} else {
// do nothing with components without meta: {requiresAuth: true}
next();
}
})
<!--input field for search query-->
<input type="text" v-model="searchQuery" placeholder="Search...">
<!--loop like this, instead of classic for user in users-->
<tr v-for="user in filterUsers">
// users array and search query variable
data: function () {
return {
searchQuery: "",
users: []
};
},
...
// computed method for filtering users by
// email, last name and first name
computed: {
filterUsers () {
return this.users.filter(user => {
return (user.email.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1 ||
user.lastName.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1 ||
user.firstName.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1)
})
}
}
// add needed variables
data: function () {
return {
ascending: false,
sortColumn: '',
users: [],
};
},
methods: {
// sort method
"sortTable": function sortTable ( col ) {
if ( this.sortColumn === col ) {
this.ascending = !this.ascending;
} else {
this.ascending = true;
this.sortColumn = col;
}
let ascending = this.ascending;
this.users.sort(function ( a, b ) {
if ( a[col] >= b[col] ) {
return ascending ? 1 : -1
} else if ( a[col] < b[col] ) {
return ascending ? -1 : 1
}
return 0;
})
}
}
<!--call sortTable method on column with corresponding property in users object-->
<tr>
<th @click="sortTable('email')">Username</th>
<th @click="sortTable('firstName')">First Name</th>
<th @click="sortTable('lastName')">Last Name</th>
<th @click="sortTable('address')">Address</th>
<th>Phone number</th>
</tr>
searchVideos() {
let filtered = this.videos;
// search by keyword
if (this.filters.searchQuery) {
filtered = this.videos.filter(
v => v.title.toLowerCase().indexOf(this.filters.searchQuery) > -1
);
}
// filter by date range
if (this.filters.startDate && this.filters.endDate) {
filtered = filtered.filter(v => {
var time = new Date(v.created_at).getTime();
return (new Date(this.filters.startDate).getTime() < time && time < new Date(this.filters.endDate).getTime());
});
}
// filter by property value
if (this.filters.filterVal) {
if (this.filters.filterVal === 'female') {
filtered = filtered.filter(
v => v.gender === this.filters.filterVal
);
}
// sort by property
if (this.filters.sortValue === 'most_popular') {
filtered.sort(function(a, b) { return a.views - b.views; });
}
}
return filtered;
}
An async
function returns a promise. When you want to call this function you prepend await
, and the calling code will stop until the promise is resolved or rejected.
// example
const doSomethingAsync = () => {
return new Promise((resolve) => {
setTimeout(() => resolve('I did something'), 3000)
})
}
const doSomething = async () => {
console.log(await doSomethingAsync())
console.log('I did something again!')
}
doSomething()
// result:
// I did something!
// I did something again!
// example
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
data: null
},
mutations: {
setData: (state, payload) => {
state.resource = payload
}
},
actions: {
async getData({ commit }) {
let res = null
try {
res = await fetch(
'https://api.coindesk.com/v1/bpi/currentprice.json'
)
} catch (err) {
console.log('err: ', err)
return
}
// Handle success
console.log('waiting for data...');
const data = await res.json()
console.log('data: ', data)
commit('setData', data)
}
}
})
// config.js
// example config file
var apiPort = 5566;
var currHost = window.location.protocol + '//' + window.location.hostname + ':' + apiPort + '/api/v1';
var url = window.location.host !== 'localhost:8080' ? 'http://PROD-URL/' : currHost;
export var cfg = {
version: "0.1.0",
api: {
endpoint: url
}
};
// main.js
import * as config from './config'
window._cfg = config.cfg
mounted() {
this.$refs.myInput.focus();
}