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.

Categories
JavaScript Vue

Saving Data to Local Storage in a Vue App with Vue-LS

Saving data with the standard JavaScript localStorage object in a Vue app is a pain because it has limited features.

To make our lives easier, we can use a library to make our lives easier.

In this article, we’ll look at how to use the vue-ls library to save data to local storage the Vue way.

Getting Started

We can use the vue-ls library to lets us manipulate the local storage of a browser in an easy way.

To install it, we can run:

npm i vue-ls

Then to use it, we first register the plugin:

import Vue from "vue";
import App from "./App.vue";
import Storage from "vue-ls";

const options = {
  namespace: "vuejs__",
  name: "ls",
  storage: "local"
};

Vue.use(Storage, options);
Vue.config.productionTip = false;

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

We called Vue.use with an options object.

The namespace is the prefix to add the key.

The name is the property name to access the vue-ls methods.

storage is the kind of storage to save the data in. It can be local, storage or memory.

Saving Data

To save data in a component, we can write:

<template>
  <div id="app"></div>
</template>

<script>
export default {
  name: "App",
  mounted() {
    this.$ls.set("foo", "boo", 60 * 60 * 1000);
  }
};
</script>

We called this.$ls.set to save an item with the key vuejs__foo since we prefixed the key withe vuejs__ according to the namespace prop.

The second argument is the key, the 3rd is the expiry time.

The last 2 arguments will be saved as a stringified object.

The key would be vuejs__foo and the value is:

{"value":"boo","expire":1589754925116}

We can check against the expiry timestamp and do what we want with it if it expires.

Adding an expiry time is a feature that isn’t available with local storage.

So, this is a valuable feature.

Watching for Changes

We can also add listen for changes in data with:

<template>
  <div id="app"></div>
</template>

<script>
export default {
  name: "App",
  mounted() {
    const callback = (val, oldVal, uri) => {
      console.log(val, oldVal, uri);
    };

    this.$ls.on("foo", callback);
    this.$ls.set("foo", "boo", 60 * 60 * 1000);
  }
};
</script>

We have the this.$ls.on method. The first argument is the key without the prefix.

The callback it a callback when the local storage item with vuejs__foo is updated.

It has the val parameter with the current value. oldVal has the current value.

uri is the URL that the app is hosted on.

We watch the value with this call.

To unwatch the item, we can write:

this.$ls.off('foo', callback)

Where callback is the same callback we passed into the $on method.

Getting Data

To get a local storage item value by its key, we can write:

this.$ls.get('foo', 10);

Then we get the local storage with the key foo. If the value isn’t found, then 10 is returned.

Finally, to remove a value, we can write:

this.$ls.remove('foo');

to remove the value with the key vuejs__foo assuming the namespace is set to vuejs__.

Conclusion

vue-ls is an easy to use local storage library that lets us do things like adding an expiry timestamp to the saved data and watch for changes to values in addition to what’s already available in browser’s localStorage object.