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:{}
}
});
where available is a boolean variable in the js
<div v-show="available">Stuff</div>
where available is a boolean variable in the js
<div v-show="available = !available">Stuff</div>
where available is a boolean variable in the js
<div v-if="available">Stuff</div>
<div v-else>Smth else</div>
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>
<ul v-if="emplyee">
<li v-for="employee in employees">{{employee.name}} - {{employee.age}}</li>
</ul>
<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>
<li v-for="id in users" :key="id" :set="item = getUserData(id)">
<img :src="item.avatar" /><br />
{{ item.name }}<br />
{{ item.homepage }}
</li>
<span v-text="name"></span>
<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";
}
}
});
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>
where method is a custom method in the js
<button v-on:click="method">Add</button>
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" />
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>
// 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);
<div id="app">
<!-- <component is="signature"></component> -->
<signature></signature>
<signature></signature>
</div>
// global registration
Vue.component('signature', {
template: '<p>Regards. Matej.</p>'
});
<!--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
}
}
}
<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.
<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"
}
}
$ vue init webpack-simple my-project
$ cd project-name
$ npm install
$ npm run dev
this will make a dist folder with minified js
$ npm run build
- new Vue();
- .beforeCreate();
- .created();
- .beforeMount();
- .updated();
- .beforeUpdate();
- .beforeDestroy();
- .destroyed();
<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: []
}
<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!
import VueResource from 'vue-resource'
Vue.use(VueResource);
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);
});
}
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
]
<template>
<router-view></router-view>
</template>
<!-- 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>
<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>
<router-link v-bind:to='"/user/" + user.id' tag="li" v-for="(user, index) in users"> {{ user.username }}</router-link>
this.$router.push({ path: "/home"});
watch: {
"$route": function (to, form){
this.id = to.params.id
}
}
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();
}
- v-once - render the element and component only once
- v-if - conditionally render the element
- Difference between computed and methods
- watch - specify what property to listen for changes and then execute some code without returning values
- v-model modifiers
- .lazy - fire event when user lefts the field
- .number - force the value to be converted to a integer
- .trim - delete whitespace