Vuejs

From Training Material
Jump to navigation Jump to search


Vuejs

Vuejs Training Materials

Introduction

  • JavaScript framework for building UI (user interfaces)
  • What do we need?
    • HTML, CSS, and JavaScript
  • Declarative, component-based programming model
    • Declarative rendering
    • Reactivity
  • Progressive framework
  • Single-file components (SFC)
  • API Styles - options VS composition

Not That

NotVue.png

BUT still - we'll have a lot to see! (-'

Framework

Progressive Framework - "framework that can grow with you and adapt to your needs"

  • framework and ecosystem
  • designed to be flexible and incrementally adoptable
  • can be used in
    • enhancing static HTML without a build step
    • embedding as Web Components on any page
    • Single-Page Application (SPA)
    • Fullstack / Server-Side Rendering (SSR)
    • Jamstack / Static Site Generation (SSG)
    • targeting desktop, mobile, WebGL, and even the terminal

Overview of Vue JS

  • Declarative rendering
  • Component composition

Declarative rendering

  • Declaring Reactive State
  • Declaring Methods - methods()
    • this is bind automatically (no arrows here!)
    • accessible in template (mostly as event listeners)
  • Deep Reactivity - by default
    • detects even mutation of nested obj or array
  • DOM Update Timing - not synchronous, buffered until the nextTick(), fixable with async..await
    • in the update cycle - ensures each component updates only once (with all the state changes)
  • Stateful Methods - dynamically created methods
    • in reused components - to avoid interference use created() lifecycle hook

Component composition

  • SFC - Single-File Components
  • Options API vs Compositions API - two styles

SFC

  • HTML-like file format (*.vue)
    • logic (JS), template (HTML), and styles (CSS) - together
    • for build-tool-enabled projects
      • recommended way
  • Example
<script>
export default {
  data() {
    return {
      coursesInCart: 0
    }
  }
}
</script>

<template>
  <button @click="coursesInCart + 1">You have: {{ coursesInCart }} courses in your bucket!</button>
</template>

<style scoped>
button {
  font-size: 48px;
}
</style>

Options vs Composition

API Styles in Vue
Compare of Options API Composition API
Component's logic Object with options (data, methods, mounted, etc) Imported API functions (ref, onMounted, etc)
Properties Exposed on this in functions Declared with functions (ref)
Syntax (some bits only) the usual <script> <script setup>, less boilerplate
Common web use cases covered covered
Centered on component instance (this), beginner-friendly, organized state directly in function, free-form, more flexible
For production use no build tools, low-complex cases builds and full apps (+SFC)

Options vs Composition Con't

Options vs Composition, Example

Options Composition
<script>
export default {
  // Properties returned from data() become reactive state and will be exposed on `this`.
  data() {
    return {
      invoice: { id: 'INV_integer', type: 'default', owner: 'countryPrefix_franchisee' }
    
  },

  // Methods are functions that mutate state and trigger updates.
  // They can be bound as event handlers in templates.
  methods: {
    setInv() {
      this.invoice = { id: 'INV2378', type: 'consultancy', owner: 'NPUK_franchisee' }
    }
  },

  // Lifecycle hooks are called at different stages of a component's existence.
  // This function will be called when the component is mounted.
  mounted() {
    console.log(`The invoice for this ${this.invoice.type} is ${this.invoice.id}.`)
  }
}
</script>

<template>
  <button @click="setInv">Send invoice from: {{ invoice.owner }}</button>
</template>
<script setup>
import { ref, onMounted } from 'vue'

// reactive state
const invoice = ref( { id: '', type: '', owner: '' } )

// functions that mutate state and trigger updates
function setInv() {
  invoice.value = { id: 'INV2378', type: 'consultancy', owner: 'NPUK_franchisee' }
}

// lifecycle hooks
onMounted(() => {
  console.log(`The default invoice has an empty ID: ${invoice.value.id}.`)
})
</script>

<template>
  <button @click="setInv">Send invoice from: {{ invoice.owner }}</button>
</template>


Setting up a development environment

vue itself

npm create vue@latest
# answer the interactive questions accordingly (proj-name, ts, routing, pinia, testing, etc)
cd proj-name ; npm i ; npm run format ; npm run dev

OR

npx create-vue proj-name
# answer the questions
cd proj-name ; npm i ; npm run format ; npm run dev

Creating your first application

Build game "Find the jewel".
The objective of the game is to find a random computer-chosen jewel in as few tries as possible.

Approach:
* First think about the functionality we want to offer
* Second think about the data and behavior that can support the functionality
* Third think about how to build a user interface for it

Test it with 'live-server' (if not yet installed in the training machine, run 'sudo npm i -g live-server')
* in command line go to application's root folder and execute the command 'live-server --cors'
  1. Designing the component
    • Detailing the features that we want the app to support
      • Choosing random jewel (origJewel)
      • Providing input for a user to find the jewel (findJewel)
      • Tracking the number of tries already made (howManyTries)
      • Giving the user hints to improve their try based on their input (hinting)
      • Giving a success message if the user found the proper jewel (hinting)
    • Determining what we need to display to the user and what data we need to track
      • Names in round brackets above are the properties that will support those features
      • We need to include these properties in our component

Exercise

Working with Templates

  • Vue uses an HTML-based template syntax
    • declaratively binds
      • the rendered DOM to the underlying component instance's data
  • syntactically valid HTML
    • parseable by spec-compliant browsers and HTML parsers
  • compiled into highly-optimized JS - when the app state changes
    • intelligently re-renders the minimal no of components
    • applies the minimal amount of DOM manipulations
  • can be written directly as render functions instead
    • JSX is optionally supported
    • but not the same level of compile-time optimizations

Methods and computed properties

Method - manages actions, mutates state, etc

  • New option - methods : { setInvoice(){} }
  • Or just functions in composition's setup() { function setInvoice(){} }
  • always called whenever a re-render happens
    • must be returned together with properties

Computed property - solves complex logic that includes reactive data

  • New option - computed: { getInvoicesPerFranchisee(){} }
  • Or just ref in composition's setup, wrapped into computed()
  • cached based on its reactive dependencies
  • getter-only by default, changeable with giving it the setter
  • should be side-effect free, don't:
    • mutate other state
    • make async requests
    • mutate the DOM inside a computed getter
    • also mutating its own computed value

Exercise

Reactive programming

  • unobtrusive reactivity system
  • adjust to changes in a declarative way
  • Proxies for reactive objects
  • getters/setters for refs (simple properties)
  • Reactive Effect => watch(option) or watchEffect()(api)
  • Runtime vs Compile-time - Vue works with Runtime
  • Debugging (only in dev mode!)
    • components - hooks again: renderTracked() and renderTriggered()
    • computed and watcher - onTrack() and onTriger() callbacks in computed() 2nd arg
  • Ext state systems - shallowRef

Directives and data rendering

Data binding - syntax Name:Argument.Modifiers="Value"

  • {{ }} - text interpolation, JS expressions (not statements!); interpreted as plain text
  • v-html - raw HTML somewhere
  • v-bind: / : - attribute directive / shortcut
    • from Vue 3.4+ even shorter, if same name :id="id" => :id
    • multiple attrs - just v-bind without argument

Built-in directives, some

Syntax - prefix v-

  • v-if, v-else - logic for adding/removing elements; destroying
    • v-show - conditional rendering; hiding only (display prop)
  • v-for: - listing elements; v-for="(el, index) in listOfEls" :key="index"
  • v-on: / @ - handling events; v-on:click="updateInv"
    • v-on:[eventName] - dynamic, 'eventName' should be string or null
    • v-on:submit.prevent - with modifier, does event.preventDefault()
  • v-bind:[attrName] - also dynamic, 'attrName' should be string or null
  • v-model - 2 way data binding, between model(data) and view(template)
  • more here https://vuejs.org/api/built-in-directives.html

Exercise

Dividing the application into smaller, self-contained components

  • Component Pattern instead of MVC
  • Constructs
    • expressions, data binding syntax
  • Change detection
  • Web components

Component pattern

In web applications

  • No messes of spaghetti code in applications
  • Reasoning about specific parts of the application in isolation from the other parts
  • Maintenance costs are less
    • Each component's internal logic can be managed separately
    • No affecting the other parts of the application
  • Self-describing components
    • Makes the application easier to understand at a higher level of abstraction

Constructs

  • Usually they live in the HTML template
  • They are linking the view HTML and component code
  • Similar to standard HTML with new symbols:
    : property bindings (v-bind)
    @ event bindings (v-on)
    {{ }} expressions (interpolation)
    


Routing

Managing state (Pinia)

Refactoring components

Debugging and performance

Embedding Vue.js into existing pages

Deploying your application to production Vue-CLI

  • Vite as a replacement for Vue-CLI
    • npm run dev
    • npm run build
    • interactive CLI commands:
press r + enter to restart the server
press u + enter to show server url
press o + enter to open in browser
press c + enter to clear console
press q + enter to quit

Scaling your application

Helpers

Exercises

  1. Simple ftj - discussing app skeleton (index.html, main.js)
    1. Map the state in data() (main.js)
      • add all the properties from designing part
      • use this property below as our main model for now
      • jewels: ['ruby','diamond','agate','amber','aquamarine','amethyst','opal','tourmaline','emerald','onyx','pearl','sapphire']
    2. Update our main html template with howmManyTries
      • Exercise: improve it with dynamic data (index.html)
      • observe it in the browser - use Vue dev-tools
  2. Design the engine of our game - initGame() method
    • it should set values for our game properties
    • supposed to randomly choose the jewel ( Math.floor((Math.random() * 12) + 1) )
    • and of course allow to cheat (-'
    • oh, don't forget to spoil(run) it, do it with hook, yeahhh.. let's go meaty-nasty now! (--'
  3. Describe first jewel in a new paragraph - say "ruby is red"
    • use computed property
    • for that let's improve slightly our model:
      gems: [
        { id:1, jname: 'ruby', jcolor: 'red' },
        { id:2, jname: 'diamond', jcolor: '#b9f2ff' },
        { id:3, jname: 'agate', jcolor: 'blue' },
        { id:4, jname: 'amber', jcolor: 'orange' },
        { id:5, jname: 'aquamarine', jcolor: 'aquamarine' },
        { id:6, jname: 'amethyst', jcolor: 'violet' },
        { id:7, jname: 'opal', jcolor: 'turquoise' },
        { id:8, jname: 'tourmaline', jcolor: 'black' },
        { id:9, jname: 'emerald', jcolor: 'green' },
        { id:10, jname: 'onyx', jcolor: 'gray' },
        { id:11, jname: 'pearl', jcolor: '#EAE0C8' },
        { id:12, jname: 'sapphire', jcolor: '#2554C7' },                       
      ]
      
  4. Communicate The Gamers - win or loose, huh? (---'
    1. interactive message shown to gamer (Drax the Destroyer)
      • first use only one type of directive (&
        • Exercise: improve this section with game logic (index.html)
      • test it in Vue dev-tools
      • later on, improve it with two different directives (&
    2. do same thing, but play hide-and-seek only
      • test it in Vue dev-tools
  5. "Fire!! Gather them together, quickly!" - grouping kids (2Kill'em all..), (----'
    1. Show all the jewels in one view (use 'ul')
    2. For each jewel add its length at the end - ruby 4
      • ..then divide it by the size of jewels array.. - ruby 0.3333333333333333
      • ..and then round it to integer.. - ruby 1
      • ..and then wrap it with logic: if 1, show ' is long', otherwise show ' is short'.. - ruby is short
      • ..and then - improve it with (...) ?? (small discussion together)
  6. Help the gamer - when the number of tries is 5, Restart game button should become huge (48px)
    • add new css class(.gameKiller) and bind it (how?)
  7. events
  8. ?