Categories
Vue 3

How to Build a Tab Component with Vue.js 3?

Sometimes, we may want to display things in tabs.

In this article, we’ll look at how to build a tab component with Vue 3.

Build a Tab Component with Vue.js 3

We can build a tab component easily with Vue 3’s dynamic component feature.

To use it, we can use the keep-alive and component components.

For instance, we can write:

`<template>
  <button @click="currentTabComponent = 'Tab1'">tab 1</button>
  <button @click="currentTabComponent = 'Tab2'">tab 2</button>
  <button @click="currentTabComponent = 'Tab3'">tab 3</button>
  <keep-alive>
    <component :is="currentTabComponent"></component>
  </keep-alive>
</template>

<script>
import Tab1 from "./components/Tab1.vue";
import Tab2 from "./components/Tab2.vue";
import Tab3 from "./components/Tab3.vue";

export default {
  name: "App",
  components: {
    Tab1,
    Tab2,
    Tab3,
  },
  data() {
    return {
      currentTabComponent: "Tab1",
    };
  },
};
</script>

components/Tab1.vue

<template>
  <div>tab 1</div>
</template>

components/Tab2.vue

<template>
  <div>tab 2</div>
</template>

components/Tab3.vue

<template>
  <div>tab 3</div>
</template>

In App.vue , we have 3 buttons that sets the currentTab component value to the tag name for the component to show.

Then we have the keep-alive component to prevent unmounting of the dynamic components.

The component component lets us set which component to display dynamically.

The is prop takes a string with the tag name of the component to display.

Next, we register the components in the compoennts property.

Then in data we return the currentTabComponent set to 'Tab1' , which is the name of the component tag for the component we want to display initially.

Then in Tab1.vue , Tab2.vue and Tab3.vue , we render the tab contents.

Now when we click on each button, we should see different content displayed below it.

Conclusion

We can add tabs easily into a Vue 3 app with the keep-alive and component components.

Categories
Vue 3

How to Build a Datepicker Component with Vue.js 3?

Sometimes, we want to build our own date picker component in our Vue 3 app to let users select a date.

In this article, we’ll look at how to build a date picker component with Vue 3.

Build a Datepicker Component with Vue.js 3

We can build our own input component by creating a component that takes the modelValue prop and emits the update:modelValue event.

The 2 things together is the same as the v-model directive.

So we can write the following code to create a date picker and use it.

App.vue

<template>
  <DatePicker v-model="date" />
  <p>{{ date }}</p>
</template>

<script>
import DatePicker from "./components/DatePicker.vue";

export default {
  name: "App",
  components: {
    DatePicker,
  },
  data() {
    return {
      date: new Date(2020, 1, 1),
    };
  },
};
</script>

components/DatePicker.vue

<template>
  <div id="date-picker">
    <div>
      <label>year</label>
      <br />
      <select v-model="year">
        <option v-for="y in years" :key="y">
          {{ y }}
        </option>
      </select>
    </div>
    <div>
      <label>month</label>
      <br />
      <select v-model="month">
        <option v-for="m in 12" :key="m" :value="m - 1">
          {{ m }}
        </option>
      </select>
    </div>
    <div>
      <label>day</label>
      <br />
      <select v-model="day">
        <option v-for="d in maxDate" :key="d">
          {{ d }}
        </option>
      </select>
    </div>
  </div>
</template>

<style scoped>
#date-picker {
  display: flex;
}

#date-picker div {
  margin-right: 10px;
}
</style>

<script>
import moment from "moment";

export default {
  name: "DatePicker",
  props: {
    modelValue: Date,
  },
  data() {
    return {
      years: [],
      year: new Date().getFullYear(),
      month: 0,
      day: 1,
    };
  },
  methods: {
    emitDate() {
      const { year, month, day } = this;
      this.$emit("update:modelValue", new Date(year, month, day).toString());
    },
  },
  watch: {
    year() {
      this.emitDate();
    },
    month() {
      this.emitDate();
    },
    day() {
      this.emitDate();
    },
  },
  computed: {
    maxDate() {
      const { month } = this;
      if ([0, 2, 4, 6, 7, 9, 11].includes(month)) {
        return 31;
      } else if ([3, 5, 8, 10].includes(month)) {
        return 30;
      }
      return 28;
    },
  },
  beforeMount() {
    const currentYear = new Date().getFullYear();
    for (let i = -100; i <= 100; i++) {
      this.years.push(currentYear + i);
    }
    const d = moment(this.modelValue);
    this.year = +d.format("YYYY");
    this.month = +d.format("MM") - 1;
    this.day = +d.format("DD");
  },
};
</script>

In App.vue , we add the DatePicker component and bind it to a date string with v-model .

We create the date string with the Date constructor.

It’ll be converted to a string automatically when we get it from the modelValue prop.

Below that, we show the date value.

Then in DatePicker.vue , we add the 3 select elements to let us pick the year, month, and day.

We bind the select element value to reactive properties with v-model .

The value for the month starts with 0 and ends with 11 to match what the Date constructor accepts.

We use v-for to render the numbers for the value for the options.

Next, we add some styles to the style tag to make the dropdowns display side by side and add margins between them.

Then we have the component object.

The component takes the modelValue prop which is a string.

data returns the reactive properties we use for the template.

years is an array of years for the year dropdown which we’ll populate later.

year , month , and day are set to default values.

Next, we have the emitDate method to emit the update:modelValue event with the date string.

We call it in the year , month , and day watchers so it’ll run when any of these values change.

Then we add the maxDate computed property to return the max day we can set according to which month is chosen.

Since JavaScript Date constructor takes months that are 0 based, we check month values from 0 to 11, where 0 is January and 11 is December.

Finally, in the beforeMount hook, we populate the years array with 100 years before and after the current year.

And we get the modelValue prop’s value and parse the year, month, and day values

We do the parsing with the format method that comes with moment objects.

Now when we change the options in the drop-down, we should see the choices reflect in the text below.

Conclusion

We can create a drop-down component easily with Vue 3.

Categories
Vue 3

Add a Loading Spinner to a Vue App with the Vue Loading Overlay Component

Sometimes, we want to show a loading spinner in our Vue app to indicate the app is loading.

In this article, we’ll look at how to add a loading spinner to a Vue app with the Vue Loading Overlay component.

Installation

To install the package, we can run:

npm i vue-loading-overlay

with NPM.

Usage

Once we installed it, we can use it by writing:

<template>
  <div>
    <loading
      :active.sync="isLoading"
      :can-cancel="true"
      :on-cancel="onCancel"
      :is-full-page="fullPage"
    >
    </loading>
    <button @click.prevent="doAjax">fetch Data</button>
  </div>
</template>

<script>
import Loading from "vue-loading-overlay";
import "vue-loading-overlay/dist/vue-loading.css";

export default {
  data() {
    return {
      isLoading: false,
      fullPage: true,
    };
  },
  components: {
    Loading,
  },
  methods: {
    doAjax() {
      this.isLoading = true;
      setTimeout(() => {
        this.isLoading = false;
      }, 5000);
    },
    onCancel() {
      console.log("User cancelled the loader.");
    },
  },
};
</script>

We import the Loading component and register it in the components property.

Also, we import the CSS file to add the spinner styles.

Then we add the loading component into the template.

active is set to the condition when the spinner shows.

can-cancel set to true means we can close the spinner manually.

on-cancel is a function that runs when the spinner closes.

is-full-page is set the condition when the spinner will take the full page.

In the methods property object, we add the doAjax method to set this.isLoading to control when the spinner shows.

onCancel is the method we run when we close the spinner.

We can also use the library as a plugin.

For instance, we can write:

<template>
  <form @submit.prevent="submit" style="height: 500px" ref="formContainer">
    <button type="submit">Login</button>
  </form>
</template>

<script>
import Vue from "vue";
import Loading from "vue-loading-overlay";
import "vue-loading-overlay/dist/vue-loading.css";
Vue.use(Loading);

export default {
  data() {
    return {
      fullPage: false,
    };
  },
  methods: {
    submit() {
      const loader = this.$loading.show({
        container: this.$refs.formContainer,
        canCancel: true,
        onCancel: this.onCancel,
      });
      setTimeout(() => {
        loader.hide();
      }, 5000);
    },
    onCancel() {
      console.log("User cancelled the loader.");
    },
  },
};
</script>

We have the form with a ref assigned to it.

The form element will be used as the container for the spinner.

Then we import the modules and CSS in the same way.

Next, we call Vue.use to register the plugin.

Then we have the submit method that calls this.$loading.show to show the loading spinner,

container is set to the form element which is stored in this.$refs.formContainer .

canCancel sets whether we can close the spinner or not.

onCancel is set to the method that we want to run when we close the spinner.

So when we click Login, we see the spinner displayed for 5 seconds or until we click on it.

Conclusion

We can add a loading spinner into our Vue app with Vue Loading Overlay.

Categories
Vue 3

How to Use the Vue 3 Suspense Component and Create Async Components

To load components only when they’re needed, we can load components asynchronously.

We can also use the Suspense component to render components with a fallback message that’s displayed when it’s loading.

In this article, we’ll look at how to create async components and use the Suspense component to render them.

Vue 3 Suspense Component and Create Async Components

The Vue 3 Suspense has the default slot to render the dynamic components we want.

The fallback slot lets us display a fallback message that’s rendered when the component is loading.

We can define async components with the defineAsyncComponent function.

To use them together, we can write the following:

main.js

import { createApp, defineAsyncComponent } from "vue";
import App from "./App.vue";

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const app = createApp(App);
const HelloWorldAsync = defineAsyncComponent(async () => {
  await sleep(2000);
  return import("./components/HelloWorld.vue");
});

app.component("hello-world", HelloWorldAsync);

app.mount("#app");

App.vue

<template>
  <Suspense>
    <template #default>
      <hello-world />
    </template>
    <template #fallback>
      <div>Loading...</div>
    </template>
  </Suspense>
</template>

<script>
export default {
  name: "App",
};
</script>

components/HelloWorld.vue

<template>
  <div class="hello">hello world</div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
};
</script>

In the main.js file, we have the sleep function to simulate a delay in loading the component.

Then we create the Vue app with the createApp function.

Next, we call defineAsyncComponenty function that takes a function that returns a promise that resolves a component.

We call sleep to add a 2000 ms delay.

Then we return the promise with the component, which we get with the import function with the path to the component.

Then we register the component with the app.component method.

Next, in App.vue , we add the Suspense component with the default slot having the main content we want to display.

And the fallback slot having the content that’s displayed when the component in the default slot is loading.

HelloWorld.vue has the content we want to display.

As a result, we should see the ‘Loading…’ message displayed for 2 seconds and then see ‘hello world’ displayed after that.

Conclusion

We can use the Vue 3 Suspense component with async components to load components dynamically in an async manner.

The Suspense component lets us display a loading message for the user when the async component is being loaded.

Categories
Vue 3

How to Register a Global Component in Vue 3?

Sometimes, we may want to add components to our Vue 3 app that’s available throughout the app.

In this case, global components are suitable for this purpose.

In this article, we’ll look at how to register a global component with Vue 3.

Register a Global Component in Vue 3

To register global components with Vue 3, we can use the app.comnponent method.

For instance, we can write:

main.js

import { createApp } from "vue";
import App from "./App.vue";
import HelloWorld from "./components/HelloWorld.vue";

const app = createApp(App);
app.component("hello-world", HelloWorld);
app.mount("#app");

App.vue

<template>
  <div>
    <hello-world />
  </div>
</template>

<script>
export default {
  name: "App",
};
</script>

components/HelloWorld.vue

<template>
  <div class="hello">hello world</div>
</template>

<script>
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
};
</script>

In main.js , we import the HelloWorld component and pass that into the app.component method.

The first argument is the component name.

The 2nd argument is the component itself.

Then in App.vue , we use the component by adding the tag with the given component name.

Then in HelloWorld.vue , we add some content to the template.

The component name only works when we use the kebab-case for the tag name since we defined it with a kebab-case tag name.

We can use the hello-world component in any other component since we registered it globally.

Conclusion

We can register a global component easily with Vue 3’s app.component method.