Skip to content

Vue Basics ​

Vue uses vue-router for links

<router-link to="/foo">Go to Foo</router-link>

https://router.vuejs.org/guide/
Getting Started | Vue Router
https://router.vuejs.org/api/#router-link
API Reference | Vue Router

Single File Components ​

A concise way to combine the markup (<template>), logic (<script>) and styling (<style>) in a single .vue file.

Often makes use of the "Options API" (vs. the "Composition API" in vue3), but not exclusively.

Web components done right!

https://v3.vuejs.org/guide/single-file-component.html

https://v3.vuejs.org/guide/component-basics.html

https://vuejs.org/v2/guide/components.html#Dynamic-Components Components Basics — Vue.js

<script>
export default {
  data() {
    return {
      greeting: 'Hello World!'
    }
  }
}
</script>

<template>
  <p class="greeting">{{ greeting }}</p>
</template>

Templates ​

https://vuejs.org/v2/guide/syntax.html

Conditional Rendering ​

https://vuejs.org/v2/guide/conditional.html

<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

For Loops ​

List rendering
https://vuejs.org/v2/guide/list.html#key

https://stackoverflow.com/questions/44617484/vue-js-loop-via-v-for-x-times-in-a-range
javascript - Vue Js - Loop via v-for X times (in a range) - Stack Overflow

    <li v-for="n in 10" :key="n">{{ n }} </li>

See all keys / values in a given object:

    <ul>
      <li v-for="key in Object.keys(item)" :key="key">
        {{ key }}: {{ item[key] }}
      </li>
    </ul>

Scripts ​

The script block is where you put logic related to your component.

data is made up of properties
computed is made up of getters.

via:
https://stackoverflow.com/questions/58931647/nuxt-component-computed-vs-data

Computed ​

A computed method will respond to changes made to data properties of the component. Similar to watch. Like a method that is called automatically.

Note: In Vue3 (maybe Vue2 also?), the computed function must be referenced somewhere in the template, otherwise it will not ever trigger!

Binding values ​

How to share data between the <template> and <script>?

Typically, just use a v-model to handle coordinating values.

<input v-model="search">

Some cases where it's easier to separate the value from what action you want to take when events occur

      <textarea
        class="resize min-h-screen w-3/4 m-auto"
        :value="articleString"
        @input="updateObject"
      />
  methods: {
    updateObject(event) {
      console.log('updateObject', event.target.value)
    }
  }

https://dilshankelsen.com/v-model-with-vuex/
How To Use V-Model With Vuex | Dilshan Kelsen

Styles (CSS) ​

Styling will depend a lot on how you configure your application, which front-end CSS framework you choose, etc.

Reminder: Anything one-off or customizable should go in the corresponding web-compenent file. A CSS utility framework like Tailwind makes this even more streamlined!

Attributes ​

Trigger if an attribute is added to a DOM element using a boolean value in the script. For example

:disabled="foo"
<textfield label="Name" value.sync="el.name" :disabled="myVar">

Then in Vue you can just set this.myVar = true and it will disable the input.

https://stackoverflow.com/questions/39247411/how-to-add-dynamically-attribute-in-vuejs

It's possible to use a similar approach to add a class conditionally:

:class="{ 'light-background': index % 2 }"

Dynamic Styles ​

Using variable in vue component to affect CSS styles

https://stackoverflow.com/questions/47322875/vue-js-dynamic-style-with-variables
css - Vue.js dynamic style with variables - Stack Overflow

https://stackoverflow.com/questions/42872002/in-vue-js-component-how-to-use-props-in-css/52280182#52280182
In vue.js component, how to use props in css? - Stack Overflow

<template>
  <div id="a" :style="style" @mouseover="mouseOver()">
  </div>
</template>

<script>
  export default {
    name: 'SquareButton',
    props: ['color'],
    computed: {
      style () {
        return 'background-color: ' + this.hovering ? this.color: 'red';
      }
    },
    data () {
      return {
        hovering: false
      }
    },
    methods: {
      mouseOver () {
       this.hovering = !this.hovering
      }
    }
  }
</script>

<style scoped>
<style>
      :style="{
          top: marginTop,
          left: marginLeft,
          width: maxSquare,
          height: maxSquare,

      }"

generating the whole style dictionary in a computed didn't work: :style="margins"

See also ~/design_system/ui/pages/windows.vue

Custom Events / Event Bus ​

If you need to signal a parent component of something that has happened in a child component, use $emit.

Child component triggers clicked event:

export default {
  methods: {
    onClickButton (event) {
      this.$emit('clicked', 'someValue')
    }
  }
}

Parent component receive clicked event:

<div>
  <child @clicked="onClickChild"></child>
</div>

Then, in the parent script block, handle the emitted event as needed:

export default {
  methods: {
    onClickChild (value) {
      console.log(value) // someValue
    }
  }
}

via: https://forum.vuejs.org/t/passing-data-back-to-parent/1201

For multiple levels of children components, there is vm.$listeners

https://vuejs.org/v2/api/#vm-listeners

https://stackoverflow.com/questions/42615445/vuejs-2-0-emit-event-from-grand-child-to-his-grand-parent-component

Note:
If you've hit a situation where an event bus pattern comes up, it may be a good time to consider State Management patterns.

Slots & Props ​

Use Props when you want to pass in a js object to a child component.

Use Slots when you want to pass in template markup to a child component.

https://medium.com/@nicomeyer/vue-js-slots-vs-props-af87078a8bd Vue.js: slots vs. props - Nico Meyer - Medium

Props ​

Example props. Linters may encourage the full form

  // https://vuejs.org/v2/guide/components-props.html#Type-Checks
  // String, Number, Boolean, Array, Object, Date, Function, Symbol
  props: {
    person: {
      type: Object,
      default: () => {},
    },
    list: {
      type: Array,
      default: () => [],
    },
    parameter: {
      type: String,
      default: 'Greetings',
    },
    something: Boolean,
  },

https://vuejs.org/v2/guide/components-props.html Props — Vue.js

Watching Props ​

Sometimes props arrive to the child component after the component's .mounted() call happens. In these cases, it's necessary to watch for the arrival of the prop from the parent:

  watch: {
    // Sometimes you want to act on the values that changed
    // propertyName: function (newVal, oldVal) {
    propertyName: function () {
      // console.log('property value changed', newVal)
      this.methodToHandleUpdate()
    },
  },

via

Slots ​

Pass in customized markup content from the parent template.

Named slots are handy for layout components:

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

via:
https://v3.vuejs.org/guide/component-slots.html#named-slots

https://vuejs.org/v2/guide/components-slots.html#Scoped-Slots
Slots — Vue.js
https://github.com/vuejs/rfcs/blob/master/active-rfcs/0001-new-slot-syntax.md
rfcs/0001-new-slot-syntax.md at master · vuejs/rfcs
https://www.google.com/search?client=ubuntu&channel=fs&q=vue+props+vs+slots&ie=utf-8&oe=utf-8
vue props vs slots - Google Search

Layouts ​

Slots get us most of the way there for a layout pattern.

https://markus.oberlehner.net/blog/dynamic-vue-layout-components/

Some vue-based framework pre-configure a layout pattern for us, however it can help to understand the pattern at work in cases where those frameworks are not a good fit.

https://awesome-vue.js.org/components-and-libraries/ui-layout.html

Forms ​

Heavy overlap with Web Components & UI Frameworks.

It helps to study the underlying mechanisms of syncing form content with the local script and parent components.

TODO: v-model binding in vue2? or is that a new feature with vue3?

https://duckduckgo.com/?t=ffab&q=creating+form+components+vue3&ia=web
creating form components vue3 at DuckDuckGo
https://javascript.plainenglish.io/how-to-build-flexible-form-factory-by-vue-3-form-builder-pattern-b88edaf94776
Building a dynamic and scalable Form Factory by Vue 3 | JavaScript in Plain English

Routing ​

Router

In your script section, use:

router.push({name: "yourroutename")

router.push("yourroutename") is NOT the same as router.push({name: "yourroutename"). First one defines the route directly. The second one takes the route with the specified name.

via: https://stackoverflow.com/questions/35664550/vue-js-redirection-to-another-page

see also: router-link and nuxt-link

Style Guide / Naming Conventions ​

General conventions

Components should use more than one word in the name.

Filenames of single-file components should either be always PascalCase or always kebab-case.

via
same in vue3

In Javascript, camelCase is typically used for most variable and method names in code.

Components are typically named in PascalCase.

kebab-case is recommended when using components in template markup. I also prefer kebab-case for filenames too.

I find it's more difficult to navigate on the command line when cases are mixed. Have to remember to type upper-cased characters. There are some filesystems that don't support case-sensitivity, but that should be moot in most cases.

This is a good discussion on the topic

https://github.com/vuejs/vuejs.org/issues/1162
Naming in PascalCase or kebab-case · Issue #1162 · vuejs/vuejs.org

Environment Variables (dotenv) ​

Automatic importing / Bundle Size / Tree-shaking ​

In an effort to minimize bundle size, it helps to only import the code being used.

https://github.com/antfu/unplugin-vue-components#readme

unplugin-vue-components helps import components automatically, which in turn helps with tree-shaking.

This is the approach recommended by some ui-frameworks, like Element+:

https://element-plus.org/en-US/guide/quickstart.html#on-demand-import

https://rollupjs.org/guide/en/#tree-shaking

Troubleshooting ​

If a console.print() statement is not showing what you expect (especially in the context of a computed value), be sure to render the value in a template.

    <button @click="selected = 1">
      test select
    </button>
    {{ selected }}