Categories
Vue 3

Vue 3 — Teleport

Vue 3 is in beta and it’s subject to change.

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at how to use the teleport component to render elements and components in a different location in the DOM.

Teleport

We can use the teleport component to let us render parts of our Vue template in a location that’s different from its usual location in the DOM

This is handy for creating things like modals and overlays.

The DOM element that we want to render our items in must already exist.

Otherwise, we’ll get an error.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <teleport to="#footer">
        <p>footer</p>
      </teleport>
    </div>

    <div id="footer"></div>

    <script>
      const app = Vue.createApp({});

      app.mount("#app");
    </script>
  </body>
</html>

We added the teleport component to our template with the to prop set to the selector to mount the content inside it.

Therefore, the div with ID footer will hold the p element that’s inside the teleport component.

Using with Vue components

If teleport has a Vue component, then it’ll remain a child component of the teleport ‘s parent.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
<teleport to="#modals">
  <div>A</div>
</teleport>
<teleport to="#modals">
  <div>B</div>
</teleport>
    </div>

    <div id="footer"></div>

    <script>
      const app = Vue.createApp({});

      app.component("parent-component", {
        template: `
          <h2>parent</h2>
          <teleport to="#footer">
            <child-component name="james" />
          </teleport>
        `
      });

      app.component("child-component", {
        props: ["name"],
        template: `
          <div>{{ name }}</div>
        `
      });

      app.mount("#app");
    </script>
  </body>
</html>

We put the parent-component in the root template of our app.

It has a teleport that has to set to #footer .

So it’ll be rendered in the div with the ID footer .

It has the child-component inside it.

And that’ll be rendered inside div with ID footer also.

Using Multiple Teleports on the Same Target

We can have multiple teleports with the same selector set as their to prop value.

They’ll be rendered by in the order that they’re defined in.

For instance, if we have:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <teleport to="#footer">
        <div>foo</div>
      </teleport>
      <teleport to="#footer">
        <div>bar</div>
      </teleport>
    </div>

    <div id="footer"></div>

    <script>
      const app = Vue.createApp({});

      app.mount("#app");
    </script>
  </body>
</html>

Then the rendered result would be:

<div id="footer">
  <div>foo</div>
  <div>bar</div>
</div>

Conclusion

The teleport component lets us render parts of a Vue template in a location that’s different from the usual location in the DOM.

Categories
Vue 3

Vue 3 — Render Functions Basics

Vue 3 is in beta and it’s subject to change.

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at how to create render functions with Vue 3.

Render Functions

Templates should be used most of the time to build Vue components.

However, there may be cases where we need more flexibility.

For instance, we may want to add elements with dynamic tags.

Instead of writing:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <variable-heading :level="1">foo</variable-heading>
    </div>
    <script>
      const app = Vue.createApp({});

      app.component("variable-heading", {
        template: `
          <h1 v-if="level === 1">
            <slot></slot>
          </h1>
          <h2 v-else-if="level === 2">
            <slot></slot>
          </h2>
          <h3 v-else-if="level === 3">
            <slot></slot>
          </h3>
          <h4 v-else-if="level === 4">
            <slot></slot>
          </h4>
          <h5 v-else-if="level === 5">
            <slot></slot>
          </h5>
          <h6 v-else-if="level === 6">
            <slot></slot>
          </h6>
        `,
        props: {
          level: {
            type: Number,
            required: true
          }
        }
      });

      app.mount("#app");
    </script>
  </body>
</html>

We can make the heading tags dynamic with a render function.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <variable-heading :level="1">foo</variable-heading>
    </div>
    <script>
      const app = Vue.createApp({});

      app.component("variable-heading", {
        render() {
          const { h } = Vue;

          return h(`h${this.level}`, {}, this.$slots.default());
        },
        props: {
          level: {
            type: Number,
            required: true
          }
        }
      });

      app.mount("#app");
    </script>
  </body>
</html>

We created the variable-heading component with a render method to render our HTML.

The h method lets us render our items.

The first argument is the tag name.

The 2nd is any props or attributes we want to pass to it.

And the 3rd argument is an array fo children.

this.$slots.default() is the default slot to let us populate content,

The rest of the component are the same as the other parts.

Every element in the DOM is a node, and the h method lets us render the nodes by nesting them as we do in a tree.

The Virtual DOM Tree

Vue keeps a virtual DOM tree to keep track of changes is needs to make to the real DOM.

The h method returns an object that has the information needed for Vue to update the read DOM.

h() Arguments

The h method takes 3 arguments.

The tag name is the first argument. It can be a string, object, function, or null .

If it’s an object, then it must be a component or async component.

The 2nd argument is an object with optional props.

The 3rd argument is a string, array, or object of child nodes.

It’s also optional.

VNodes Must Be Unique

We can’t have duplicate VNodes in our render function.

So we can’t have:

render() {
  const myParagraphVNode = Vue.h('p', 'hi')
  return Vue.h('div', [
    paragraph, paragraph
  ])
}

We can’t have 2 paragraph s in the array.

Conclusion

We can use render functions to tell Vue how to render components with JavaScript.

This is an alternative to templates.

Categories
Vue 3

Vue 3 — More Complex Render Functions

Vue 3 is in beta and it’s subject to change.

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at how to create render functions with Vue 3.

Replacing Template Features with Render Functions

We can replace template features with render functions.

Directives like v-if and v-for can be replaced within render functions.

v-if can be replaced an if statement.

v-for can be replaced with an array of items.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <todo-list :todos="todos"></todo-list>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            todos: [{ name: "eat" }, { name: "drink" }, { name: "sleep" }]
          };
        }
      });

      app.component("todo-list", {
        props: ["todos"],
        render() {
          if (this.todos.length) {
            return Vue.h(
              "div",
              this.todos.map(todo => {
                return Vue.h("div", todo.name);
              })
            );
          } else {
            return Vue.h("div", "no todos.");
          }
        }
      });

      app.mount("#app");
    </script>
  </body>
</html>

We created the todo-list component with the if statement to check the length fo the this.todos array.

And we called map to return an array of divs with the name .

v-on

The equivalent of the v-on directive is the on methods in the object in the 2nd argument.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <custom-div></custom-div>
    </div>
    <script>
      const app = Vue.createApp({});

      app.component("custom-div", {
        render() {
          return Vue.h(
            "div",
            {
              onClick: $event => console.log("clicked", $event.target)
            },
            "click me"
          );
        }
      });

      app.mount("#app");
    </script>
  </body>
</html>

We created a custom-div component with a div.

The 2nd argument is an object that has the onClick method, which listens to clicks on the div.

The 3rd argument has the content between the div tags.

v-model

v-model ‘s equivalent is the modelValue prop and the onInput method.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <custom-input v-model="value"></custom-input>
      <p>{{value}}</p>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            value: ""
          };
        }
      });

      app.component("custom-input", {
        props: ["modelValue"],
        render() {
          return Vue.h("input", {
            modelValue: this.modelValue,
            onInput: ev => this.$emit("update:modelValue", ev.target.value)
          });
        }
      });

      app.mount("#app");
    </script>
  </body>
</html>

We have the modelValue prop with the custom-input component.

this.modelValue has the prop’s value.

We set that as the modelValue property’s value.

And then we emit the update:modelValue event to send the value to the parent.

Now when we type in something, it’ll be synchronized with the value state.

So we’ll see what we typed displayed.

Event Modifiers

Event modifiers can also be replaced with render functions.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <custom-div></custom-div>
    </div>
    <script>
      const app = Vue.createApp({});

      app.component("custom-div", {
        render() {
          return Vue.h(
            "div",
            {
              onClick: {
                handler: ev => console.log(ev),
                capture: true
              },
              onKeyUp: {
                handler: ev => console.log(ev),
                once: true
              },
              onMouseOver: {
                handler: ev => console.log(ev),
                once: true,
                capture: true
              }
            },
            "click me"
          );
        }
      });

      app.mount("#app");
    </script>
  </body>
</html>

to add the event handler methods.

The options are the modifiers.

Conclusion

We can replace various directives with their equivalents with render functions.

Categories
Top Vue Packages

Top Vue Packages for Checking Network Status, Checkboxes and Radio Buttons

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at the best packages for checking network status, particle background, checkboxes and radio buttons, and infinite scrolling.

Vue Offline

Vue Offline is a good plugin for detecting whether a Vue app is online for offline.

To use it, we run:

npm i vue-offline

Then we can use it by writing:

main.js

import Vue from "vue";
import App from "./App.vue";
import VueOffline from "vue-offline";

Vue.use(VueOffline);
Vue.config.productionTip = false;

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

App.vue

<template>
  <div>
    <p v-if="isOnline">online</p>
    <p v-if="isOffline">Toffline</p>
  </div>
</template>

<script>
export default {
  mounted() {
    this.$on("offline", () => {
      console.log('offline')
    });
  }
};
</script>

We register the plugin., Then we can use the isOnline and isOffline properties to check whether the app is online or offline.

Also, we can use the $on method to listen to network status changes.

We can also save data to local storage to make the data available offline.

To save the data, we can write:

<template>
  <div>
    <p v-if="isOnline">online</p>
    <p v-if="isOffline">Toffline</p>
  </div>
</template>

<script>
export default {
  mounted() {
    this.$offlineStorage.set("user", { foo: "bar" });
  }
};
</script>

We use the this.$offlineStorage.set method to save the data.

The first argument is the key and the 2nd is the value.

We can use this.$offlineStorage.get to get the value by the key.

vue-particles

We can use vue-particles to display a particles background in our Vue app.

To use it, we run:

npm i vue-particles

to install the package.

Then we can write:

main.js

import Vue from "vue";
import App from "./App.vue";
import VueParticles from "vue-particles";
Vue.use(VueParticles);
Vue.config.productionTip = false;

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

App.vue

<template>
  <div>
    <vue-particles color="#dedede"></vue-particles>
  </div>
</template>

<script>
export default {};
</script>

to use it.

We have the vue-particles component to display the background.

color is the color of the particles.

There are many other things we can customize.

Line colors, width, opacity, distance, speed, opacity, all can be customized.

vue-checkbox-radio

vue-checkbox-radio lets us add radio buttons or checkboxes to our Vue app.

To use it, we run:

npm install vue-checkbox-radio --save

to install it.

Then we can write:

main.js

import Vue from "vue";
import App from "./App.vue";
import CheckboxRadio from "vue-checkbox-radio";

Vue.use(CheckboxRadio);
Vue.config.productionTip = false;

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

App.vue

<template>
  <div>
    <checkbox name="agree" v-model="agree" value="1">
      I agree to the
      <a href="#">terms</a>
    </checkbox>
  </div>
</template>

<script>
export default {
  data() {
    return { agree: false };
  }
};
</script>

to use it.

checkbox is the component for adding the checkbox.

The content between the tags will be the content beside the checkbox.

name is the name attribute of the checkbox.

v-model binds the checked value to the agree state.

We can also add radio buttons with it.

To do that, we write:

<template>
  <div>
    <radio name="robot" value="1" v-model="isRobot">I'm a robot</radio>
    <radio name="robot" value="0" v-model="isRobot">I'm not a robot</radio>
    <p>{{isRobot}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return { isRobot: false };
  }
};
</script>

We just bind v-model to the same state and it’ll be set when we check it.

The name attribute of one set of checkboxes will have the same name.

vue-mugen-scroll

vue-mugen-scroll is an infinite scrolling library for Vue apps.

To use it, we can install it by running:

npm i vue-mugen-scroll

Then we write:

<template>
  <div id="app">
    <div class="list">
      <p v-for="n in num" :key="n">{{n}}</p>
    </div>
    <mugen-scroll :handler="fetchData" :should-handle="!loading">loading...</mugen-scroll>
  </div>
</template>

<script>
import MugenScroll from "vue-mugen-scroll";
export default {
  data() {
    return { loading: false, num: 50 };
  },
  methods: {
    fetchData() {
      this.loading = true;
      this.num += 50;
      this.loading = false;
    }
  },
  components: { MugenScroll }
};
</script>

to add infinite scrolling to our component.

We put whatever needs infinite scrolling above the mugen-scroll component so that it watches the scroll position and load more data if needed.

handler is the prop for the method to fetch data.

should-handle is the state that loads the handler.

Conclusion

vue-mugen-scroll lets us add infinite scrolling.

Vue Offline lets us check network status in a Vye app.

vue-particles lets us create a particle background.

vue-checkbox-radio lets us add checkbox or radio buttons.

Categories
Top Vue Packages

Top Vue Packages for Adding a Password Strength Meter, Charts, and File Uploader

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at the best packages for adding a password strength meter, charts, and file uploader.

vue-password-strength-meter

vue-password-strength-meter is an easy to add password strength meter for our Vue app.

To use it, we run:

npm i vue-password-strength-meter zxcvbn

to install it.

zxcvbn is required for measuring the password strength.

Then we can use it by writing:

<template>
  <password v-model="password"/>
</template>

<script>
import Password from "vue-password-strength-meter";
export default {
  components: { Password },
  data() {
    return {
      password: null
    };
  }
};
</script>

We use the password component to add a password input.

We bind to the password state with v-model .

It can be customized with some options.

We can listen to events emitted when the score and feedback events are emitted.

For instance, we can write:

<template>
  <password v-model="password" @score="showScore" @feedback="showFeedback"/>
</template>

<script>
import Password from "vue-password-strength-meter";
export default {
  components: { Password },
  data() {
    return {
      password: null
    };
  },
  methods: {
    showFeedback({ suggestions, warning }) {
      console.log(suggestions);
      console.log(warning);
    },
    showScore(score) {
      console.log(score);
    }
  }
};
</script>

It emits the score event with the password strength score.

The feedback event is emitted with the feedback for our password strength.

We can get these things and display them to the user if we want.

We can customize the styles for the strange meter, success and error classes, labels, and more.

vue-simple-uploader

vue-simple-uploader is a file uploader component for Vue apps.

To use it, we run:

npm i vue-simple-uploader

to install it.

Then we write:

main.js

import Vue from "vue";
import App from "./App.vue";
import uploader from "vue-simple-uploader";

Vue.use(uploader);
Vue.config.productionTip = false;

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

App.vue

<template>
  <uploader :options="options" class="uploader-example">
    <uploader-unsupport></uploader-unsupport>
    <uploader-drop>
      <p>Drop files here to upload or</p>
      <uploader-btn>select files</uploader-btn>
      <uploader-btn :attrs="attrs">select images</uploader-btn>
      <uploader-btn :directory="true">select folder</uploader-btn>
    </uploader-drop>
    <uploader-list></uploader-list>
  </uploader>
</template>

<script>
export default {
  data() {
    return {
      options: {
        target: "//localhost:3000/upload",
        testChunks: false
      },
      attrs: {
        accept: "image/*"
      }
    };
  }
};
</script>

to add the uploader component to our app.

uploader-unsupport is displayed when the required features are unsupported in the browser.

upload-btn is an upload button.

uploader-drop is the dropzone for the file upload.

uploader-list display the list of files uploaded.

options has the options, including the upload URL.

attres have the items we accept.

There are slots that we can populate to customize our app.

vue-highcharts

We can use the vue-highcharts package to add charts easily with our app.

One special feature is that we can add custom markers for points.

To use it, we run:

npm i vue2-highcharts highcharts

to install it with its dependencies.

Then we can use it by writing:

<template>
  <div>
    <vue-highcharts :options="options" ref="lineCharts"></vue-highcharts>
    <button @click="load">load</button>
  </div>
</template>

<script>
import VueHighcharts from "vue2-highcharts";
const data = {
  name: "New York",
  marker: {
    symbol: "square"
  },
  data: [
    7.0,
    6.9,
    {
      y: 26.5,
      marker: {
        symbol: "url(http://www.highcharts.com/demo/gfx/sun.png)"
      }
    }
  ]
};
export default {
  components: {
    VueHighcharts
  },
  data() {
    return {
      options: {
        chart: {
          type: "spline"
        },
        title: {
          text: "Monthly Average Temperature"
        },
        subtitle: {
          text: "temperature chart"
        },
        xAxis: {
          categories: ["Jan", "Feb", "Mar"]
        },
        yAxis: {
          title: {
            text: "Temperature"
          },
          labels: {
            formatter() {
              return this.value + "°";
            }
          }
        },
        tooltip: {
          crosshairs: true,
          shared: true
        },
        credits: {
          enabled: false
        },
        plotOptions: {
          spline: {
            marker: {
              radius: 4,
              lineColor: "#666666",
              lineWidth: 1
            }
          }
        },
        series: []
      }
    };
  },
  methods: {
    load() {
      const lineCharts = this.$refs.lineCharts;
      lineCharts.delegateMethod("showLoading", "Loading...");
      lineCharts.addSeries(data);
      lineCharts.hideLoading();
    }
  }
};
</script>

We add the vue-highcharts component to add the chart.

options has all the chart options.

chart has the chart type,

title has the title.

subtitle has the subtitle.

xAxis has the x-axis labels.

yAxis has the y-axis labels.

labels has the labels.

formatter has the function to format the labels.

tooltios enable the tooltips. crosshairs enables the labels on the line.

shared enables the other labels.

plotOptions has the markers.

delegateMethod lets us do various things with our chart.

In our example, we use 'showLoading' to show the loading text.

We get the ref of the chart component and then use the addSeries method to add the chart data.

hideLoading hides the loading text.

Conclusion

vue-password-strength-meter provides us with a useful password strength meter.

vue-simple-uploader provides us with a file upload component.

vue-highcharts is a chart library.