5 ejemplos prácticos para aprender Vue.js

Ya hemos cubierto Angular.js y React en artículos anteriores, pero hay una nueva biblioteca de interfaz que creemos que vale la pena. Se llama Vue.js y ha reunido a una gran comunidad de desarrolladores entusiastas.

La filosofía detrás de Vue.js es proporcionar la API más simple posible para crear enlaces de datos bidireccionales en tiempo real entre la vista (HTML) y el modelo (un objeto JavaScript). Como verá en los siguientes ejemplos, la biblioteca se mantiene fiel a esa idea y trabajar con ella es fácil y agradable, sin comprometer ninguna funcionalidad.

Cómo empezar

La forma más fácil de instalar Vue.js es simplemente incluirlo con un <script> etiqueta al final del cuerpo de su HTML. Toda la biblioteca se encuentra en un solo archivo JavaScript que puede descargar desde el sitio web oficial o importar directamente a través de CDN:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.5/vue.min.js"></script>

Si desea utilizar la biblioteca en un proyecto de Node.js, vue está disponible como módulo npm. También hay una CLI oficial, que permite a los usuarios configurar rápidamente todo su proyecto en función de compilaciones de plantillas prefabricadas.

A continuación se muestran cinco editores que contienen aplicaciones de ejemplo que hemos creado para usted. El código tiene muchos comentarios y está separado en pestañas para cada archivo, lo que lo hace muy fácil de seguir. Los editores tienen Vue.js integrado, así que no tengas miedo de experimentar. Además, puede descargar un archivo que contiene todos los ejemplos de Descargar cerca de la parte superior de este artículo.

1. Menú de navegación

Para empezar, vamos a construir una barra de navegación simple. Hay algunos componentes básicos que casi todas las aplicaciones de Vue.js deben tener. Ellos son:

  • El modelo , es decir, los datos de nuestra aplicación. En Vue.js, esto es simplemente un objeto de JavaScript que contiene variables y sus valores iniciales.
  • Una plantilla HTML, cuya terminología correcta es ver . Aquí elegimos qué mostrar, agregamos detectores de eventos y manejamos diferentes usos para el modelo.
  • Modelo de vista - una instancia de Vue que une el modelo y la vista, lo que les permite comunicarse entre sí.

La idea detrás de estas elegantes palabras es que el modelo y la vista siempre estará sincronizado. Cambiar el modelo actualizará instantáneamente la vista y viceversa. En nuestro primer ejemplo, esto se muestra con el active variable, que representa qué elemento del menú está seleccionado actualmente.

<div id="main">

    <!-- The navigation menu will get the value of the "active" variable as a class. -->

    <!-- To stops the page from jumping when a link is clicked 
        we use the "prevent" modifier (short for preventDefault). -->

    <nav v-bind:class="active" v-on:click.prevent>

        <!-- When a link in the menu is clicked, we call the makeActive method, 
        defined in the JavaScript Vue instance. It will change the value of "active". -->

        <a href="#" class="home" v-on:click="makeActive('home')">Home</a>
        <a href="#" class="projects" v-on:click="makeActive('projects')">Projects</a>
        <a href="#" class="services" v-on:click="makeActive('services')">Services</a>
        <a href="#" class="contact" v-on:click="makeActive('contact')">Contact</a>
    </nav>

    <!-- The mustache expression will be replaced with the value of "active".
         It will automatically update to reflect any changes. -->

    <p>You chose <b>{{active}}</b></p>
</div>
// Creating a new Vue instance and pass in an options object.
var demo = new Vue({

    // A DOM element to mount our view model.
    el: '#main',

    // This is the model.
    // Define properties and give them initial values.
    data: {
        active: 'home'
    },

    // Functions we will be using.
    methods: {
        makeActive: function(item){
            // When a model is changed, the view will be automatically updated.
            this.active = item;
        }
    }
});
*{
    margin:0;
    padding:0;
}

body{
    font:15px/1.3 'Open Sans', sans-serif;
    color: #5e5b64;
    text-align:center;
}

a, a:visited {
    outline:none;
    color:#389dc1;
}

a:hover{
    text-decoration:none;
}

section, footer, header, aside, nav{
    display: block;
}

/*-------------------------
    The menu
--------------------------*/

nav{
    display:inline-block;
    margin:60px auto 45px;
    background-color:#5597b4;
    box-shadow:0 1px 1px #ccc;
    border-radius:2px;
}

nav a{
    display:inline-block;
    padding: 18px 30px;
    color:#fff !important;
    font-weight:bold;
    font-size:16px;
    text-decoration:none !important;
    line-height:1;
    text-transform: uppercase;
    background-color:transparent;

    -webkit-transition:background-color 0.25s;
    -moz-transition:background-color 0.25s;
    transition:background-color 0.25s;
}

nav a:first-child{
    border-radius:2px 0 0 2px;
}

nav a:last-child{
    border-radius:0 2px 2px 0;
}

nav.home .home,
nav.projects .projects,
nav.services .services,
nav.contact .contact{
    background-color:#e35885;
}

p{
    font-size:22px;
    font-weight:bold;
    color:#7d9098;
}

p b{
    color:#ffffff;
    display:inline-block;
    padding:5px 10px;
    background-color:#c4d7e0;
    border-radius:2px;
    text-transform:uppercase;
    font-size:18px;
}

Como puede ver, trabajar con la biblioteca es bastante sencillo. Vue.js hace gran parte del trabajo por nosotros y proporciona una sintaxis familiar y fácil de recordar:

  • objeto JavaScript simple para todas las opciones
  • {{double brackets}} para plantillas
  • v-something atributos en línea para agregar funcionalidad directamente en el HTML.

2. Editor en línea

En el ejemplo anterior, nuestro modelo tenía solo un par de valores predefinidos. Si queremos darles a los usuarios la capacidad de configurar cualquier dato, podemos hacer un enlace bidireccional y vincular un campo de entrada con una propiedad del modelo. Cuando se ingresa texto, se guarda automáticamente en el text_content modelo, que luego hace que la vista se actualice.

<!-- v-cloak hides any un-compiled data bindings until the Vue instance is ready. -->
<!-- When the element is clicked the hideTooltp() method is called. -->

<div id="main" v-cloak v-on:click="hideTooltip" >

    <!-- This is the tooltip. 
         v-on:clock.stop is an event handler for clicks, with a modifier that stops event propagation.
         v-if makes sure the tooltip is shown only when the "showtooltip" variable is truthful -->

    <div class="tooltip" v-on:click.stop v-if="show_tooltip">

        <!-- v-model binds the contents of the text field with the "text_content" model.
         Any changes to the text field will automatically update the value, and
         all other bindings on the page that depend on it.  -->

        <input type="text" v-model="text_content" />
    </div>

    <!-- When the paragraph is clicked, call the "toggleTooltip" method and stop event propagation. -->

    <!-- The mustache expression will be replaced with the value of "text_content".
         It will automatically update to reflect any changes to that variable. -->

    <p v-on:click.stop="toggleTooltip">{{text_content}}</p>

</div>
// Creating a new Vue instance and pass in an options object.
var demo = new Vue({

    // A DOM element to mount our view model.
    el: '#main',

    // Define properties and give them initial values.
    data: {
        show_tooltip: false,
        text_content: 'Edit me.'
    },

    // Functions we will be using.
    methods: {
        hideTooltip: function(){
            // When a model is changed, the view will be automatically updated.
            this.show_tooltip = false;
        },
        toggleTooltip: function(){
            this.show_tooltip = !this.show_tooltip;
        }
    }
})
/* Hide un-compiled mustache bindings
until the Vue instance is ready */

[v-cloak] {
  display: none;
}

*{
    margin:0;
    padding:0;
}

body{
    font:15px/1.3 'Open Sans', sans-serif;
    color: #5e5b64;
    text-align:center;
}

a, a:visited {
    outline:none;
    color:#389dc1;
}

a:hover{
    text-decoration:none;
}

section, footer, header, aside, nav{
    display: block;
}

/*-------------------------
    The edit tooltip
--------------------------*/

.tooltip{
    background-color:#5c9bb7;

    background-image:-webkit-linear-gradient(top, #5c9bb7, #5392ad);
    background-image:-moz-linear-gradient(top, #5c9bb7, #5392ad);
    background-image:linear-gradient(top, #5c9bb7, #5392ad);

    box-shadow: 0 1px 1px #ccc;
    border-radius:3px;
    width: 290px;
    padding: 10px;

    position: absolute;
    left:50%;
    margin-left:-150px;
    top: 80px;
}

.tooltip:after{
    /* The tip of the tooltip */
    content:'';
    position:absolute;
    border:6px solid #5190ac;
    border-color:#5190ac transparent transparent;
    width:0;
    height:0;
    bottom:-12px;
    left:50%;
    margin-left:-6px;
}

.tooltip input{
    border: none;
    width: 100%;
    line-height: 34px;
    border-radius: 3px;
    box-shadow: 0 2px 6px #bbb inset;
    text-align: center;
    font-size: 16px;
    font-family: inherit;
    color: #8d9395;
    font-weight: bold;
    outline: none;
}

p{
    font-size:22px;
    font-weight:bold;
    color:#6d8088;
    height: 30px;
    cursor:default;
}

p b{
    color:#ffffff;
    display:inline-block;
    padding:5px 10px;
    background-color:#c4d7e0;
    border-radius:2px;
    text-transform:uppercase;
    font-size:18px;
}

p:before{
    content:'✎';
    display:inline-block;
    margin-right:5px;
    font-weight:normal;
    vertical-align: text-bottom;
}

#main{
    height:300px;
    position:relative;
    padding-top: 150px;
}

Otra cosa a tener en cuenta en el código anterior es el v-if atributo . Muestra u oculta un elemento completo dependiendo de la veracidad de una variable. Puedes leer más sobre esto aquí.

3. Formulario de pedido

Este ejemplo ilustra múltiples servicios y su costo total. Dado que nuestros servicios se almacenan en una matriz, podemos aprovechar el v-for directiva para recorrer todas las entradas y mostrarlas. Si se agrega un nuevo elemento a la matriz o se cambia alguno de los anteriores, Vue.js se actualizará automáticamente y mostrará los nuevos datos.

<!-- v-cloak hides any un-compiled data bindings until the Vue instance is ready. -->

<form id="main" v-cloak>

    <h1>Services</h1>

    <ul>
        <!-- Loop through the services array, assign a click handler, and set or
             remove the "active" css class if needed -->
        <li v-for="service in services" v-on:click="toggleActive(service)" v-bind:class="{ 'active': service.active}">
            <!-- Display the name and price for every entry in the array .
                Vue.js has a built in currency filter for formatting the price -->
            {{service.name}} <span>{{service.price | currency}}</span>
        </li>
    </ul>

    <div class="total">
        <!-- Calculate the total price of all chosen services. Format it as currency. -->
        Total: <span>{{total() | currency}}</span>
    </div>

</form>
// Define a custom filter called "currency". 
Vue.filter('currency', function (value) {
    return '$' + value.toFixed(2);
});

var demo = new Vue({
    el: '#main',
    data: {
        // Define the model properties. The view will loop
        // through the services array and genreate a li
        // element for every one of its items.
        services: [
            {
                name: 'Web Development',
                price: 300,
                active:true
            },{
                name: 'Design',
                price: 400,
                active:false
            },{
                name: 'Integration',
                price: 250,
                active:false
            },{
                name: 'Training',
                price: 220,
                active:false
            }
        ]
    },
    methods: {
        toggleActive: function(s){
            s.active = !s.active;
        },
        total: function(){

            var total = 0;

            this.services.forEach(function(s){
                if (s.active){
                    total+= s.price;
                }
            });

           return total;
        }
    }
});
@import url(https://fonts.googleapis.com/css?family=Cookie);

/* Hide un-compiled mustache bindings
until the Vue instance is ready */

[v-cloak] {
  display: none;
}

*{
    margin:0;
    padding:0;
}

body{
    font:15px/1.3 'Open Sans', sans-serif;
    color: #5e5b64;
    text-align:center;
}

a, a:visited {
    outline:none;
    color:#389dc1;
}

a:hover{
    text-decoration:none;
}

section, footer, header, aside, nav{
    display: block;
}

/*-------------------------
    The order form
--------------------------*/

form{
    background-color: #61a1bc;
    border-radius: 2px;
    box-shadow: 0 1px 1px #ccc;
    width: 400px;
    padding: 35px 60px;
    margin: 50px auto;
}

form h1{
    color:#fff;
    font-size:64px;
    font-family:'Cookie', cursive;
    font-weight: normal;
    line-height:1;
    text-shadow:0 3px 0 rgba(0,0,0,0.1);
}

form ul{
    list-style:none;
    color:#fff;
    font-size:20px;
    font-weight:bold;
    text-align: left;
    margin:20px 0 15px;
}

form ul li{
    padding:20px 30px;
    background-color:#e35885;
    margin-bottom:8px;
    box-shadow:0 1px 1px rgba(0,0,0,0.1);
    cursor:pointer;
}

form ul li span{
    float:right;
}

form ul li.active{
    background-color:#8ec16d;
}

div.total{
    border-top:1px solid rgba(255,255,255,0.5);
    padding:15px 30px;
    font-size:20px;
    font-weight:bold;
    text-align: left;
    color:#fff;
}

div.total span{
    float:right;
}

Para mostrar los precios en un formato correcto tendremos que definir un filtro de moneda simple. Los filtros nos permiten modificar o filtrar perezosamente los datos del modelo. Para definir un filtro personalizado tenemos que usar la siguiente sintaxis:

// Define a custom filter called "currency". 
Vue.filter('currency', function (value) {
    return '$' + value.toFixed(2);
});

Como puede ver, nuestro filtro es bastante sencillo:agrega un signo de dólar y decimales numéricos adecuados. Al igual que en Angular, los filtros se aplican usando el botón | sintaxis - {{ some_data | filter }} .

4. Búsqueda instantánea

Aquí crearemos una aplicación que exhiba algunos de los artículos en nuestro sitio web. La aplicación también tendrá un campo de búsqueda de texto que nos permitirá filtrar qué artículos se muestran. Todos los artículos se guardarán en un article s matriz, y los artículos que coincidan con la consulta de búsqueda estarán en una propiedad calculada llamada filteredArticles .

<form id="main" v-cloak>

    <div class="bar">
        <!-- Create a binding between the searchString model and the text field -->

        <input type="text" v-model="searchString" placeholder="Enter your search terms" />
    </div>

    <ul>
        <!-- Render a li element for every entry in the computed filteredArticles array. -->

        <li v-for="article in filteredArticles">
            <a v-bind:href="article.url"><img v-bind:src="article.image" /></a>
            <p>{{article.title}}</p>
        </li>
    </ul>

</form>
var demo = new Vue({
    el: '#main',
    data: {
        searchString: "",

        // The data model. These items would normally be requested via AJAX,
        // but are hardcoded here for simplicity.

        articles: [
            {
                "title": "What You Need To Know About CSS Variables",
                "url": "https://tutorialzine.com/2016/03/what-you-need-to-know-about-css-variables/",
                "image": "https://tutorialzine.com/media/2016/03/css-variables.jpg"
            },
            {
                "title": "Freebie: 4 Great Looking Pricing Tables",
                "url": "https://tutorialzine.com/2016/02/freebie-4-great-looking-pricing-tables/",
                "image": "https://tutorialzine.com/media/2016/02/great-looking-pricing-tables.jpg"
            },
            {
                "title": "20 Interesting JavaScript and CSS Libraries for February 2016",
                "url": "https://tutorialzine.com/2016/02/20-interesting-javascript-and-css-libraries-for-february-2016/",
                "image": "https://tutorialzine.com/media/2016/02/interesting-resources-february.jpg"
            },
            {
                "title": "Quick Tip: The Easiest Way To Make Responsive Headers",
                "url": "https://tutorialzine.com/2016/02/quick-tip-easiest-way-to-make-responsive-headers/",
                "image": "https://tutorialzine.com/media/2016/02/quick-tip-responsive-headers.png"
            },
            {
                "title": "Learn SQL In 20 Minutes",
                "url": "https://tutorialzine.com/2016/01/learn-sql-in-20-minutes/",
                "image": "https://tutorialzine.com/media/2016/01/learn-sql-20-minutes.png"
            },
            {
                "title": "Creating Your First Desktop App With HTML, JS and Electron",
                "url": "https://tutorialzine.com/2015/12/creating-your-first-desktop-app-with-html-js-and-electron/",
                "image": "https://tutorialzine.com/media/2015/12/creating-your-first-desktop-app-with-electron.png"
            }
        ]
    },
    computed: {
        // A computed property that holds only those articles that match the searchString.
        filteredArticles: function () {
            var articles_array = this.articles,
                searchString = this.searchString;

            if(!searchString){
                return articles_array;
            }

            searchString = searchString.trim().toLowerCase();

            articles_array = articles_array.filter(function(item){
                if(item.title.toLowerCase().indexOf(searchString) !== -1){
                    return item;
                }
            })

            // Return an array with the filtered data.
            return articles_array;;
        }
    }
});
/* Hide un-compiled mustache bindings
until the Vue instance is ready */

[v-cloak] {
  display: none;
}

*{
    margin:0;
    padding:0;
}

body{
    font:15px/1.3 'Open Sans', sans-serif;
    color: #5e5b64;
    text-align:center;
}

a, a:visited {
    outline:none;
    color:#389dc1;
}

a:hover{
    text-decoration:none;
}

section, footer, header, aside, nav{
    display: block;
}

/*-------------------------
    The search input
--------------------------*/

.bar{
    background-color:#5c9bb7;

    background-image:-webkit-linear-gradient(top, #5c9bb7, #5392ad);
    background-image:-moz-linear-gradient(top, #5c9bb7, #5392ad);
    background-image:linear-gradient(top, #5c9bb7, #5392ad);

    box-shadow: 0 1px 1px #ccc;
    border-radius: 2px;
    width: 400px;
    padding: 14px;
    margin: 45px auto 20px;
    position:relative;
}

.bar input{
    background:#fff no-repeat 13px 13px;
    background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkU5NEY0RTlFMTA4NzExRTM5RTEzQkFBQzMyRjkyQzVBIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkU5NEY0RTlGMTA4NzExRTM5RTEzQkFBQzMyRjkyQzVBIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6RTk0RjRFOUMxMDg3MTFFMzlFMTNCQUFDMzJGOTJDNUEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6RTk0RjRFOUQxMDg3MTFFMzlFMTNCQUFDMzJGOTJDNUEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4DjA/RAAABK0lEQVR42pTSQUdEURjG8dOY0TqmPkGmRcqYD9CmzZAWJRHVRIa0iFYtM6uofYaiEW2SRJtEi9YxIklp07ZkWswu0v/wnByve7vm5ee8M+85zz1jbt9Os+WiGkYdYxjCOx5wgFeXUHmtBSzpcCGa+5BJTCjEP+0nKWAT8xqe4ArPGEEVC1hHEbs2oBwdXkM7mj/JLZrad437sCGHOfUtcziutuYu2v8XUFF/4f6vMK/YgAH1HxkBYV60AR31gxkBYd6xAeF3VzMCwvzOBpypX8V4yuFRzX2d2gD/l5yjH4fYQEnzkj4fae5rJulF2sMXVrAsaTWttRFu4Osb+1jEDT71/ZveyhouTch2fINQL9hKefKjuYFfuznXWzXMTabyrvfyIV3M4vhXgAEAUMs7K0J9UJAAAAAASUVORK5CYII=);

    border: none;
    width: 100%;
    line-height: 19px;
    padding: 11px 0;

    border-radius: 2px;
    box-shadow: 0 2px 8px #c4c4c4 inset;
    text-align: left;
    font-size: 14px;
    font-family: inherit;
    color: #738289;
    font-weight: bold;
    outline: none;
    text-indent: 40px;
}

ul{
    list-style: none;
    width: 428px;
    margin: 0 auto;
    text-align: left;
}

ul li{
    border-bottom: 1px solid #ddd;
    padding: 10px;
    overflow: hidden;
}

ul li img{
    width:60px;
    height:60px;
    float:left;
    border:none;
}

ul li p{
    margin-left: 75px;
    font-weight: bold;
    padding-top: 12px;
    color:#6e7a7f;
}

El campo de entrada está vinculado a la cadena de búsqueda modelo. Cuando se ingresa texto, el modelo se actualiza instantáneamente y la matriz de artículos filtrados calculados se genera nuevamente. De esta manera, podemos crear una búsqueda en tiempo real sin tener que preocuparnos por renderizar o configurar detectores de eventos:¡Vue.js se encarga de todo eso!

5. Rejilla conmutable

En nuestro último ejemplo, demostraremos un escenario común donde una página tiene diferentes modos de diseño. Al igual que en la aplicación anterior, mostraremos una lista de artículos de tutorialzine.com almacenados en una matriz.

Al presionar uno de los botones en la barra superior, puede cambiar entre un diseño de cuadrícula que contiene imágenes grandes y un diseño de lista con imágenes y texto más pequeños.

<form id="main" v-cloak>

    <div class="bar">

        <!-- These two buttons switch the layout variable,
             which causes the correct UL to be shown. -->

        <a class="list-icon" v-bind:class="{ 'active': layout == 'list'}" v-on:click="layout = 'list'"></a>
        <a class="grid-icon" v-bind:class="{ 'active': layout == 'grid'}" v-on:click="layout = 'grid'"></a>
    </div>

    <!-- We have two layouts. We choose which one to show depending on the "layout" binding -->

    <ul v-if="layout == 'grid'" class="grid">
        <!-- A view with big photos and no text -->
        <li v-for="a in articles">
            <a v-bind:href="a.url" target="_blank"><img v-bind:src="a.image.large" /></a>
        </li>
    </ul>

    <ul v-if="layout == 'list'" class="list">
        <!-- A compact view smaller photos and titles -->
        <li v-for="a in articles">
            <a v-bind:href="a.url" target="_blank"><img v-bind:src="a.image.small" /></a>
            <p>{{a.title}}</p>
        </li>
    </ul>

</form>
var demo = new Vue({
    el: '#main',
    data: {
        // The layout mode, possible values are "grid" or "list".
        layout: 'grid',

        articles: [{
            "title": "What You Need To Know About CSS Variables",
            "url": "https://tutorialzine.com/2016/03/what-you-need-to-know-about-css-variables/",
            "image": {
                "large": "https://tutorialzine.com/media/2016/03/css-variables.jpg",
                "small": "https://tutorialzine.com/media/2016/03/css-variables.jpg"
            }
        },
        {
            "title": "Freebie: 4 Great Looking Pricing Tables",
            "url": "https://tutorialzine.com/2016/02/freebie-4-great-looking-pricing-tables/",
            "image": {
                "large": "https://tutorialzine.com/media/2016/02/great-looking-pricing-tables.jpg",
                "small": "https://tutorialzine.com/media/2016/02/great-looking-pricing-tables.jpg"
            }
        },
        {
            "title": "20 Interesting JavaScript and CSS Libraries for February 2016",
            "url": "https://tutorialzine.com/2016/02/20-interesting-javascript-and-css-libraries-for-february-2016/",
            "image": {
                "large": "https://tutorialzine.com/media/2016/02/interesting-resources-february.jpg",
                "small": "https://tutorialzine.com/media/2016/02/interesting-resources-february.jpg"
            }
        },
        {
            "title": "Quick Tip: The Easiest Way To Make Responsive Headers",
            "url": "https://tutorialzine.com/2016/02/quick-tip-easiest-way-to-make-responsive-headers/",
            "image": {
                "large": "https://tutorialzine.com/media/2016/02/quick-tip-responsive-headers.png",
                "small": "https://tutorialzine.com/media/2016/02/quick-tip-responsive-headers.png"
            }
        },
        {
            "title": "Learn SQL In 20 Minutes",
            "url": "https://tutorialzine.com/2016/01/learn-sql-in-20-minutes/",
            "image": {
                "large": "https://tutorialzine.com/media/2016/01/learn-sql-20-minutes.png",
                "small": "https://tutorialzine.com/media/2016/01/learn-sql-20-minutes.png"
            }
        },
        {
            "title": "Creating Your First Desktop App With HTML, JS and Electron",
            "url": "https://tutorialzine.com/2015/12/creating-your-first-desktop-app-with-html-js-and-electron/",
            "image": {
                "large": "https://tutorialzine.com/media/2015/12/creating-your-first-desktop-app-with-electron.png",
                "small": "https://tutorialzine.com/media/2015/12/creating-your-first-desktop-app-with-electron.png"
            }
        }]

    }
});
/* Hide un-compiled mustache bindings
until the Vue instance is ready */

[v-cloak] {
  display: none;
}

*{
    margin:0;
    padding:0;
}

body{
    font:15px/1.3 'Open Sans', sans-serif;
    color: #5e5b64;
    text-align:center;
}

a, a:visited {
    outline:none;
    color:#389dc1;
}

a:hover{
    text-decoration:none;
}

section, footer, header, aside, nav{
    display: block;
}

/*-------------------------
    The search input
--------------------------*/

.bar{
    background-color:#5c9bb7;

    background-image:-webkit-linear-gradient(top, #5c9bb7, #5392ad);
    background-image:-moz-linear-gradient(top, #5c9bb7, #5392ad);
    background-image:linear-gradient(top, #5c9bb7, #5392ad);

    box-shadow: 0 1px 1px #ccc;
    border-radius: 2px;
    width: 580px;
    padding: 10px;
    margin: 45px auto 25px;
    position:relative;
    text-align:right;
    line-height: 1;
}

.bar a{
    background:#4987a1 center center no-repeat;
    width:32px;
    height:32px;
    display:inline-block;
    text-decoration:none !important;
    margin-right:5px;
    border-radius:2px;
    cursor:pointer;
}

.bar a.active{
    background-color:#c14694;
}

.bar a.list-icon{
    background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkYzNkFCQ0ZBMTBCRTExRTM5NDk4RDFEM0E5RkQ1NEZCIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkYzNkFCQ0ZCMTBCRTExRTM5NDk4RDFEM0E5RkQ1NEZCIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6RjM2QUJDRjgxMEJFMTFFMzk0OThEMUQzQTlGRDU0RkIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6RjM2QUJDRjkxMEJFMTFFMzk0OThEMUQzQTlGRDU0RkIiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7h1bLqAAAAWUlEQVR42mL8////BwYGBn4GCACxBRlIAIxAA/4jaXoPEkMyjJ+A/g9MDJQBRhYg8RFqMwg8RJIUINYLFDmBUi+ADQAF1n8ofk9yIAy6WPg4GgtDMRYAAgwAdLYwLAoIwPgAAAAASUVORK5CYII=);
}

.bar a.grid-icon{
    background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjBEQkMyQzE0MTBCRjExRTNBMDlGRTYyOTlBNDdCN0I4IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjBEQkMyQzE1MTBCRjExRTNBMDlGRTYyOTlBNDdCN0I4Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MERCQzJDMTIxMEJGMTFFM0EwOUZFNjI5OUE0N0I3QjgiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MERCQzJDMTMxMEJGMTFFM0EwOUZFNjI5OUE0N0I3QjgiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4MjPshAAAAXklEQVR42mL4////h/8I8B6IGaCYKHFGEMnAwCDIAAHvgZgRyiZKnImBQsACxB+hNoDAQyQ5osQZIT4gH1DsBZABH6AB8x/JaQzEig++WPiII7Rxio/GwmCIBYAAAwAwVIzMp1R0aQAAAABJRU5ErkJggg==);
}

.bar input{
    background:#fff no-repeat 13px 13px;

    border: none;
    width: 100%;
    line-height: 19px;
    padding: 11px 0;

    border-radius: 2px;
    box-shadow: 0 2px 8px #c4c4c4 inset;
    text-align: left;
    font-size: 14px;
    font-family: inherit;
    color: #738289;
    font-weight: bold;
    outline: none;
    text-indent: 40px;
}

/*-------------------------
    List layout
--------------------------*/

ul.list{
    list-style: none;
    width: 500px;
    margin: 0 auto;
    text-align: left;
}

ul.list li{
    border-bottom: 1px solid #ddd;
    padding: 10px;
    overflow: hidden;
}

ul.list li img{
    width:120px;
    height:120px;
    float:left;
    border:none;
}

ul.list li p{
    margin-left: 135px;
    font-weight: bold;
    color:#6e7a7f;
}

/*-------------------------
    Grid layout
--------------------------*/

ul.grid{
    list-style: none;
    width: 570px;
    margin: 0 auto;
    text-align: left;
}

ul.grid li{
    padding: 2px;
    float:left;
}

ul.grid li img{
    width:280px;
    height:280px;
    object-fit: cover;
    display:block;
    border:none;
}

Conclusión

Hay mucho más en Vue.js que lo que mostramos en estos ejemplos. La biblioteca también ofrece animaciones, componentes personalizados y todo tipo de otras funciones. Le recomendamos que consulte la excelente documentación oficial que está llena de información y fragmentos útiles.

¿Tiene problemas para decidir si Vue.js es la biblioteca adecuada para su proyecto? Los siguientes enlaces te serán de gran ayuda:

  • Una comparación oficial detallada con otros marcos:aquí.
  • TodoMVC:un sitio web donde se recrea la misma aplicación con muchos marcos diferentes.
  • Nuestros artículos donde hemos hecho ejemplos similares usando React y Angular.js.

¡Gracias por leer!


No