Tutorial

Using Vue Template Syntax to Build A Photo Gallery

Published on March 24, 2020
author

Parthiv Mohan

Using Vue Template Syntax to Build A Photo Gallery

Vue is best used when with its templating features. It becomes very intuitive to build fancy user interfaces.

Take its directives, for example, which refers to tag attributes with the v- prefix.

You could have a variable url in your Vue instance that your anchor tag uses as its href. That would look like this:

<a v-bind:href="url"></a>

Let’s try it with the other directive that we’ll find ourselves using a lot:

<a v-on:click="myFunction"></a>

That is how we would call one of our component’s functions upon clicking the link.


Dynamic arguments take your directives to a new level. Consider the following:

<a v-bind:[attributeName]="url">...</a>

attributeName is itself a JavaScript expression like url, interpreted as such because of the square brackets around it.

<a v-on:[event]="myFunction"></a> would mean that the event variable could be "hover" or "click" or any other attribute used with v-on.


Let’s go over one more thing.

The directives v-on and v-bind are so common that we have shortcuts for writing them in Vue; : and @.

So, an img tag with a dynamic attribute could be <img :[classOrId]="value" @click="display"> where display is a function, value is a string variable, and classOrId is also a string variable.


To expand on that, we’re going to create a photo gallery with some of this new fangled template syntax. Get ready!

App Setup

If you don’t have the Vue CLI installed already, start by running either of these commands in your terminal, depending on if you prefer using npm or Yarn:

$ npm install -g @vue/cli

or

$ yarn global add @vue/cli

Now you’ll be able to run the vue command from the command line. Let’s create a Vue app called alligator-zest

$ vue create alligator-zest
$ cd alligator-zest
$ npm run build
$ npm run serve

Next, we’re going to change HelloWorld.vue to be PhotoGallery.vue. App.vue should look something like this:

App.vue
<template>
  <div id="app">
    <PhotoGallery/>
  </div>
</template>

<script>
import PhotoGallery from './components/PhotoGallery.vue'

export default {
  name: 'App',
  components: {
    PhotoGallery
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

PhotoGallery.vue is where we’re about to get fancy while keeping things simple at the same time. 🌈

Let’s assume we have 5 photo files in the assets/photos folder named 1.jpeg through 5.jpeg. Use any images you want.

PhotoGallery.vue
<template>
  <div>
    <ul class="gallery">
      <li v-for="n in 5" :key="n">
        <img
          :src="require('@/assets/photos/' + n + '.jpeg')"
        >
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'PhotoGallery'
}
</script>

<style scoped>
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
.gallery {
  display: flex;
  justify-content: space-around;
}
img {
  width: 20%;
}
</style>

The @ symbol is a webpack alias that points to the src folder.

Note the display: flex on "gallery" as well as the v-for in the <li> tag. You should be able to see the app in your browser at localhost:8080.

Let’s update this code so that when we click on a photo it’s enlarged.

PhotoGallery.vue
<template>
  <div>
    <ul class="gallery">
      <li v-for="n in 5" :key="n">
        <img
             @click="highlight"
          :src="require('@/assets/photos/beijing/' + n + '.jpeg')"
        >
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'PhotoGallery'
},
methods: {
  highlight() {
    event.target.id = "theater";
    let eventIterator = event.target.parentNode;
    while (eventIterator.previousElementSibling != null) {
      eventIterator.previousElementSibling.getElementsByTagName('img')[0].id = "";
      eventIterator = eventIterator.previousElementSibling;
    }
    eventIterator = event.target.parentNode;
    while (eventIterator.nextElementSibling != null) {
      eventIterator.nextElementSibling.getElementsByTagName('img')[0].id = "";
      eventIterator = eventIterator.nextElementSibling;
    }
  }
}
</script>

<style scoped>
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
.gallery {
  display: flex;
  justify-content: space-around;
}
img {
  width: 20%;
}
#theater {
  width: 40%;
}
</style>

We added a v-on:click to each image that sets off the highlight() method. This method makes the image that is clicked-on become larger while ensuring that the others are thumbnail-sized.

It sets the id of the clicked image to “theater” which has a larger width. Then, it gets the sibling nodes of the parent node off of the image, the li with the v-for in it. It goes into all of these li tags and sets their respective img tag’s id to a null string to make sure that only one img has the “theater” id at any given time.

This is cool but it’s still not what we see on the web; how can we get the enlarged image to be a big display, say, under the 5 thumbnails? The end result would be a roll of thumbnails with the selected image enlarged to a real theater size right below. Sounds good, right?

We’re going to add the following:

<div id="frame">
  <img
    :src="this.theatrical"
  >
</div>
data() {
  return {
    theatrical: ""
  }
},
methods: {
  highlight() {
    event.target.id = "theater";
    this.theatrical = event.target.src;

And finally, add the following to your CSS.

#frame img {
  width: 80%;
}

Check it out in your browser!

The big frame is filled up by the photo that you clicked-on since its src attribute gets set when you click. Now you have a nice gallery view of your photos!

All with some nifty use of Vue’s reactivity system, data properties, and template syntax. 🧪

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Parthiv Mohan

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Featured on Community

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more