Use v-bind for prop destructuring

Use v-bind as kind of a “prop destructuring” instead of passing multiple object properties into a component as props.
<template>
  <post
    :id="post.id"
    :title="post.title"
    :author="post.author"
  />
  
  <!-- This (↑) is the same as this (↓) -->

  <post v-bind="post" />
</template>

<script>
// <post> component definition
export default {
  props: {
    id: Number,
    title: String,
    author: Object
  }
}
</script>

This tip originally appeared as a tweet.

Manage Document Title

Update the document’s title with reactive data.
<script>
new Vue({
  el: '#app',
  data: () => ({
    documentTitle: document.title
  }),
  watch: {
    documentTitle: {
      immediate: true,
      handler (value) {
        document.title = value
      }
    }
  }
})
</script>

Since the root Vue instance is almost always initialized on a child element of <body>, we don’t have access to elements in <head>. The solution is actually very simple: to watch a data attribute that corresponds to the document title, and then use DOM functions for updating.

This is only a proof of concept. If you want full power over a document’s meta with SSR support, take a look at vue-meta.

Methods to computed properties

When you find yourself in need of using an argument for a computed property, consider creating and moving the logic into a child component.
<!-- BEFORE -->
<template>
  <section class="posts">
    <article v-for="post in posts">
      <a :href="getUrl(post)">{{ getTitle(post) }}</a>
    </article>
  </section>
</template>

<script>
export default {
  methods: {
    getUrl (post) { ... },
    getTitle (post) { ... }
  }
}
</script>


<!-- AFTER -->
<!-- 1. PostList.vue -->
<template>
  <section class="posts">
    <PostItem v-for="post in posts" :post="post"/>
  </section>
</template>

<!-- 2. PostItem.vue -->
<template>
  <article v-for="post in posts">
    <a :href="url">{{ title }}</a>
  </article>
</template>

<script>
export default {
  props: ['post'],
  computed: {
    url () { /* compute on this.post */ },
    title () { /* compute on this.post */ }
  }
}
</script>

This results in simpler and decoupled components, structured and moduralized code, plus you have the benefits of computed property’s caching for free.

Originally tweeted by @alexjoverm.

Long press directive

A simple directive to execute a function when the element is long-pressed.
<template>
  <button v-longpress='showOptions'>Hold me for a while</button>
</template>

<script>
const PRESS_TIMEOUT = 1000

Vue.directive('longpress', {
  bind: function (el, { value }, vNode) {
    if (typeof value !== 'function') {
      console.warn(`Expect a function, got ${value}`)
      return
    }

    let pressTimer = null

    const start = e => {
      if (e.type === 'click' && e.button !== 0) {
        return;
      }

      if (pressTimer === null) {
        pressTimer = setTimeout(() => value(e), PRESS_TIMEOUT)
      }
    }

    const cancel = () => {
      if (pressTimer !== null) {
        clearTimeout(pressTimer)
        pressTimer = null
      }
    }

    ;['mousedown', 'touchstart'].forEach(e => el.addEventListener(e, start))
    ;['click', 'mouseout', 'touchend', 'touchcancel'].forEach(e => el.addEventListener(e, cancel))
  }
})
</script>

A more in-depth article with commented code can be found here.

Smarter Watchers

Watchers that are called immediately when the component is ready.
watch: {
  searchText: {
    handler: 'fetchUserList',
    immediate: true
  }
},

methods: {
  fetchUserList () {
    //
  }
}

Fetch and display HTML

Sometimes you just want to fetch some HTML from the server, display them right in your application, and call it done.
<template>
  <html-fetcher url="/your/static/content.html"/>
</template>

<script>
import axios from 'axios'

Vue.component('html-fetcher', {
  template: '<div>Loading…</div>',
  props: ['url'],
  mounted () {
    axios.get(this.url).then(({ data }) => this.$el.outerHTML = data)
  }
})
</script>

Detect if user has scrolled to bottom

Detect if the user has scrolled to bottom of a container element and executed a function (for example, load more posts à la infinite scrolling).
<template>
  <div @scroll="onScroll"></div>
</template>

<script>
export default function () {
  methods: {
    onScroll ({ target: { scrollTop, clientHeight, scrollHeight }}) {
      if (scrollTop + clientHeight >= scrollHeight) {
        this.loadMorePosts()
      }
    }
  }
}
</script>

Click Away

A simple directive that triggers a function if the user clicks outside of the bound element.
<template>
  <div v-clickaway="hideMe">Hide me</div>
</template>

<script>
Vue.directive('clickaway', {
  bind (el, { value }) {
    if (typeof value !== 'function') {
      console.warn(`Expect a function, got ${value}`)
      return
    }

    document.addEventListener('click', e => el.contains(e.target) || value())
  }
})

export default {
  methods: {
    hideMe () {
      // your logic here
    }
  }
}
</script>

Debounce

Prevent your methods or events from being executed so often using lodash’s debounce() function.
<template>
  <input type="search" v-on:input="filter">
</template>

<script>
import { debounce } from 'lodash'

export default {
  methods: {
    filter: debounce(function () {
      // your logic here
    }, 200)
  }
}
</script>