DEV Community

Cover image for Intro to the Vue Framework
sandrockj
sandrockj

Posted on

Intro to the Vue Framework

What is Vue?

from the Vue website
Vue is a "progressive" JavaScript framework for building user interfaces. It works by building on top of standard HTML, CSS, and JavaScript. It is a component-based programming model similar to that of Anuglar, AngularJS, and React. As a framework, Vue aims to be flexible so that it can adapt to the projects of any scale. It can be implemented for any purpose ranging from creating a static HTML page, embedding web components, and dynamic DOM rendering based on server interactions.

What are the strengths of the Vue framework?

from the Vue website
- Single-File Components (SFC) provide a modularized development model that allows different parts of an application to be developed in isolation.
- Composition API enables clean patterns for organizing, extracting, and reusing complex logic.
- Comprehensive tooling support ensures a smooth development experience as the application grows, which can translate to a more efficient development cycle.
- Lower barrier to entry and excellent documentation translates to lower onboarding/training costs for new developers.

The Basics of the Vue Framework

How can Vue be used to render items to the page?

A simple Component example

<script setup>
  import { ref } from 'vue'

  // A "ref" is a reactive data source that stores a value.
  const message = ref('Hello World!')
</script>

<template>
  <h1>{{ message }}</h1>
</template>
Enter fullscreen mode Exit fullscreen mode
  1. We import the ref() function from Vue, which allows us to reference a reactive data source.
  2. We declare a constant variable message which refers to the string 'Hello World'.
  3. Our template uses this constant variable, specifically the value it references, to render to the Document Object Model (DOM).

How can Vue be used to handle user input fields?

Initializing scripts for the Component

<script setup>
    import { ref } from 'vue'

    const message = ref('Hello World!')

    function reverseMessage() {
      message.value = message.value.split('').reverse().join('')
    }

    function notify() {
      alert('navigation was prevented.')
    }
</script>
Enter fullscreen mode Exit fullscreen mode
  1. The ref() function is imported from Vue.
  2. The ref() function is used to refer to a message.
  3. We define two functions in our scripts, so that we can use them in our templates. Function reverseMessage() can be used to modify the render for our reference message. Function notify() can be used to alert the user if something went wrong.

Creating the template for the Component

<template>
  <h1>{{ message }}</h1>

  <button @click="reverseMessage">Reverse Message</button>
  <button @click="message += '!'">Append "!"</button>

  <a href="https://vuejs.org" @click.prevent="notify">
    A link with e.preventDefault()
  </a>
</template>
Enter fullscreen mode Exit fullscreen mode
  1. The template section will render to the page, and we begin by displaying the referenced message within header tags.
  2. We create one button with a 'click' event listener, which references the reverseMessage() function that we defined in our scripts. Another button is also created, but in this case we use an in-line expression to edit our referenced message.
  3. On our hypertext reference link, we add a specialized 'click' event listener by chaining 'prevent' to the event listener. This is how Vue can be used to prevent defaults!

Optional styling for the Component

<style>
    button, a {
      display: block;
      margin-bottom: 1em;
    }
</style>
Enter fullscreen mode Exit fullscreen mode

How does Vue handle attribute bindings and states?

Initializing scripts for the Component

<script setup>
import { ref } from 'vue'

const message = ref('Hello World!')
const isRed = ref(true)
const color = ref('green')

function toggleRed() {
  isRed.value = !isRed.value
}

function toggleColor() {
  color.value = color.value === 'green' ? 'blue' : 'green'
}
</script>
Enter fullscreen mode Exit fullscreen mode
  1. First, we reference the data message that we will eventually render.

  2. We also reference constant variable isRed to the boolean true. Function toggleRed() is used to toggle this referenced value to either true or false.

  3. We also reference constant variable color to the string 'green'. Function toggleColor() is used with a ternary operator, toggling the reference value to a string of either 'green' or 'blue'.

  4. The references declared in these scripts enables a developer to initialize the state, and then the functions declared therein may also be used to manage/modify the state of the page.


Creating the template for the Component

Now that we have our state initialized, in addition to the tools necessary to modify it, we can begin working on our template. This is where 'fusion' occurs; at this stage we implementing our state references and functions to actually modify what is rendered!

<template>

                                  <!-- 1 -->
  <p>
    <span :title="message">
      Hover your mouse over me for a few seconds to see my dynamically bound title!
    </span>
  </p>

                                  <!-- 2 -->
  <p :class="{ red: isRed }" @click="toggleRed">
    This should be red... but click me to toggle it.
  </p>

                                  <!-- 3 -->
  <p :style="{ color }" @click="toggleColor">
    This should be green, and should toggle between green and blue on click.
  </p>

</template>

<style>
    .red {
      color: red;
    }
</style>
Enter fullscreen mode Exit fullscreen mode

Let's break down what is happening here; each paragraph listed above is denoted with a corresponding number:

  1. In the first paragraph, we target the 'title' property of the current HTML element.

    1. The 'title' property is set equal to that of our referenced message in scripts.
    2. When the output is hovered, our message will display!
  2. In the second paragraph, we are targeting the 'red' class property and we are setting it equal to the current value of isRed.

    1. On a click event the toggleRed() function determines a trueor falseboolean.
    2. The state reference value isRed is assigned to this trueor falseboolean.
    3. When the boolean changes our render will dynamically react to this change; this is because the template is referencing ref() the state of isRedand will change dynamically when this state value is changed.
  3. In the third paragraph, we are targeting the 'style' property and we are setting it equal to the current value of color.

    1. On a click event the toggleColor() function determines a string value.
    2. The state reference value color is reassigned to this string value.
    3. Because our paragraph refers to the value of color, our paragraph styling property is reassigned the value of color.

How does Vue implement conditionals and loops?

Let's take our approach closer to the real-world, so that we can start understanding what the actual workflow would look like when we are working on our own. First, let's start by creating a template of everything we might want to render to the DOM.

Initializing a Component

<template>
  <button>Toggle List</button>
  <button>Push Number</button>
  <button>Pop Number</button>
  <button>Reverse List</button>

  <ul>
    <li></li>
  </ul>
</template>
Enter fullscreen mode Exit fullscreen mode

For now, we have created a few buttons that will be statically rendered to the DOM. We also have created an unordered list, but right now we don't know how long our list will be and we don't even know what we want it to display. At this point, we need to understand what our objectives are.

  1. The button Toggle List will hide our unordered list.
  2. The button Push Number will add an item to our list.
  3. The button Pop Number will remove an item from our list.
  4. The button Reverse List should change the render, causing the list to be displayed in reverse.
  5. Our unordered list needs to reflect a collection of items, and each item needs to be dynamically rendered to the DOM.

I think it is best that we start with displaying each item of our list, so that way we have a way to visualize the DOM before we start implementing scripts that will change what is rendered. In this case, we want our unordered list to have a new list entry for every item in a collection of data.


Adding references and looping through a collection

<script setup>
    import { ref } from 'vue'
    const list = ref([1, 2, 3])
</script>

<template>
  <button>Toggle List</button>
  <button>Push Number</button>
  <button>Pop Number</button>
  <button>Reverse List</button>

  <ul>
    <li v-for="listEntry of list">{{listEntry}}</li>
  </ul>
</template>
Enter fullscreen mode Exit fullscreen mode

Great, now we have established a reference to a collection within our scripts! Let's see if we can break down what we did here into something that we can understand.

  1. The constant variable list refers to a collection (array of numbers).
  2. The list entry now has an attribute respective to the v-for directive. ######1. The v-for directive receives a collection, and iterates over every item it contains. ######2. As the v-for directive is looking at the current item, it creates a new list entry and inserts the specified data there. ######3. In this case we are displaying the entire item in the collection, but that is okay because our collection is only primitive data types and not nested arrays or objects.

Now that we have a way to dynamically render these items, we can review the functionality of our buttons. We will start with the Toggle List button for the time being. In this case, we want the display of our list to switch between two states 'shown' and 'hidden'. Because there are only two states, we can think of this as a true or false expression.


Adding to our Component states

<script setup>
    import { ref } from 'vue'
    const list = ref([1, 2, 3])
    const show = ref(true)
</script>

<template>
  <button @click="show = !show">Toggle List</button>
  <button>Push Number</button>
  <button>Pop Number</button>
  <button>Reverse List</button>

  <ul>
    <li v-for="listEntry of list">{{listEntry}}</li>
  </ul>
</template>
Enter fullscreen mode Exit fullscreen mode
  1. First we declare a constant variable show in our scripts. It refers to a boolean value.
  2. After we add this variable, we can use it for managing the state of content on our page.
  3. We attach a click event listener to the Toggle List button. On click, an expression is evaluated. This inverts the current value of the show variable.

We are close to implementing this functionality, but now we need to account for some edge conditions. What if our list is empty? What if our list is hidden, but it isn't empty? Our current design establishes a way to toggle whether something is rendered to the DOM, but there are no conditional expressions that rely on the state of the show variable. Let's fix that.


Adding conditional expressions to check our states

<script setup>
    import { ref } from 'vue'
    const list = ref([1, 2, 3])
    const show = ref(true)
</script>

<template>
  <button @click="show = !show">Toggle List</button>
  <button>Push Number</button>
  <button>Pop Number</button>
  <button>Reverse List</button>

  <ul v-if="show && list.length">
    <li v-for="listEntry of list">{{listEntry}}</li>
  </ul>
</template>
Enter fullscreen mode Exit fullscreen mode

First, we have added a Vue directive known as v-if to our unordered list. When the DOM attempts to render the list, it first checks the following conditions:

1. If the value of show is true.
2. If the value of list.length is above zero (a truthy value).

If either of these conditions fail, with our current implementation, it would refuse to render the list to the DOM. However, we want to be a bit clearer with our implementation. In this case, we want to expand our conditional expressions so that they will inform the user about the current state of the list.

1. If the list is hidden, but the list is not empty, then we want a message reflecting that.
2. If the list is empty (list.length === 0), then we want a message reflecting that.

Other modifications to states

<script setup>
    import { ref } from 'vue'
    const list = ref([1, 2, 3])
    const show = ref(true)
</script>

<template>
  <button @click="show = !show">Toggle List</button>
  <button>Push Number</button>
  <button>Pop Number</button>
  <button>Reverse List</button>

  <ul v-if="show && list.length">
    <li v-for="listEntry of list">{{listEntry}}</li>
  </ul>
  <p v-else-if="list.length">List is not empty, but hidden.</p>
  <p v-else>List is empty.</p>
</template>
Enter fullscreen mode Exit fullscreen mode

At this point, we should now have three conditions which are capable of informing the end-user about the state of the list that they are interacting with. This is great progress, but we still need to implement the rest of our buttons. You might notice that, in the previous examples, we are using the properties and methods native to the JavaScript Array prototype. Because we have this functionality, we can interact with our list in the same way.


Final version of our Component

<script setup>
    import { ref } from 'vue'
    const list = ref([1, 2, 3])
    const show = ref(true)
</script>

<template>
  <button @click="show = !show">Toggle List</button>
  <button @click="list.push(list.length + 1)">Push Number</button>
  <button @click="list.pop()">Pop Number</button>
  <button @click="list.reverse()">Reverse List</button>

  <ul v-if="show && list.length">
    <li v-for="listEntry of list">{{listEntry}}</li>
  </ul>
  <p v-else-if="list.length">List is not empty, but hidden.</p>
  <p v-else>List is empty.</p>
</template>
Enter fullscreen mode Exit fullscreen mode

At this point, our DOM should have all of the functionality that we originally set out for it to have! This is what is so powerful about Vue; despite the fact that many similar frameworks and libraries can accomplish this, the approach with Vue feels more natural and developer-friendly.

In the beginning, we starting with a basic and static HTML page. We increased our scale slightly when we made our page somewhat dynamic; we added a reference to list and we also added a directive that helped dynamically render items from that list.

After we added this somewhat dynamic feature, we expanded upon it so that other items could change the state of the DOM. In this case, we increased our scale again as we began handling more states.

If we began increasing our scale further, such as in the case were the list reference pointed to data that is received from the server, then we already have a solid foundation that can be tweaked to reflect data appropriately.


How does Vue interact with other components?

So far, we have only looked at how an individual component can change what is rendered to the DOM. However the reality is that, in most cases, your components should be interacting with one another so that you can reuse them in other parts of the DOM. Let's take a look at an example with a simple component.

Scripts for our Component

<script setup>
import { ref } from 'vue'
import TodoItem from './TodoItem.vue'

const groceryList = ref([
  { id: 0, text: 'Vegetables' },
  { id: 1, text: 'Cheese' },
  { id: 2, text: 'Whatever else humans are supposed to eat' }
])
</script>
Enter fullscreen mode Exit fullscreen mode

We import the ref() function from Vue, but we are also importing the component TodoItem so that we can use it inside of this component. Because subcomponents must be imported and implemented, this creates a separation of concerns.

In separations of concerns, the system's components are organized in a way where each component addresses a single concern; the concern could be simple or it could address a (larger) specific functionality for the DOM. This means that each component only interacts with other components when necessary; this is especially beneficial for ensuring that the overall state of our DOM is not affected when we only want changes to occur within a specific component's scope.

Before we move onto our template for this component, we should understand how the subcomponent that it has imported will work. After all, if we don't know what it is doing then we don't know how to use that component.


The TodoItem Component

<script setup>
  const props = defineProps({
    todo: Object
  })
</script>

<template>
  <li>{{ todo.text }}</li>
</template>
Enter fullscreen mode Exit fullscreen mode

It looks like when this component is being setup, it is defining its own properties props to include a key todo that will be assigned to the value of an object. In this case, the properties are looking back to see which data was passed to it as an attribute. Specifically, it is looking for an attribute name todo and it is expecting it to be an Object instance. More documentation on the defineProps() function can be found here.

After the object has been received, the TodoItem component tries to render the text property from the object that has been passed into it. If we have passed the values to it properly, then this should render whatever the value of the text property is for that object. Now we can take a look at how our main App component will try to use the TodoItem component when it renders.


Our template references the TodoItem Component

<template>
  <ol>
    <TodoItem
      v-for="item in groceryList"
      :todo="item"
      :key="item.id"
    ></TodoItem>
  </ol>
</template>
Enter fullscreen mode Exit fullscreen mode

Inside of our template we are using the Vue directive v-for to iterate through the groceryList collection, which is an array of objects. However, in this case, we are referencing the component TodoItem which we imported earlier. In this case, we are saying the following:

  1. For each item (object) in groceryList (array), pass the item to the TodoItem component.
  2. TodoItem receives two attributes during each iteration:

    1. The todo attribute stores the item (object).
    2. The key attribute is used to create a unique 'key' for each item.
  3. We expect that, for every item in our collection, the TodoItem component will return something to be rendered to the DOM.


Conclusion

I hope that you found this introduction to Vue somewhat helpful, it was a pleasure to research into how this framework can be used to make developers more efficient and effective. If you are familiar with similar frameworks and libraries, you might still be wondering whether or not Vue is something that you would want to use for your own projects. If you feel that way, I recommend that you read through Vue's FAQ to see if its benefits fit the needs of your team, project, or organization.

Is the knowledge of the Vue framework in demand?

According to the 2023 StackOverflow Developer Survey, Vue ranked eighth for one of the most popular web frameworks and technologies at 16.38%. In comparison, similar frameworks and libraries such as React ranked second at 40.58% whereas Angular ranked fifth at 17.46%.

Who uses the Vue framework?

from the Vue website
Vue is one of the most widely used JavaScript frameworks in production today, with over 1.5 million users worldwide. It is downloaded approximately 10 million times a month on Node Package Manager (NPM)!
      - Wikimedia Foundation
      - National Aeronautics and Space Administration (NASA)
      - Apple
      - Google
      - Microsoft
      - GitLab
      - Zoom
      - Tencent
      - Weibo
      - Bilibili
      - Kuaishou

Top comments (0)