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

  • 937