A Full Day of Vue.js

03. Components & Single-File Components

Everything we've discussed thus far has been within the context of a single Vue Instance.

new Vue({
  el: '#app',
});
<body>
 <div id="app"></div>
</body>
new Vue({
  el: '#app',
  data: {},
  created() {},
  computed: {},
  methods: {},
  ...
});

What if our application was really large?

Can we create modules that can group markup and logic separately?

Components

 Vue Components

Vue Components are self-contained modules that can group markup (HTML), logic (JS), and even styles (CSS) within them

Simplest, most straightforward way to create a component:

Vue.component('name-of-component', {});

options

 Vue Components

Vue Components are Vue Instances!

Contain instance data/events/methods except for root-specific functionality (e.g. el)

 Vue Components

 Vue Components

Vue.component('name-of-component', {
  data() {
    return {}
  }
});

Data must be a function for Components!

 Vue Components

Vue.component('name-of-component', {
  template: ``,
});

 Vue Components

Vue.component('hello-world', {
  template: '<div>Hello World</div>',
});

 Vue Components

Vue.component('hello-world', {
  template: `
    <div>
     <h1>Hello World</h1>
     <p>This is the Hello World component</p>
    </div>
  `,
});

 Vue Components

Must have a single root element

Vue.component('tweet-component', {
  template: `
    <div class="tweet" v-for="tweet in tweets" :key="tweet.id">
      <div class="box">
        <article class="media">
          <div class="media-left">
            <figure class="image is-64x64">
              <img :src="tweet.img">
            </figure>
          </div>
          <div class="media-content">
            <div class="content">
              <p>
                <strong>{{tweet.name}}</strong>
                <small>{{tweet.handle}}</small>
                <br>
                {{tweet.tweet}}
              </p>
            </div>
              <div class="level-left">
                <a class="level-item">
                  <span class="icon is-small">
                    <i class="fas fa-heart"></i>
                  </span>
                  <span class="likes">{{tweet.likes}}</span>
                </a>
              </div>
          </div>
        </article>
      </div>
      <div class="control has-icons-left has-icons-right">
        <input class="input is-small" placeholder="Tweet your reply..." />
        <span class="icon is-small is-left">
          <i class="fas fa-envelope"></i>
        </span>
      </div>
    </div>`
});

 Vue Components

Vue.component('tweet-component', {
  template: `
    <div class="tweet" v-for="tweet in tweets" :key="tweet.id">
      // ...
     </div>
  `,
});

tweets is unrecognizable here

tweet-component shouldn't render a list of tweets

 Vue Components

Vue Instance

tweet-component

tweets
props

 Vue Components

Props allow us to pass data from parent instance/component down to child components.

 Vue Components

2 things to do to declare props

1. Declare the value of the prop attribute where the child component is being rendered.

<component greeting="Hello!"></component>

2. Have the child component declare the props it receives in a props option.

Vue.component('component', {
  props: ['greeting'],
});

 Vue Components - Props

2 things to do to declare props

1. Bind the value of the prop attribute where the child component is being rendered.

<tweet-component v-for="tweet in tweets"
                 :key="tweet.id"
                 :tweet="tweet">
</tweet-component>

2. Have the child component declare the props it receives in a props option.

Vue.component('tweet-component', {
  props: ['tweet'],
});

 Vue Components - Props

Vue.component('tweet-component', {
  props: {
    tweet: {
       type: Object,
     required: true
   }
  },
});

We can also specify prop validation requirements in the props option.

 Vue Components - Props

Vue.component() creates the component globally.

 Vue Components - Props

Vue.component('tweet-component', {
  // ...
});

As long as we construct the component before instance creation - the component is registered globally

 Vue Components - Props

We could instead define components as plain objects.

Vue.component('name-of-component', {
  template: ``,
});
const nameOfComponentObject = {
  template: ``,
};

 Vue Components - Component Registration

For us to use the component created object, we'll have to register it in a components property in the parent.

new Vue({
  // ...,
  components: {
    'name-of-component': nameOfComponentObject
  }
});
Component Object
Name of Component in template
<name-of-component></name-of-component/>

 Vue Components - Component Registration

const tweetComponent = {
  template: `...`,
  props: ['tweet']
};

new Vue({
  // ...,
  components: {
    'tweet-component': tweetComponent
  }
});

 Vue Components - Component Registration

Components can be nested multiple levels deep.

Vue Instance

Component #1

Component #2

Component #3

props
props
props

Important Note: Props (data) can only be passed downwards!

 Vue Components - Component Registration

 Vue Components - Component Registration

 Vue Components - Component Registration

const tweetContent = {
  template: `..`,
  props: ['tweet']
}

const tweetComponent = {
  template: `...`,
  props: ['tweet'],
  components: {
    'tweet-content': tweetContent
  }
};

new Vue({
  // ...,
  components: {
    'tweet-component': tweetComponent
  }
});

tweet

tweet

Ways to define a Vue Component

1. Global Vue Components

2. Component Objects

Vue.component('name-of-component', {
  // options
});
const nameOfComponentObject = {
  // options
};

3. Single File Components!

Template options are in strings (or back-ticks). No syntax highlighting.

No isolated CSS styling.

Disadvantages of 1. and 2.

 Vue Components - Component Registration

Single File Components allow us to define HTML/CSS and JS of a component all within a single .vue file

 Vue Components - Single File Components

Single File Components contain three parts

  • <template> which contains the component’s markup in plain HTML

 Vue Components - Single File Components

  • <script> which consists of all the JS logic within the component

  • <style> which contains all the component styles

<template>
  <div class="hello-world">
    <h2>{{ getGreeting }}</h2>
    <p>This is the Hello World component.</p>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      reversedGreeting: '!dlrow olleH'
    } 
  },
  computed: {
    getGreeting() {
      return this.reversedGreeting.split("").reverse().join("");
    }
  }
}
</script>

<style scoped>
.hello-world {
  width: 100%;
  text-align: center;
}
</style>

 Vue Components - Single File Components

HelloWorld.vue

What are all these other files?

package.json | index.html | main.js | etc.

 Vue Components - Single File Components

Single File Components are only made possible with build tools like Webpack.

These tools work alongside built Vue packages (e.g. vue-loader library) to compile .vue components to plain JavaScript modules that can be understood in browsers.

 Vue Components - Single File Components

*Webpack is a module bundler.

This is where we level up from:

Simple Standalone Vue Applications

Webpack bundled Vue Applications

 Vue Components - Single File Components

But...how do we set up a Webpack bundled Vue application?

🤔 

 Vue Components - Single File Components

Setting up a Webpack based project often involves understanding how to set up:

  • Webpack Configuration

  • Babel Configuration

  • Styles Preprocessing (if we use SASS/LESS)

  • ESLint (if we'd like a linter)

  • Vue Single-File Compilation

....

😓 

 Vue Components - Vue Cli

The vue-cli (i.e the Vue command line interface) is a tool built by the Vue.js team to help facilitate the rapid building and developing of Vue applications.

 Vue Components - Vue Cli

Using the vue-cli

Assuming you have npm (or yarn) and Node already installed

npm install -g @vue/cli
vue create name_of_project

1. Install the vue-cli globally

2. Create a new Vue project

3. Follow the prompts and create!

 Vue Components - Vue Cli

Let's see this in action!

 Vue Components - Vue Cli

 Vue Components - Vue Cli

Quick walkthrough of a vue-cli scaffolded project:

  • babel.config.js: Configuration of Babel presets and plugins to transpile ES6 JS

  • node-modules/: All the different libraries that have been installed.

  • package.json: Listing of all installed libraries.

Listing of script commands to serve, build, and lint an app.

Can contain certain Webpack configuration if intended.

  • public/: Contains the root markup page (index.html)

  • src/: Contains all Vue code

. . .

 Vue Components - Vue Cli

 Vue Components - Vue Cli

new Vue({
  render: h => h(App)
}).$mount('#app');

 Vue Components - Vue Cli

.$mount('#app')

is somewhat equivalent to

el: '#app'

Main difference being we can call mount after the instance has been instantiated.

 Vue Components - Vue Cli

new Vue({
  render: h => h(App)
}).$mount('#app');
render (createElement) {
  return createElement(App);
}
render (h) {
  return h(App);
}
render: h => h(App)
Helpful Article (Sarah Drasner): 
what-does-the-h-stand-for-in-vues-render-method/
Helpful Comment (Bobby Juncosa): 
What is render: h => h (App)

 Vue Components - Vue Cli

new Vue({
  el: '#app',
  template: '<App />'
  components: { App }
});

We can also stick with this - with which we're more familiar with!

Single File Components - Separation of concerns, but more fine-grained

Templates

Scripts

Styles

SFC

SFC

SFC

 Vue Components - Chapter Summary!

  • Vue Components are self-contained modules that can group markup, logic, and even styles.

Global Components:
Component Variables:
Single File Components
Vue.component('name-of-component', {});
const nameOfComponentObject = {};
  • Single File Components allow us to define HTML/CSS and JS of a component within a single .vue file

<template> section - HTML
<script> section - JS
<style> section - CSS
  • Props (data) can only be passed downwards in a single direction (parent - child - etc.).

  • vue-cli can help facilitate the rapid building and developing of Vue applications.

npm install -g @vue/cli
vue create name_of_project

 Vue Components - Chapter Exercise 💪!

With Single-File Components and in a module based Vue application.

 Vue Components - Chapter Exercise 💪!

SubmissionComponent

SubmissionContent

SubmissionComponent

SubmissionContent

 Vue Components - Chapter Exercise 💪!

Complete example from last exercise - Codepen

Starting Point - CodeSandbox

Solution 👀 - CodeSandbox 

Made with Slides.com