Building Your First App With Vue.js

Build an app for browsing Reddit posts.

A tutorial by Tutorialzine

The App

The applications' purpose is simply to fetch the feed from a number of subbreddits and display them. Here is what the end result will look like:

Final Result

The code will contain

  1. Custom Components
  2. Custom Filters

The Full Code

Here is the full code of the app for you to take a look and get an idea on how things work.

Javascript

/*-----------------
    Components 
-----------------*/

// Parent | Subreddit component containing a list of 'post' components. 
var subreddit = Vue.component('subreddit',{
    template: '#subreddit',
    props: ['name'],

    data: function () {
        return { posts: [] }
    },

    created: function(){
        this.$http.get("https://www.reddit.com/r/"+ this.name +"/top.json?limit=3")
        .then(function(resp){
            this.posts=resp.data.data.children;
        });
    }
});

// Child | Componenet represiting a single post.
var post = Vue.component('post', {
    template: "#post",
    props: ['item']
});

/*-----------------
   Custom filters 
-----------------*/

// Filter for cutting off strings that are too long.
Vue.filter('truncate', function(value) {
    var length = 60;

    if(value.length <= length) {
        return value;
    }
    else {
        return value.substring(0, length) + '...';            
    }
});

// Filter that takes an image url and creates a CSS style.
Vue.filter('setAsBackground', function(value) {
    if(value && value!='self' && value!='nsfw') {
        return 'background-image: url(' + value + ')';  
    }
    else {
        return 'background-image: url(assets/img/placeholder.png)';   
    }
});

/*-----------------
   Initialize app 
-----------------*/

new Vue({
    el: 'body'
});

HTML

<!DOCTYPE html>
<html>
<head>
    <title>Your First App With Vue.js</title>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link rel="stylesheet" type="text/css" href="assets/css/styles.css">
</head>
<body>
    <div class="container">
        <subreddit name="aww"></subreddit>
        <subreddit name="space"></subreddit>
        <subreddit name="gifs"></subreddit>
        <subreddit name="food"></subreddit>
        <subreddit name="comics"></subreddit>
        <subreddit name="sports"></subreddit>
    </div>

    <template id="subreddit">
        <div class="subreddit">
            <h2>{{ name | uppercase }}</h2>
            <ul class="item-list">
                <li v-for="obj in posts">
                    <post :item="obj"></post>
                </li>
            </ul>
        </div>
    </template>

    <template id="post">
        <div class="post">
            <a   :href="item.data.url" :style="item.data.thumbnail | setAsBackground" 
                 target="_blank" class="thumbnail"></a>
            <div class="details">
                <a :href="item.data.url" :title="item.data.title" target="_blank" class="title">
                    {{ item.data.title | truncate}}
                </a>          

                <div class="action-buttons">
                    <a href="http://reddit.com{{ item.data.permalink }}" title="Vote">
                        <i class="material-icons">thumbs_up_down</i>
                        {{item.data.score}}
                    </a>

                    <a href="http://reddit.com{{ item.data.permalink }}" title="Go to discussion">
                        <i class="material-icons">forum</i>
                        {{item.data.num_comments}}
                    </a>
                </div>
            </div>
        </div>       
    </template>

    <script src="assets/js/vue.js"></script>
    <script src="assets/js/vue-resource.min.js"></script>
    <script src="assets/js/script.js"></script>
</body>
</html>

CSS

*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

a{
    text-decoration: none;
}

a:hover{
    text-decoration: underline;
}

html{
    font: normal 16px sans-serif;
    color: #333;
    background-color: #f9f9f9;
}

.container{
    padding: 27px 20px;
    margin: 30px auto 50px;
    max-width: 1250px;
    display: flex;
    flex-wrap: wrap;
    flex-direction: row;
    background-color: #fff;
    box-shadow: 0 0 1px #ccc;
}

/* Subreddit component */

.subreddit{
    flex: 0 0 33%;
    min-width: 400px;
    padding: 20px 42px;
}

.subreddit h2{
    font-size: 18px;
    margin-bottom: 10px;
}

.subreddit .item-list{
    border-top: 1px solid #bec9d0;
    padding-top: 20px;
    list-style: none;
}

.subreddit .item-list li{
    margin-bottom: 17px;
}

/* Post component */

.post{
    display: flex;
}

.post .thumbnail{
    display: block;
    flex: 0 0 60px;
    height: 60px;
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center;
    margin-right: 10px;
    border-radius: 4px;
    margin-right: 12px;
}

.post .details{
    display: flex;
    flex-direction: column;
}

.post .details .title{
    font-size: 15px;
    margin-bottom: 3px;
    color: #04477b;
}

.post .details .title:visited{
    color: purple;
}

.post .details .action-buttons a{
    font-size: 11px;
    margin-right: 4px;
    display: inline-block;
    color: #666;
}

.post .details .action-buttons i{
    font-size: 10px;
    margin-right: 1px;
}

@media(max-width: 1250px){

    .container{
        justify-content: center;
        margin: 30px 30px 50px 30px;
    }
}

@media(max-width: 500px){

    .subreddit{
        min-width: 300px;
        padding: 20px 15px;
    }
}

See a more detailed tutorial on tutorialzine

Demo