Vue.js
The Practical Guide
About me
Staff Frontend Engineer
Core Team Member
About you!
- Ask questions
- Communicate openly
- Share feedback
@N_Tepluhina
What will we learn today?
- Starting a new Vue app - options
- Migrating to Vue
- Single-File Component anatomy
@N_Tepluhina
Vue 2 or Vue 3?
@N_Tepluhina
Creating a new Vue app
@N_Tepluhina
Vue CLI
npm install -g @vue/cli
# OR
yarn global add @vue/cli
vue create my-project
@N_Tepluhina
Vue CLI
@N_Tepluhina
SSR with Nuxt (v2)
npx create-nuxt-app <my-project>
# OR
yarn create-nuxt-app <my-project>
@N_Tepluhina
Vite
npm init vite@latest
# OR
yarn create vite
@N_Tepluhina
Vite
@N_Tepluhina
Vite
@N_Tepluhina
Vite
- The fastest and the lightest option
- Only works with Vue 3
@N_Tepluhina
Migrating from JS/jQuery
- No build step required
- Add CDN script
- Iteratively refactor the logic
@N_Tepluhina
Migrating from other framework
- Reuse component structure
- React: reuse JSX with render functions
- Angular: reuse template with directives
@N_Tepluhina
Angular
<section class="main" *ngIf="todoStore.todos.length > 0">
<input type="checkbox"
*ngIf="todoStore.todos.length"
[checked]="todoStore.allCompleted()"
(click)="todoStore.setAllTo(toggleall.checked)">
<ul class="todo-list">
<li *ngFor="#todo of todoStore.todos" [class.completed]="todo.completed" [class.editing]="todo.editing">
<div class="view">
<input class="toggle" type="checkbox" (click)="toggleCompletion(todo)" [checked]="todo.completed">
<label (click)="editTodo(todo)">{{todo.title}}</label>
<button class="destroy" (click)="remove(todo)"></button>
</div>
<input class="edit"
*ngIf="todo.editing"
[value]="todo.title"
(blur)="stopEditing(todo, editedtodo.value)"
(keyup.enter)="updateEditingTodo(todo, editedtodo.value)"
(keyup.escape)="cancelEditingTodo(todo)">
</li>
</ul>
</section>
@N_Tepluhina
Vue
<section class="main" v-if="todoStore.todos.length > 0">
<input type="checkbox"
v-f="todoStore.todos.length"
:checked="todoStore.allCompleted()"
@click="todoStore.setAllTo(toggleall.checked)">
<ul class="todo-list">
<li v-for="todo in todoStore.todos" :class="{completed: todo.completed, editing: todo.editing}">
<div class="view">
<input class="toggle" type="checkbox" @click="toggleCompletion(todo)" :checked="todo.completed">
<label @click="editTodo(todo)">{{todo.title}}</label>
<button class="destroy" @click="remove(todo)"></button>
</div>
<input class="edit"
v-if="todo.editing"
:value="todo.title"
@blur="stopEditing(todo, editedtodo.value)"
@keyup.enter="updateEditingTodo(todo, editedtodo.value)"
@keyup.esc="cancelEditingTodo(todo)">
</li>
</ul>
</section>
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
React
import { ref } from "vue";
export default {
setup() {
const state = ref("");
const handleSubmit = (event) => {
event.preventDefault();
alert("A name was submitted: " + state.value);
};
const handleChange = (event) => {
state.value = event.target.value;
};
return () => (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={state.value} onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
},
};
Vue
@N_Tepluhina
Vue 2 -> 3 migration
- Check your dependencies
- Fix deprecated slot syntax
- Make sure you don't need to support IE
- Follow compat build steps
@N_Tepluhina
Single-File Components
- Script
- Template
- Style
@N_Tepluhina
Script: what API?
- Options API: a long-time default, easier to learn
- Composition API: advanced logic composition
@N_Tepluhina
Script: <script setup>
- Less boilerplate
- Better runtime performance
- Can be used along normal <script>
@N_Tepluhina
Script: what about types?
- In v2 TypeScript is still not easy
- In v3 most of the cases are typed with defineComponent
@N_Tepluhina
Style - Scoped styles
- Allow you to have component-specific styles
- Keep global styles in root component
@N_Tepluhina
Style: state-driven dynamic CSS
<script>
export default {
data() {
return {
headerColor: 'red',
}
},
}
</script>
<template>
<h1 class="title">Smashing Workshop: Lesson 1</h1>
</template>
<style>
.title {
color: v-bind(headerColor);
}
</style>
@N_Tepluhina
Style: preprocessors
<style lang="scss">
.user-wrapper {
& > .user {
&:hover {
// ...
}
}
}
</style>
Q & A
@N_Tepluhina
Vue.js: The Practical Guide
By Natalia Tepluhina
Vue.js: The Practical Guide
Smashing Workshop - Day 1
- 925