Basic Vue Component Recipe and Workflow

A simple recipe to add a component to a Vue project or application.

Basic File Structure

Add component file in the components/ diectory on the same project level as the main App.vue and main.js, note the Vue.js Style Guide essential rule on using multi-word component names. This rule prevents potential clashes with HTML elements, which are specfied as single words

src
├── App.vue
├── components
│   └── MyComponent.vue
└── main.js

Refer to these sources to get more background on Vue project structure:

Article on itnext.io by Sandoche ADITTANE
Application structure principles for Vuex
Vue.js Style Guide

Basic Development Workflow

A good basic Vue development workflow to follow takes 3 steps:

  1. Add structure
  2. Add logic
  3. Add style

1. Add Structure

The structure of a Vue component is defined in its <template> tag. Note that the <template> tag can contain only one root level element. In the following example, it is the first (and only) <div> element:

<template>
  <div>
    <h1>My Component</h1>
    <p>My component paragraph text</p>
    <button>Button</button>
  </div>
</template>
//...

Besides the HTML structure, Vue will also need some application configuration to use the new component.

Import and register the component in the main.js file:

//...
import MyComponent from './components/MyComponent';
//...
app.component('my-component', MyComponent);
//...

And finally, add the component tag to the App.vue file:

<template>
    <div id="app">
        <h1>My App</h1>
        <my-component />
    </div>
</template>

As a side note, pay attention to the deliberate use of kebab-case and camelCase or PascalCase. The case used is important to allow Vue to run code as HTML in some instances, and Javascript in others.

2. Add Logic

Before writing any code for the logic, consider what functionality the new component will need.

  • What data will be sent from the parent App.vue to the component?
  • What data will the component need to send to the rest of the app?
  • Which parts of the component will be dynamic or interactive?
  • Which methods or functions will the main app and the component need to communicate with each other?

Props

Props allow the parent app to pass data to its children components. In its simplest form, props are added to a component in three parts:

Include the props option and the prop attribute in the component script:

<script>
export default {
  props: ["textContent"],
//...

Add the data to pass to the app, as a custom attribute of the component:

<template>
//...
  <my-component text-content="Lorem ipsum dolor sit amet." />  

Render the data dyamically in the component, with a template tag:

<template>
//...
    <p>{{ textContent }}</p>

Now the parent app sends the text-content data to the child component, and Vue renders the result to the page.

Click Event

Adding a click event to the component markup is relatively straightforward:

<template>
  <div>
    <h1>My Component</h1>
    <p>{{ textContent }}</p>
    <button @click="replaceText">Replace Text</button>
  </div>
</template>

It is also a good opportunity to change the button label, as the nature of the button event is clarified.

The tricky part comes next, to properly handle passing data changes back to the parent app.

Emits

Emits send data from the child component back to the parent.

Add the click handler to the component element

Add the this.$emit() to the component methods, with reference arguments for the component click event, and any data to pass to the parent app:

//...
  methods: {
    replaceText() {
      // emit custom event
      this.$emit("replace-text", this.textContent);
    },
  },
//...

Add the event listener attribute to the instance of the component in the parent app:

<template>
    <div id="app">
        <my-component
        :text-content="textString"
        @replaceText="replaceComponentText"
        />
//...

Add a method to the parent app, so the parent can run the method from the child component:

//...
methods: {
    replaceComponentText(currentTextContent) {
      // always replace the text content, i.e. avoid duplicates
      while (currentTextContent === this.textString) {
        const rand = getRandomInt(3);
        if (rand === 0) {
          this.textString = this.textStringA;
        } else if (rand === 1) {
          this.textString = this.textStringB;
        } else if (rand === 2) {
          this.textString = this.textStringC;
        }
      }
    },
  },
//...

Optional, but recommended: define emits with the emits property in the component. This helps clarify and make obvious the purpose and function of the emits in the component:

//...
  emits: ["replace-text"],
//...

3. Add Style

Not just style, but dynamic style...

Bind a class to the element and add style properties that depend on dynamic values

<template>
//...
    <p class="dynamic" :class="textContentClass">{{ textContent }}</p>
//...

Set computed properties to influence the dynamic style values:

<script>
//...
  computed: {
    textContentClass() {
      if (this.textContent[0] === "J") {
        return "green-machine";
      } else if (this.textContent[0] === "W") {
        return "bold-and-spicy";
      } else if (this.textContent[0] === "R") {
        return "cool-as-ice";
      } else {
        return "no-style";
      }
    },
  },
//...

And of course add the styles to the component file:

<style>
.no-style {
  font-weight: normal;
  color: inherit;
}
.bold-and-spicy {
  font-weight: bold;
  color: crimson;
}
.cool-as-ice {
  font-style: italic;
  color: rgb(20, 163, 220);
}
.green-machine {
  font-style: normal;
  color: rgb(13, 114, 9);
}
</style>

VS Code Keyboard Moves to Navigate Terminal Windows

These days I'm trying to keep my hands on the keyboard as much as possible. Here are some notes to remind myself how to get around the VS Code interface between code editing panes and terminal windows.

Custom Keybinding to Toggle from Code Pane to Terminal Window

I added this JSON snippet (found somewhere on the Internet, thank you kind stranger) to the VS Code keybindings file. Here is how I did it:

Open the VS Code keybindings JSON file for editing with ctrl+shift+p > Preferences: Open Keyboard Shortcuts (JSON)

Add the following to the file:

[
    {
	"key": "ctrl+;",
	"command": "workbench.action.focusActiveEditorGroup",
	"when": "terminalFocus"
    },
]

Now the ctrl+; key combination smoothly toggles from the code pane to the terminal window/s.

Using Built-In VS Code Keyboard Shortcuts for Terminal Window Navigation

VS Code provides excellent documentation for using the intergated terminal and clear instructions for the defaul keyboard shortcuts to navigate multiple terminals.

From One Group to Another

Navigate between terminal groups using focus next Ctrl+PageDown and focus previous Ctrl+PageUp.

From One Terminal to Another in a Group

Navigate between terminals in a group by focusing the previous pane, Alt+Left, and focusing the next pane, Alt+Right.

Customizing Keybindings for VIM-like Motion across Terminal Groups

Adding this code snippet to VS Code keybindings allows for VIM-like motion keyboard shortcuts to move from one split terminal to the next, and back.

Open the VS Code keybindings JSON file for editing with ctrl+shift+p > Preferences: Open Keyboard Shortcuts (JSON)

[
    {
        "key": "ctrl+shift+j",
	"command": "workbench.action.terminal.focusNext"
    },
    {
	"key": "ctrl+shift+k",
	"command": "workbench.action.terminal.focusPrevious"
    },
]

The VIM paragdigm breaks down at the bottom or top of the terminal group, because VS Code will just loop back to the beginning. Oh well.

Handy Django Test Command Examples

Quick reference of the syntax for running different Django test commands. These were scooped from the excellent book Practical Django 2 and Channels 2 by Federico Marani

$ # Run all the views tests
$ ./manage.py test main.tests.test_views.TestPage

$ # Run the homepage test (specific test run)
$ ./manage.py test main.tests.test_views.TestPage.test_home_page_works

$ # Run all the tests
$ ./mange.py test

PRO TIPS:

--keepdb to keep test db between runs
--failfast to stop tests at first failure