Categories
Vue

Add a Chat Scroll Effect to a Vue App with the vue-chat-scroll Library

To add a scrolling effect that looks like the scrolling in a chat app in a Vue app, we can use the vue-chat-scroll library.

In this article, we’ll look at how to use the vue-chat-scroll library to add the chat scrolling effect.

Installation

We can install the library by running:

npm i vue-chat-scroll

We can also add the library with a script tag:

<script src="https://cdn.jsdelivr.net/npm/vue-chat-scroll/dist/vue-chat-scroll.min.js"></script>

Add the Chat Scroll Effect

We can add the chat scroll effect with the v-chat-scroll directive. To do that, we write:

<template>
  <div id="app">
    <ul class="messages" v-chat-scroll>
      <li class="message" v-for="(n, i) in messages" :key="i">{{ n }}</li>
    </ul>
    <form @submit.prevent="addMessage">
      <input v-model="message">
      <input type="submit">
    </form>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      message: "",
      messages: [
        "Lorem",
        "ipsum",
        "dolor",
        "sit",
        "amet,",
        "consectetur",
        "adipiscing",
        "elit.",
        "Praesent",
        "facilisis",
        "justo"
      ]
    };
  },
  methods: {
    addMessage() {
      this.messages.push(this.message);
      this.message = "";
    }
  }
};
</script>

Now when we type something into the box and submit it, the v-chat-scroll directive will scroll to the bottom of the list.

We have a form that we submit add to the this.messages array.

Prevent Scroll Down When User has Scrolled Up and Smooth Scrolling

We can prevent the scroll down effect when the user scrolled up by setting the always property to false .

And we can add smooth scrolling with the smooth property set to true :

<template>
  <div id="app">
    <ul class="messages" v-chat-scroll="{always: false, smooth: true}">
      <li class="message" v-for="(n, i) in messages" :key="i">{{ n }}</li>
    </ul>
    <form [@submit](http://twitter.com/submit "Twitter profile for @submit").prevent="addMessage">
      <input v-model="message">
      <input type="submit">
    </form>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      message: "",
      messages: [
        "Lorem",
        "ipsum",
        "dolor",
        "sit",
        "amet,",
        "consectetur",
        "adipiscing",
        "elit.",
        "Praesent",
        "facilisis",
        "justo"
      ]
    };
  },
  methods: {
    addMessage() {
      this.messages.push(this.message);
      this.message = "";
    }
  }
};
</script>

We can only add smooth scrolling for updates but not on first load with the notSmoothOnInit property:

<template>
  <div id="app">
    <ul class="messages" v-chat-scroll="{smooth: true, notSmoothOnInit: true}">
      <li class="message" v-for="(n, i) in messages" :key="i">{{ n }}</li>
    </ul>
    <form [@submit](http://twitter.com/submit "Twitter profile for @submit").prevent="addMessage">
      <input v-model="message">
      <input type="submit">
    </form>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      message: "",
      messages: [
        "Lorem",
        "ipsum",
        "dolor",
        "sit",
        "amet,",
        "consectetur",
        "adipiscing",
        "elit.",
        "Praesent",
        "facilisis",
        "justo"
      ]
    };
  },
  methods: {
    addMessage() {
      this.messages.push(this.message);
      this.message = "";
    }
  }
};
</script>

We can also add the scrollonremoved property to ensure the scroll happens after the element loading indicator is removed:

<template>
  <div id="app">
    <ul class="messages" v-chat-scroll="{always: false, smooth: true, scrollonremoved:true}">
      <li class="message" v-for="(n, i) in messages" :key="i">{{ n }}</li>
      <li v-if="loading">...</li>
    </ul>
    <form [@submit](http://twitter.com/submit "Twitter profile for @submit").prevent="addMessage">
      <input v-model="message">
      <input type="submit">
    </form>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      message: "",
      messages: [
        "Lorem",
        "ipsum",
        "dolor",
        "sit",
        "amet,",
        "consectetur",
        "adipiscing",
        "elit.",
        "Praesent",
        "facilisis",
        "justo"
      ],
      loading: false
    };
  },
  methods: {
    addMessage() {
      this.loading = true;
      setTimeout(() => {
        this.messages.push(this.message);
        this.message = "";
        this.loading = false;
      }, 1000);
    }
  }
};
</script>

We set this.loading to true when we submit the message and set it to false when it’s added.

Having the scrollonremoved property ensures that when the loading indicator is gone that the scrolling will happen.

Conclusion

The vue-chat-scroll library lets us scroll to the bottom of a list of text easily within a Vue app.

Categories
Vue

Vueper Slides Library — 3d Rotation and External Controls

With the Vueper Slides library, we can add a carousel to our Vue app easily.

In this article, we’ll look at how to use it to add a carousel to our Vue app.

3D Rotation

We can add a 3d rotation effect when we change the slides with the 3d prop.

For example, we can write:

<template>
  <div id="app">
    <vueper-slides 3d fixed-height="300px" arrows-outside bullets-outside>
      <vueper-slide
        v-for="i in 9"
        :key="i"
        :title="i.toString()"
        :style="`background-color: ${colors[i % 2]}`"
      />
    </vueper-slides>
  </div>
</template>

<script>
import { VueperSlides, VueperSlide } from "vueperslides";
import "vueperslides/dist/vueperslides.css";

export default {
  name: "App",
  components: { VueperSlides, VueperSlide },
  data() {
    return {
      colors: ["green", "red"]
    };
  }
};
</script>

Now we see a cube when we slide between 2 slides.

External Controls

We can add our own controls that are outside the slides itself:

<template>
  <div id="app">
    <button @click="$refs.slides.previous()">Previous</button>
    <button @click="$refs.slides.goToSlide(6 - 1)">Go to slide 6</button>
    <button @click="$refs.slides.next()">Next</button>
    <vueper-slides ref="slides">
      <vueper-slide
        v-for="i in 9"
        :key="i"
        :title="i.toString()"
        :style="`background-color: ${colors[i % 2]}`"
      />
    </vueper-slides>
  </div>
</template>

<script>
import { VueperSlides, VueperSlide } from "vueperslides";
import "vueperslides/dist/vueperslides.css";

export default {
  name: "App",
  components: { VueperSlides, VueperSlide },
  data() {
    return {
      colors: ["green", "red"]
    };
  }
};
</script>

We assign a ref to the vueper-slides component so that we can call the methods that are included with the vueper-slides component.

previous is used to move to the previous slide.

goToSlide goes to the slide with the given index.

next goes to the next slide.

Sync 2 Instances

We can synchronize 2 carousels with Vueper Slides. To do that, we use the goToSlide method:

<template>
  <div id="app">
    <vueper-slides
      ref="vueperslides1"
      @slide="$refs.vueperslides2 && $refs.vueperslides2.goToSlide($event.currentSlide.index, { emit: false })"
      :slide-ratio="1 / 4"
      :bullets="false"
    >
      <vueper-slide
        v-for="i in 8"
        :key="i"
        :title="i.toString()"
        content="Navigation in sync"
        :style="'background-color: ' + ['#ff5252', '#42b983'][i % 2]"
      />
    </vueper-slides>

    <vueper-slides
      ref="vueperslides2"
      :slide-ratio="1 / 8"
      :dragging-distance="50"
      @slide="$refs.vueperslides1 && $refs.vueperslides1.goToSlide($event.currentSlide.index, { emit: false })"
      :visible-slides="3"
      fixed-height="100px"
    >
      <vueper-slide
        v-for="i in 8"
        :key="i"
        @click.native="$refs.vueperslides2 && $refs.vueperslides2.goToSlide(i - 1)"
      >
        <template v-slot:content>
          <div
            class="vueperslide__content-wrapper"
            :style="'background-color: ' + ['#ff5252', '#42b983'][i % 2]"
          >
            <div class="vueperslide__title">{{ i.toString() }}</div>
          </div>
        </template>
      </vueper-slide>
    </vueper-slides>
  </div>
</template>

<script>
import { VueperSlides, VueperSlide } from "vueperslides";
import "vueperslides/dist/vueperslides.css";

export default {
  name: "App",
  components: { VueperSlides, VueperSlide },
  data() {
    return {
      colors: ["green", "red"]
    };
  }
};
</script>

We assign refs to both vueper-slides components. Then we listen to the slide event to listen for slide changes.

Then we can call goToSlide to on the other slide to change the slide.

emit set to false prevents the emission of the slide event when we call goToSlide .

This way, the slides for both carousels will be in sync.

Conclusion

We can synchronize 2 carousels with Vueper Slides.

Also, we can add 3d rotation effect and external controls for slides.

Categories
Vue

Add a Sidebar Menu to a Vue App with vue-sidebar-menu

We can add a sidebar menu with into a Vue app with the vue-sidebar-menu library.

In this article, we’ll look at how to us it to add the menu.

Installation

We can install the package by running:

npm i vue-sidebar-menu

Adding the Menu

We use the sidebar-menu component to do that.

To do that, we write:

main.js

import Vue from "vue";
import App from "./App.vue";
import VueSidebarMenu from "vue-sidebar-menu";
import "vue-sidebar-menu/dist/vue-sidebar-menu.css";
Vue.use(VueSidebarMenu);
Vue.config.productionTip = false;

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

App.vue

<template>
  <div id="app">
    <sidebar-menu :menu="menu"/>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      menu: [
        {
          header: true,
          title: "Main Navigation",
          hiddenOnCollapse: true
        },
        {
          href: "/",
          title: "Dashboard",
          icon: "fa fa-user"
        },
        {
          href: "/charts",
          title: "Charts",
          icon: "fa fa-pie-chart",
          child: [
            {
              href: "/charts/sublink",
              title: "Sub Link"
            }
          ]
        }
      ]
    };
  }
};
</script>

We register the library in main.js .

Then we add it to our component.

href has the URL. title has the menu entry title.

icon has the menu class.

In index.html , we add the Font Awesome library to add our icons”

<link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
      integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN"
      crossorigin="anonymous"
    />

Use With Vue Router

We can use the library with Vue Router. To do this, we add Vue Router and the router-view component.

main.js

import Vue from "vue";
import App from "./App.vue";
import VueSidebarMenu from "vue-sidebar-menu";
import "vue-sidebar-menu/dist/vue-sidebar-menu.css";
import VueRouter from "vue-router";
Vue.use(VueRouter);
Vue.use(VueSidebarMenu);
Vue.config.productionTip = false;

const Dashboard = { template: "<div>dashboard</div>" };
const Charts = { template: "<div>charts</div>" };

const routes = [
  { path: "/dashboard", component: Dashboard },
  { path: "/charts", component: Charts }
];

const router = new VueRouter({
  routes
});

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

App.vue

<template>
  <div id="app">
    <div style="display: flex; justify-content: space-between">
      <div>
        <sidebar-menu :menu="menu"/>
      </div>
      <div>
        <router-view></router-view>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      menu: [
        {
          header: true,
          title: "Main Navigation",
          hiddenOnCollapse: true
        },
        {
          href: "/dashboard",
          title: "Dashboard",
          icon: "fa fa-user"
        },
        {
          href: "/charts",
          title: "Charts",
          icon: "fa fa-pie-chart"
        }
      ]
    };
  }
};
</script>

We added the components and use them in the routes array.

Then we pass routes in the VueRouter component.

In App.vue , we have the same menu items.

The only thing we added is the router-view to display the components that are mapped to the routes.

Slots

We can custom the content of our menu by populating various slots.

To do this, we add:

<template>
  <div id="app">
    <div style="display: flex; justify-content: space-between">
      <div>
        <sidebar-menu :menu="menu">
          <div slot="header">header</div>
          <div slot="footer">footer</div>
          <span slot="toggle-icon">
            <i class="fa fa-caret-square-o-down"></i>
          </span>
          <span slot="dropdown-icon">dropdown-icon</span>
        </sidebar-menu>
      </div>
      <div>
        <router-view></router-view>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      menu: [
        {
          header: true,
          title: "Main Navigation",
          hiddenOnCollapse: true
        },
        {
          href: "/dashboard",
          title: "Dashboard",
          icon: "fa fa-user"
        },
        {
          href: "/charts",
          title: "Charts",
          icon: "fa fa-pie-chart"
        }
      ]
    };
  }
};
</script>

We populate the header slot to change the header.

footer slot changes the footer.

toggle-icon changes the toggle icon at the bottom of the menu.

dropdown-icon sets the dropdown icon.

Conclusion

We can add a sidebar menu to our Vue app with the vue-sidebar-menu library.

Categories
Vue

Vueper Slides Library — Updating Content

With the Vueper Slides library, we can add a carousel to our Vue app easily.

In this article, we’ll look at how to use it to add a carousel to our Vue app.

Updating Content Inside and Outside

We can update our slide content from the outside.

For example, we can write:

<template>
  <div id="app">
    <button @click="toggleSlidesTime">Keep updating time</button>

    <vueper-slides :slide-ratio="1 / 4" autoplay :slide-content-outside="contentPosition">
      <vueper-slide
        v-for="(slide, i) in slides"
        :key="i"
        :style="`background-color: ${['green', 'red'][i % 2]}`"
      >
        <template v-slot:content>
          <div class="vueperslide__content-wrapper" style="flex-direction: row">
            <span>{{ slide.title }}</span>
          </div>
        </template>
      </vueper-slide>
    </vueper-slides>
  </div>
</template>

<script>
import { VueperSlides, VueperSlide } from "vueperslides";
import "vueperslides/dist/vueperslides.css";

export default {
  name: "App",
  components: { VueperSlides, VueperSlide },
  data: () => ({
    slidesTimeTimerId: null,
    slides: [{ title: "Time" }, { title: "Time" }]
  }),
  methods: {
    toggleSlidesTime() {
      if (this.slidesTimeTimerId) {
        clearInterval(this.slidesTimeTimerId);
        this.slidesTimeTimerId = 0;
      } else {
        this.updateSlidesWithTime();
        this.slidesTimeTimerId = setInterval(this.updateSlidesWithTime, 1000);
      }
    },
    updateSlidesWithTime() {
      this.slides.forEach(slide => {
        const time = new Date();
        slide.title = time.toLocaleTimeString();
      });
    }
  }
};
</script>

We have the toggleSlidesTime method to update title with the latest date and time.

The slides property is reactive, so the updates will be automatically reflected.

Add, Remove, and Disable Slides

We can add or remove slides by changing our slides array.

For example, we can write:

<template>
  <div id="app">
    <button @click="appendSlide">Add Slide</button>
    <button @click="removeSlide">Remove Slide</button>
    <button @click="toggleSlideshow">Toggle Slideshow</button>

    <vueper-slides
      :slide-ratio="0.2"
      :infinite="false"
      disable-arrows-on-edges
      bullets-outside
      :disable="slideshowDisabled"
    >
      <vueper-slide v-for="(slide, i) in slides" :key="i" :title="slide.title"/>
    </vueper-slides>
  </div>
</template>

<script>
import { VueperSlides, VueperSlide } from "vueperslides";
import "vueperslides/dist/vueperslides.css";

export default {
  name: "App",
  components: { VueperSlides, VueperSlide },
  data: () => ({
    slidesTimeTimerId: null,
    slides: [{ title: "slide" }]
  }),
  methods: {
    appendSlide() {
      this.slides.push({
        title: `slide`
      });
    },
    removeSlide() {
      this.slides.pop();
    },
    toggleSlideshow() {
      this.slideshowDisabled = !this.slideshowDisabled;
    }
  }
};
</script>

to add the appendSlide method to add slides by calling push on the this.slides array.

removeSlide is a method to call pop to remove the last slide.

toggleSlideshow toggles the disable prop to toggling disabling the slides.

Center Mode

We can center our slides with some styles.

For example, we can write:

<template>
  <div id="app">
    <vueper-slides class="no-shadow" arrows-outside bullets-outside transition-speed="250">
      <vueper-slide
        v-for="i in 10"
        :key="i"
        :title="i.toString()"
        :style="`background-color: ${['#ff5252', '#42b983'][i % 2]}`"
      />
    </vueper-slides>
  </div>
</template>

<script>
import { VueperSlides, VueperSlide } from "vueperslides";
import "vueperslides/dist/vueperslides.css";

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

<style>
.ex--center-mode {
  width: 600px;
  max-width: 100%;
  margin: auto;
}
</style>

to center the slides.

We put the arrows outside the slide with the arrows-outside prop.

bullets-outside puts the bullets outside.

transition-speed changes the transition speed in milliseconds.

Conclusion

We can update our content in various ways with Vueper Slides Vue carousel component.

Categories
Vue

Vueper Slides Library —Slides Breakpoints, Heights, and Gaps

With the Vueper Slides library, we can add a carousel to our Vue app easily.

In this article, we’ll look at how to use it to add a carousel to our Vue app.

Breakpoints

We can set the breakpoints to make a responsive slider.

To do that, we can write:

<template>
  <div id="app">
    <vueper-slides :breakpoints="breakpoints">
      <vueper-slide
        v-for="i in 10"
        :key="i"
        :title="i.toString()"
        :style="`background-color: ${['#ff5252', '#42b983'][i % 2]}`"
      />
    </vueper-slides>
  </div>
</template>

<script>
import { VueperSlides, VueperSlide } from "vueperslides";
import "vueperslides/dist/vueperslides.css";

export default {
  name: "App",
  components: { VueperSlides, VueperSlide },
  data: () => ({
    breakpoints: {
      1200: {
        slideRatio: 1 / 5
      },
      900: {
        slideRatio: 1 / 3
      },
      600: {
        slideRatio: 1 / 2,
        arrows: false,
        bulletsOutside: true
      },
      1100: {
        slideRatio: 1 / 4
      }
    }
  })
};
</script>

We change the slideRatio according to the breakpoints listed in the keys of the breakpoints reactive property.

Dragging Distance and Prevent Y-Axis Scroll

We can set the dragging distance with the dragging-distance prop.

To prevent y-axis scrolling, we add the prevent-y-scroll prop:

<template>
  <div id="app">
    <vueper-slides :dragging-distance="70" prevent-y-scroll>
      <vueper-slide
        v-for="i in 10"
        :key="i"
        :title="i.toString()"
        :style="`background-color: ${['#ff5252', '#42b983'][i % 2]}`"
      />
    </vueper-slides>
  </div>
</template>

<script>
import { VueperSlides, VueperSlide } from "vueperslides";
import "vueperslides/dist/vueperslides.css";

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

The dragging distance is in pixels.

Parallax Effect

We can add a parallax effect with the parallax and parallax-fixed-content props:

<template>
  <div id="app">
    <vueper-slides parallax parallax-fixed-content>
      <vueper-slide
        v-for="i in 10"
        :key="i"
        :title="`title ${i}`"
        :image="`https://picsum.photos/id/${i}/400/300`"
      />
    </vueper-slides>
  </div>
</template>

<script>
import { VueperSlides, VueperSlide } from "vueperslides";
import "vueperslides/dist/vueperslides.css";

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

Fixed Height

The heights of the slides can be fixed with the fixed-height prop:

<template>
  <div id="app">
    <vueper-slides :slide-ratio="1 / 2" fixed-height="500px">
      <vueper-slide
        v-for="i in 10"
        :key="i"
        :title="`title ${i}`"
        :image="`https://picsum.photos/id/${i}/400/300`"
      />
    </vueper-slides>
  </div>
</template>

<script>
import { VueperSlides, VueperSlide } from "vueperslides";
import "vueperslides/dist/vueperslides.css";

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

We set the aspect ratio of the slide with the aspect-ratio prop and the fixed-height prop sets the height in pixels.

Slide Image Inside

The slide-image-inside prop lets us put the image in a div in the slide container instead of the container itself:

<template>
  <div id="app">
    <vueper-slides slide-image-inside>
      <vueper-slide
        v-for="i in 10"
        :key="i"
        :title="`title ${i}`"
        :image="`https://picsum.photos/id/${i}/400/300`"
      />
    </vueper-slides>
  </div>
</template>

<script>
import { VueperSlides, VueperSlide } from "vueperslides";
import "vueperslides/dist/vueperslides.css";

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

Show Multiple Slides and Gap

We can add a gap between the slides. For example, we can write:

<template>
  <div id="app">
    <vueper-slides
      :visible-slides="3"
      slide-multiple
      :gap="3"
      :slide-ratio="1 / 4"
      :dragging-distance="200"
      :breakpoints="{ 800: { visibleSlides: 2, slideMultiple: 2 } }"
    >
      <vueper-slide
        v-for="i in 10"
        :key="i"
        :title="`title ${i}`"
        :image="`https://picsum.photos/id/${i}/400/300`"
      />
    </vueper-slides>
  </div>
</template>

<script>
import { VueperSlides, VueperSlide } from "vueperslides";
import "vueperslides/dist/vueperslides.css";

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

to add a gap with the gap prop. The slide gap is in pixels.

dragging-distance has the dragging distance.

breakpoints has an object with the breakpoints in the keys and we set the number of slides to show with the visibleSlides and slideMultiple properties.

Conclusion

We can set breakpoints, gaps in slides, and make the height fixed with the Vueper Slides Vue carousel package.