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!
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:
<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.
<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.
<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.
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.
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!