Categories
JavaScript Vue

Lazy Load Images in a Vue App with v-lazy-image

We can lazy load images in a Vue app with the v-lazy-image library.

Lazy loading images makes the image only load when it’s showing on the screen.

To install it, we can run:

npm i v-lazy-image

Once that’s done, we can register the plugin by writing:

import Vue from "vue";
import App from "./App.vue";
import { VLazyImagePlugin } from "v-lazy-image";

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

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

Then we can use the VLazyImage component by writing:

<template>
  <div id="app">
    <v-lazy-image src="http://placekitten.com/200/200"/>
  </div>
</template>

<script>
import VLazyImage from "v-lazy-image";

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

src has the URL of the image.

We can also add a placeholder image by using the src-placeholder prop:

<template>
  <div id="app">
    <v-lazy-image
      src="http://placekitten.com/200/200"
      src-placeholder="http://placekitten.com/400/400"
    />
  </div>
</template>

<script>
import VLazyImage from "v-lazy-image";

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

We can also add some styles to the component by adding styles to the v-lazy-image and v-lazy-image-loaded classes. The 2nd one is applied when the image is loaded.

For instance, we can write:

<template>
  <div id="app">
    <v-lazy-image
      src="http://placekitten.com/200/200"
      src-placeholder="http://placekitten.com/400/400"
    />
  </div>
</template>

<script>
import VLazyImage from "v-lazy-image";

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

<style scoped>
.v-lazy-image {
  filter: blur(20px);
  transition: filter 0.7s;
}
.v-lazy-image-loaded {
  filter: blur(0);
}
</style> 

to add some blur effect when it’s being loaded.

We can load different images according to the screen size.

To do that, we use the srcset prop.

For instance, we can write:

<template>
  <div id="app">
    <v-lazy-image
      srcset="https://cdn.pixabay.com/photo/2020/02/25/19/16/stawberry-4879794_960_720.jpg 1x, https://cdn.pixabay.com/photo/2020/02/06/08/51/water-4823443__340.jpg 2x"
      src="http://placekitten.com/400/400"
    />
  </div>
</template>

<script>
import VLazyImage from "v-lazy-image";

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

We need both the src and srcset attributes. src is for the fallback image.

v-lazy-image is used for letting us lazy load images, which means that it only loads when it’s in the viewport.

It supports responsiveness and styling.

Categories
JavaScript Vue

Adding Keyboard Shortcut Handling to a Vue App with vue-shortkey

We can use the vue-shortkey package to add shortcut key handling to our Vue app.

To use it, we first install it by running:

npm i vue-shortkey

Then we can use it by writing:

<template>
  <div id="app">
    <button v-shortkey="['ctrl', 'alt', 'o']" @shortkey="theAction()">Open</button>
  </div>
</template>

<script>
export default {
  name: "App",
  methods: {
    theAction() {
      alert("hello");
    }
  }
};
</script>

We have a button that responds to the keyboard shortcut Ctrl+Alt+O.

When we press it, theAction will be called because we passed it into the shortkey event handler.

Then we should see the ‘hello’ alert displayed when we pressed the key combination.

We can also handle multiple key combinations with one handler.

For instance, we can write:

<template>
  <div id="app">
    <button v-shortkey="{up: ['arrowup'], down: ['arrowdown']}" @shortkey="theAction">arrow</button>
  </div>
</template>

<script>
export default {
  name: "App",
  methods: {
    theAction(event) {
      switch (event.srcKey) {
        case "up":
          alert("up");
          break;
        case "down":
          alert("down");
          break;
        default:
          break;
      }
    }
  }
};
</script>

We have the v-shortkey directive with an object with the up and down keys.

We have an array with the values as the values of the objecy.

Then in theAction, we take an event parameter which has the key we pressed.

We then have the switch statement and then we have alerts displayed according to the key pressed.

It can also be used on a component. However, we have to add the native modifier to catch the event.

For instance, we can write:

<template>
  <div id="app">
    <HelloWorld v-shortkey="['ctrl', 'alt', 'o']" @shortkey.native="theAction"/>
  </div>
</template>

<script>
import HelloWorld from "@/components/HelloWorld";

export default {
  name: "App",
  components: {
    HelloWorld
  },
  methods: {
    theAction() {
      alert("hello");
    }
  }
};
</script>

We added the v-shortkey directive to the HelloWorld component, and we used the native modifier on @shortkey so that the handler is run.

The full list of keys are at https://www.npmjs.com/package/vue-shortkey

vue-shortkey is a simple package that lets us add shortcut key handling capability to a Vue app that’s easier to use than the Vue way.

Categories
JavaScript Vue

Using the Intersection Observer API in a Vue App with Vue Intersect

We can use the Vue Intersect package to use the intersection observer API in our app.

To install it, we run:

npm install vue-intersect --save

or:

yarn add vue-intersect

Then we can use it by using the intersect component that comes with the package.

For instance, we can write:

<template>
  <div id="app">
    <div style="height: 300px; overflow-y: scroll">
      <intersect @enter="onEnter" @leave="onLeave" v-for="a of arr" :key="a">
        <div :id="a">{{ a }}</div>
      </intersect>
    </div>
    <div>in screen: {{inScreen.join(', ')}}</div>
  </div>
</template>

<script>
import Intersect from "vue-intersect";

export default {
  name: "App",
  components: { Intersect },
  data() {
    return {
      arr: Array(100)
        .fill()
        .map((_, i) => i),
      inScreen: []
    };
  },
  methods: {
    onEnter(e) {
      this.inScreen.push(e[0].target.id);
      this.inScreen = [...new Set(this.inScreen)];
    },
    onLeave(e) {
      const index = this.inScreen.indexOf(e[0].target.id);
      this.inScreen.splice(index, 1);
      this.inScreen = [...new Set(this.inScreen)];
    }
  }
};
</script>

We have the intersect component, which we pass the enter and leave handlers into.

We set them to onEnter and onLeave respectively.

In the methods, we have the e object, which is the event objects.

We assigned the ID to each item that we rendered with v-for, so we can get the id property of those elements that enter the screen in onEnter and the ones the left the screen in onLeave.

We add the ones that are on the screen to the inScreen array.

Likewise, we do the same with the ones that left the screen in onLeave.

We remove the duplicates by converting them to a set and then converting back to an array.

The div is made scrollable by setting its height to 300px and setting the overflow-y property to scroll.

Then when the elements enter or leave the div’s displayed area, those callbacks will be called.

We displayed the IDs of the items that are displayed in the bottom div.

vue-intersect lets us use the intersection observer API to detect if something is in the viewport easily.

Categories
JavaScript Vue

Create Styled Vue Components Easily with vue-styled-components

To created component with built-in styles with a few lines of code, we can use the vue-styled-components to create them.

Getting Started

First, we install the package by running:

npm i vue-styled-components

Then we can create some basic components by writing:

import styled from "vue-styled-components";

export const StyledTitle = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: palevioletred;
`;

export const StyledHeader = styled.header`
  padding: 4em;
  background: yellow;
`;

We import the package then use the template tags that came with the code to create new styled elements.

We change the font size, text alignment, and other things with the tags.

The h1 tag makes an h1 element.

header makes a styled header element.

Then we can use it by registering the component and use it:

<template>
  <div id="app">
    <styled-header>
      <b>header</b>
    </styled-header>
    <styled-title>hello</styled-title>
  </div>
</template>

<script>
import { StyledTitle, StyledHeader } from "./components";

export default {
  name: "App",
  components: {
    "styled-title": StyledTitle,
    "styled-header": StyledHeader
  }
};
</script>

We just register them in components and reference it in our templates.

The styles in the string are applied automatically.

Props

Like any other component, we can pass props to them.

We can create an element by writing:

import styled from "vue-styled-components";

export const StyledInput = styled.input`
  font-size: 1.25em;
  padding: 0.5em;
  margin: 0.5em;
  color: palevioletred;

  &:hover {
    box-shadow: inset 1px 1px 2px red;
  }
`;

Then we can write:

<template>
  <div id="app">
    <styled-input v-model="val" placeholder="val"/>
    <p>{{val}}</p>
  </div>
</template>

<script>
import { StyledInput } from "./components";

export default {
  name: "App",
  data() {
    return {
      val: ""
    };
  },
  components: {
    "styled-input": StyledInput
  }
};
</script>

Whatever we entered is displayed below it.

This is because it takes the value prop and emits the input event like any other component.

The styles we specified are also applied.

The placeholder prop also works and the placeholder is applied.

Adapting Based on Props

We can change styling based on props that we passed in.

For instance, we can write:

import styled from "vue-styled-components";

const btnProps = { primary: Boolean };

export const StyledButton = styled("button", btnProps)`
  font-size: 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
  background: ${props => (props.primary ? "green" : "white")};
  color: ${props => (props.primary ? "white" : "red")};
`;

to let our component takes props.

We specify the btnProps object to let our StyledButton takes props.

btnProps specifies the props that our component takes. We specified that our component takes the primary prop.

Then we can use it by writing:

<template>
  <div id="app">
    <styled-button primary>button</styled-button>
  </div>
</template>

<script>
import { StyledButton } from "./components";

export default {
  name: "App",
  data() {
    return {
      val: ""
    };
  },
  components: {
    "styled-button": StyledButton
  }
};
</script>

We set the primary prop to true, so we get a green background and white text.

Conclusion

We can create styled-components with vue-styled-components.

The package lets us create elements with styles applied to them so we can use them as Vue components.

Categories
JavaScript Vue

Create a Very Simple Tree View with Vue.js

Recursion can hurt our heads. It’s especially tough when we have to use recursion to display tree structures the way we want.

In this article, we’ll look at how to build a very simple tree view with Vue.js

To get started, we have to create a component to display the tree nodes.

We can do that by create a Tree component in components/Tree.vue:

<template>
  <div>
    <ul>
      <li v-for="i of items" :key="i.name">
        {{i.name}}
        <Tree :items="i.children" v-if="i.children"/>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "Tree",
  props: {
    items: Array
  }
};
</script>

We have a ul element, which renders the name property of some object in a li.

Then it renders the children property, which is an array with objects with the name and children properties like the current node.

As indicated by the props property, our component takes an items prop, which is an array.

In the li, we pass in the i.chilren into the items prop to render the items one level down.

We check if i.children is defined so that Tree will only render recursively if it’s defined.

Also, we display the i.name value in the current component instance.

The name property is required for recursive components.

Therefore, we should have that.

Then we can create our App.vue component, which renders the root node.

To implement it, we write:

<template>
  <div id="app">
    <Tree :items="items"/>
  </div>
</template>

<script>
import Tree from "./components/Tree";

export default {
  name: "App",
  components: {
    Tree
  },
  data() {
    return {
      items: [
        {
          name: "foo",
          children: [
            { name: "bar", children: [{ name: "baz" }, { name: "qux" }] }
          ]
        },
        {
          name: "lorem",
          children: [{ name: "ipsum" }]
        },
        {
          name: "dolor"
        }
      ]
    };
  }
};
</script>

We have an items array, which is a nested array with objects that have the name and children properties.

The children property has arrays with objects that have the same properties.

This is why we wrote out Tree component the way we have before.

children are rendered recursively, and name is rendered in the current node.

We just pass items straight into the items prop of Tree without changes.

Now we should see a nested list of words displayed on the page in the same order and levels that they’re defined in items.