Skip to content

Instantly share code, notes, and snippets.

@mrcodedev
Last active May 27, 2023 02:24
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrcodedev/741b61abeeb8547de30e7f1661861575 to your computer and use it in GitHub Desktop.
Save mrcodedev/741b61abeeb8547de30e7f1661861575 to your computer and use it in GitHub Desktop.
VueJS2 - Empezando con Vue

Vue2JS - Empezando con VueJS

Como iniciar Vue con CDN

Para iniciar Vue podemos utilizarlo a través de un CDN o añadiendo el archivo físicamente. Aquí empezarémos a utilizarlo a través de CDN. El enlace del CDN puede variar con el tiempo, pero cuando escribo este Gist es el siguiente:

https://cdn.jsdelivr.net/npm/vue/dist/vue.js

Creamos un archivo htmly añadimos el CDN:

/index.html

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
</body>
</html>

Una vez creado el html con el script del CDN, inicializamos un script con una nueva instancia de Vue. Vamos a llamar al elemento app:

new Vue({
  el: '#app',
});

Estamos que debemos de crear un div con el id app para que se inicialice dentro Vue.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
    </div>
    <script>
        new Vue({
            el: '#app',
        });
    </script>
</body>
</html>

Vamos a inicializar el método data donde guardaremos variables y podrémos utilizar a través de interpolación. Vamos a crear un mensaje Hola mundo:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        {{ message }}
    </div>
    <script>
        new Vue({
            el: '#app',
            data() {
                return {
                    message: 'Hola Mundo',
                }
            }

        });
    </script>
</body>
</html>

Componentes

Lo más correcto es tener todo en distintos archivos modularizados, lo que llamamos en Vue componentes. Así que vamos a crear un archivo en la misma carpeta llamado components y vamos a llamarlo por ejemplo message.js (cuando utilicemos el CLI de Vue usaremos la extensión .vue, pero como usamos la versión de CDN es mejor usar .js). Los archivos quedarían de la siguiente manera:

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
</head>
<body>
    <div id="app">
        <message></message>
    </div>
    <script>
        new Vue({
            el: '#app',
        });
    </script>
</body>
</html>

/components/message.js

Vue.component('message', {
    data() {
        return {
            message: 'Hola Mundo',
        }
    },
    template: `
        <div>
            <h2>Componente message</h2>
            <p>{{ message }}</p>
        </div>
    `
});

Cosas importantes

  • Cada template tendrá que tener un contenedor padre.
  • Los componentes deben estar antes que la instancia de Vue.

Computed properties

Nos permiten crear nuevas propiedades reactivas que dependen de otra propiedades del objeto datay que pueden tener una lógica "complicada" (filtros, concatenaciones, etc).

Un ejemplo de computed properties sería el siguiente:

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
</head>
<body>
    <div id="app">
        <message></message>
        <computed-properties></computed-properties>
    </div>
    <script>
        new Vue({
            el: '#app',
        });
    </script>
</body>
</html>

Hemos añadido un script con computed-properties y añadido el tag con el mismo nombre <computed-properties></computed-properties>

Después añadimos el componente, con una data, un computed con los elementos a mostrar del datay un template:

/components/computed-properties.js

Vue.component('computed-properties', {
    data() {
        return {
            name: 'José Luis',
            surname: 'García'
        }
    },
    computed: {
        fullName() {
            return `${this.name} ${this.surname}`;
        },
    },
    template: `
        <div>
            <h2>Computed properties</h2>
            <p>{{ fullName }}</p>
        </div>
    `
});

Métodos

Para escribir métodos utilizaremos la palabra methods y ahí meteremos los elementos que queramos.

En el siguiente ejemplo vemos como implementamos methods:

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
</head>
<body>
    <div id="app">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
    </div>
    <script>
        new Vue({
            el: '#app',
        });
    </script>
</body>
</html>

Y el componente es el siguiente:

/components/methods.js

Vue.component('methods', {
    data() {
        return {
            name: 'José Luis',
            surname: 'García'
        }
    },
    computed: {
        fullName() {
            return `${this.name} ${this.surname}`;
        }
    },
    methods: {
        hello() {
            alert(this.fullName);
        }
    },
    template: `
        <div>
            <h2>Ejecutar métodos con Vuejs</h2>
            <p @click="hello">Pulsa aquí para ejecutar el método hello</p>
        </div>
    `
});

El evento v-on:click es igual que @click es un atajo.

Data Binding con v-model

Es una forma de actualizar datos tanto en la template como en el script, que sean de ida y vuelta. Son muy útiles cuando utilizamos formularios.

La directiva v-model espera un dato, en este caso espera el dato framework.

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
</head>
<body>
    <div id="app">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
    </div>
    <script>
        new Vue({
            el: '#app',
        });
    </script>
</body>
</html>

/components/vmodel.js

Vue.component('vmodel', {
    data() {
        return {
            framework: 'Vuejs2',
        }
    },
    template: `
        <div>
            <h2>Trabajando con vmodel</h2>
            <input v-model="framework" />
            <p>El framework usado es {{ framework }}</p>
        </div>
    `
})

Vmodel con formulario y array

Un ejemplo de v-modelcon formulario y array es el siguiente:

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
</head>
<body>
    <div id="app">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
    </div>
    <script>
        new Vue({
            el: '#app',
        });
    </script>
</body>
</html>

/components/vmodel-checkboxes.js

Vue.component('vmodel-checkboxes', {
    data() {
        return {
            frameworks: [],
        }
    },
    template: `
        <div>
            <h2>Vmodel con arrays</h2>
            <input type="checkbox" id="vuejs2" value="Vuejs2" v-model="frameworks" />
            <label for="vuejs2">Vuejs 2</label>
            <input type="checkbox" id="reactjs" value="Reactjs" v-model="frameworks" />
            <label for="reactjs">Reactjs</label>
            <input type="checkbox" id="angular" value="Angular" v-model="frameworks" />
            <label for="angular">Angular</label>
            <p>Frameworks seleccionados: {{ frameworks }}</p>
        </div>
    `
});

Emitir eventos a componentes padres con $emit

Los eventos siempre se emiten del elemento hijo al elemento padre (de abajo hacia arriba). Para entender esto tenemos el siguiente ejemplo:

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
</head>
<body>
    <div id="app">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
    </div>
    <script>
        new Vue({
            el: '#app',
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

Vemos que utilizamos el componente <emit> el cual le pasamos un evento v-on con @ con el nombre @show_card_brand y le pasamos un método. En la misma página añadimos el método con el alert.

/components/emit.js

Vue.component('emit', {
    data() {
        return {
            carBrand: 'Tesla',
        }
    },
    template: `
        <div>
            <h2>Emitir eventos Vuejs2</h2>
            <p @click="$emit('show_car_brand', carBrand)">Pulsa aquí para emitir un evento a la instancia ROOT de VueJS</p>
        </div>
    `
});

$emit nos permite pasar dos cosas, el primero es el evento que queremos emitir y el segundo el dato le queremos pasar cuando pasemos el evento: <p @click="$emit('show_car_brand', carBrand)">Texto</p>

Acceso a datos del componente padre

En el index.html inyectamos el script del componente y ponemos la etiqueta del component en este caso parent-data. /index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
</head>
<body>
    <div id="app">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
    </div>
    <script>
        new Vue({
            el: '#app',
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

Aquí creamos un archivo llamado parent-data.js donde pondrémos una template accediendo al dato que queremos. Usamos $parent para acceder al elemento de arriba (padre). Si queremos subir niveles hacia arriba, usuariamos $parent las veces que quisieramos. Para subir por ejemplo tres niveles usuariamos $parent.$parent.$parent. El ejemplo del componente es el siguiente:

/components/parent-data.js

Vue.component('parent-data', {
    template: `
        <div>
            <h2>Acceso a los datos del CMP padre desde el CMP hijo</h2>
            {{ $parent.appName }}
        </div>
    `
});

Acceso a datos del componente hijo utilizando referencias

Creamos una referencia en nuestro componente, en este caso se llama <child-data> y la referencia se puede llamar como quieras, en el ejemplo le hemos llamado ref="childData". En el ciclo de vida de Vue, vamos a poner los datos del componente cuando esté mounted.

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
</head>
<body>
    <div id="app">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

Aquí tenemos el cmpName que deseamos pasar.

/components/child-data.js

Vue.component('child-data', {
    data() {
        return {
            cmpName: 'Child Data CMP',
        }
    },
    template: `
        <div>
            <h2>Acceso a los datos del CMP hijo desde el CMP padre</h2>
        </div>
    `
});

Ejecutar métodos del componente hijo utilizando referencias

Podemos llamar al método primero invocando a nuestro componente child-methods con la referencia childMethod. Vamos a poner un ejemplo en el mounted con un setTimeout llamándolo de la siguiente manera: this.$refs.childMethod.showCmpName(); Hacemos un ref, despues llamamos al método de la referencia y finalmente el método del hijo.

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
    <script src="components/child-methods.js"></script>
</head>
<body>
    <div id="app">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
        <child-methods ref="childMethod"></child-methods>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);

                setTimeout(() => {
                    this.$refs.childMethod.showCmpName();
                },3000);
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

/componentes/.js

Vue.component('child-methods', {
    data() {
        return {
            cmpName: 'Child Data CMP',
        }
    },
    template: `
        <div>
            <h2>Acceso a métodos del CMP hijo desde el CMP padre</h2>
        </div>
    `,
    methods: {
        showCmpName() {
            console.log(`Llamada al método showCmpName ${this.cmpName}`);
        }
    }
});

Introducción a los formularios

Ejemplo básico de login

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
    <script src="components/child-methods.js"></script>
    <script src="components/login-form.js"></script>

</head>
<body>
    <div id="app" style="margin-bottom: 100px;">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
        <child-methods ref="childMethod"></child-methods>
        <login-form></login-form>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);

                setTimeout(() => {
                    this.$refs.childMethod.showCmpName();
                },3000);
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

Creamos unos datos típicos como son email y password. Creamos el método login donde cambiamos el logged a true si la condición this.user.email === 'test@m.com' && this.user.password === 1234 es true.

La directiva v-show la utilizamos si queremos mostrar el contenido, en este caso sólo se mostrará si logged es true.

Para el formulario utilizamos @submit que por si sólo hace una redirección. Para evitar esta redirección pondremos @submit.prevent y en este caso le decimos que haga caso al método login, quedando de la siguiente manera: <form @submit.prevent="login">.

v-model nos permite hacer databinding, que hace que cambie los datos del componente.

/components/login-form.js

Vue.component('login-form', {
    data() {
        return {
            logged: false,
            user: {
                email: '',
                password: ''
            }
        }
    },
    methods: {
        login() {
            this.logged = this.user.email === 'test@m.com' && this.user.password === '1234';
        }
    },
    template: `
        <div>
            <h2>Formulario de login</h2>
            <p v-show="logged" style="background: green; color: #fff;">
                Has iniciado sesión con los datos: {{ user }}
            </p>
            <form @submit.prevent="login">
                <input autocomplete="off" type="email" v-model="user.email" name="email"/>
                <input type="password" v-model="user.password" name="password" />
                <input type="submit" value="Iniciar sesión" />
            </form>
        </div>
    `
});

Bucles con la directiva v-for

Nos cubre nuestras necesidades para iterar información. En index.html sólo habrá que invocar el script y el componente <loops>.

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
    <script src="components/child-methods.js"></script>
    <script src="components/login-form.js"></script>
    <script src="components/loops.js"></script>

</head>
<body>
    <div id="app" style="margin-bottom: 100px;">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
        <child-methods ref="childMethod"></child-methods>
        <login-form></login-form>
        <loops></loops>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);

                setTimeout(() => {
                    this.$refs.childMethod.showCmpName();
                },3000);
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

En el componente creamos un array de Frameworks, después en el template es donde utilizamos el v-for. En el <ul> usamos la condición v-if para no mostrar nada si en el array no hay nada guardado.

La directiva v-for utilizamos si queremos el index para mostrar el indice. El array se llama frameworks y por normativa solemos utilizar el elemento para mostrar en singular, así que v-for quedaría de la siguiente manera: v-for="(framework, index) in frameworks". Para que sea clave única y no se repita utilizamos :key, y le pasamos el elemento framework.id ya que no se repite.

Dentro del <li> dibujamos ya toda la información accediendo a través de framework.

/components/loops.js

Vue.component('loops', {
    data() {
        return {
            frameworks: [
                { id: 1, name: 'Vue2JS' },
                { id: 2, name: 'ReactJS' },
                { id: 3, name: 'Ember' },
                { id: 4, name: 'AdonisJS' },
                { id: 5, name: 'Angular' },
                { id: 6, name: 'Laravel' },
            ]
        }
    },
    template: `
        <div>
            <h2>Bucles con v-for</h2>
            <ul v-if="frameworks.length">
                <li v-for="(framework, index) in frameworks" :key="framework.id">
                    ({{ index }}) | {{ framework.name }}
                </li>
            </ul>
        </div>
    `
});

Condicionales con la directiva v-if

El v-if lo utilizamos para poder hacer condicionales y mostrar o no datos.

En nuestro index.html sólo vamos a tener que invocar al componente a través de su archivo js y después a través de su tag <conditionals>.

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
    <script src="components/child-methods.js"></script>
    <script src="components/login-form.js"></script>
    <script src="components/loops.js"></script>
    <script src="components/conditionals.js"></script>

</head>
<body>
    <div id="app" style="margin-bottom: 100px;">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
        <child-methods ref="childMethod"></child-methods>
        <login-form></login-form>
        <loops></loops>
        <conditionals></conditionals>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);

                setTimeout(() => {
                    this.$refs.childMethod.showCmpName();
                },3000);
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

Tenemos un dato que es agey en el input le decimos que su v-model de referencia es age. Ya después hacemos condiciones a traves de la directiva v-if. Cuando queremos añadir otro elemento usaremos v-else-if y cuando ya no tengamos que ver ninguna condición añadimos v-else.

/components/conditionals.js

Vue.component('conditionals', {
    data() {
        return {
            age: 10
        }
    },
    template: `
    <div>
        <h2>Condicionales con v-if</h2>
        <input v-model="age" />
        <p v-if="age < 18">Menor de edad</p>
        <p v-else-if="age >= 18 && age < 30">Mayor de edad y menor de 30</p>
        <p v-else-if="age >= 30 && age < 65">30 años o más y menor de 65</p>
        <p v-else>Estás jubilad@</p>
    </div>
    `
})

Slots, definiendo secciones para poder sobrescribir

Un slot nos permite definir unas layout pero podiendo sobrescribir el contenido.

Después de invocar el js de nuestro componente y llamarlo por <slot> meteremos nuestros elementos dentro.

Ejemplo de Layout

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
    <script src="components/child-methods.js"></script>
    <script src="components/login-form.js"></script>
    <script src="components/loops.js"></script>
    <script src="components/conditionals.js"></script>
    <script src="components/slots.js"></script>

</head>
<body>
    <div id="app" style="margin-bottom: 100px;">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
        <child-methods ref="childMethod"></child-methods>
        <login-form></login-form>
        <loops></loops>
        <conditionals></conditionals>
        <slots>
            <p>Contenido del slot para el cuerpo</p>
            <template slot="header">
                <h3>Header del layout con slot</h3>
            </template>

            <template slot="footer">
                <p>Footer del layout con Slots</p>
            </template>
        </slots>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);

                setTimeout(() => {
                    this.$refs.childMethod.showCmpName();
                },3000);
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

Hacemos el "template" del slot y a continuación analizamos como se comporta el código.

/components/slots.js

Vue.component('slots', {
    template: `
        <div>
            <h2>Slots, ejemplo de layout</h2>
            <div>
                <header>
                    <slot name="header"></slot>
                </header>
                <main>
                    <slot></slot>
                </main>
                <footer>
                    <slot name="footer"></slot>
                </footer>
            </div>
        </div>

    `
});
            <p>Contenido del slot para el cuerpo</p>
            <template slot="header">
                <h3>Header del layout con slot</h3>
            </template>

            <template slot="footer">
                <p>Footer del layout con Slots</p>
            </template>

Si nos fijamos en esta parte del código junto a esta:

                <header>
                    <slot name="header"></slot>
                </header>
                <main>
                    <slot></slot>
                </main>
                <footer>
                    <slot name="footer"></slot>
                </footer>

Vemos que si no definimos un <template slot="nameSlot"> realmente nos creará un main, aunque lo creemos en primera instancia. Un slot lo iremos construyendo según su plantilla y o sino lo llevará a último lugar.

Watchers

Haciendo cosas cuando algún dato cambie, peticiones HTTP GET con Fetch

En el index.html sólo añadimos la ruta del archivo javascript y invocamos al componente que le hemos llamado watchers. /index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
    <script src="components/child-methods.js"></script>
    <script src="components/login-form.js"></script>
    <script src="components/loops.js"></script>
    <script src="components/conditionals.js"></script>
    <script src="components/slots.js"></script>
    <script src="components/watchers.js"></script>

</head>
<body>
    <div id="app" style="margin-bottom: 100px;">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
        <child-methods ref="childMethod"></child-methods>
        <login-form></login-form>
        <loops></loops>
        <conditionals></conditionals>
        <slots>
            <p>Contenido del slot para el cuerpo</p>
            <template slot="header">
                <h3>Header del layout con slot</h3>
            </template>

            <template slot="footer">
                <p>Footer del layout con Slots</p>
            </template>
        </slots>
        <watchers></watchers>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);

                setTimeout(() => {
                    this.$refs.childMethod.showCmpName();
                },3000);
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

En watchers tenemos dos data de un usuario nuevo user y de un usuario anterior o viejo oldUser, los dos sin definir. Después a través de un async - await traemos información de un API que nos dá información de usuario aleatoria. Pasamos la información en un JSON y elegimos sólo la primera opción. Una vez hemos guardado esa información, componemos un usuario a través de su title, first y last.

/components/watchers.js

Vue.component('watchers', {
    data() {
        return {
            user: null,
            oldUser: null
        }
    },
    methods: {
        async randomUser() {
            try {
                const data = await fetch('https://randomuser.me/api/');
                const json = await data.json();
                const user = json.results[0];
                this.user = `${user.name.title} ${user.name.first} ${user.name.last}`;
            }catch(e) {
                //algo ha ido mal
                console.log(`Algo ha ido mal: ${e}`);
            }
        }
    },
    watch: {
        user(newVal, oldVal) {
            this.user = newVal;
            this.oldUser = oldVal;
        }
    },
    template: `
        <div>
            <h2>Watchers con VueJS2</h2>
            <button @click="randomUser">Obtener un usuario aleatorio</button>
            <p>Nuevo usuario: {{ user }}</p>
            <p>Anterior usuario: {{ oldUser }}</p>
        </div>
    `
});

Tenemos el método watch que es nuestro watcher. Estará viendo el estado de nuestros datos y recogerá lo que queramos. En el watcher nos va a pedir un newValue y un oldValue. Y así en el template, vamos a poder ir recogiendo estos datos y mostrándolos por la pantalla.

Computed Properties con getters y setters

En el documento index.html invocaremos el archivo javascript de computed-properties-getset.js e iniciamos el componente llamado <computed-properties-getset>.

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
    <script src="components/child-methods.js"></script>
    <script src="components/login-form.js"></script>
    <script src="components/loops.js"></script>
    <script src="components/conditionals.js"></script>
    <script src="components/slots.js"></script>
    <script src="components/watchers.js"></script>
    <script src="components/computed-properties-getset.js"></script>

</head>
<body>
    <div id="app" style="margin-bottom: 100px;">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
        <child-methods ref="childMethod"></child-methods>
        <login-form></login-form>
        <loops></loops>
        <conditionals></conditionals>
        <slots>
            <p>Contenido del slot para el cuerpo</p>
            <template slot="header">
                <h3>Header del layout con slot</h3>
            </template>

            <template slot="footer">
                <p>Footer del layout con Slots</p>
            </template>
        </slots>
        <watchers></watchers>
        <computed-properties-getset></computed-properties-getset>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);

                setTimeout(() => {
                    this.$refs.childMethod.showCmpName();
                },3000);
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

Creamos el componente con un dato 0 llamado amount. Dentro de computed creamos un amountFormatted donde tendremos dos funciones llamadas get() y set(). Dentro de ellas vamos a poder jugar para tener el valor o poder modificarlo después.

/components/computed-properties-getset.js

Vue.component('computed-properties-getset', {
    data() {
        return {
            amount: 0,
        }
    },
    computed: {
        amountFormatted: {
            get() {
                return `${this.amount} €`;
            },
            set(newValue) {
                this.amount = newValue;
            }
        }
    },
    template: `
        <div>
            <h2>Computed properties get && set</h2>
            <input v-model="amount" />
            <p>{{ amountFormatted }}</p>
        </div>
    `
});

Creamos un v-model con la referencia de amount y mostramos en pantalla el amountFormatted.

Carga de componentes dinámicos con el componente component

Para este ejemplo usaremos más archivos. Vamos a crear dentro de la carpeta components la carpeta dynamic-components creando los archivos cmp1.js, cmp2.js y cmp3.js. Dentro de cada archivo habrá lo siguiente, cambiando el nombre del cmp.

components/dynamic-components/cmp1.js

Vue.component('cmp1', {
    template: `
        <h4>Componente 1</h4>
    `
});

En el index.html cargamos primero los componentes dinámicos cmpX.js y después el cargador de componentes load-dynamic-components.js.

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
    <script src="components/child-methods.js"></script>
    <script src="components/login-form.js"></script>
    <script src="components/loops.js"></script>
    <script src="components/conditionals.js"></script>
    <script src="components/slots.js"></script>
    <script src="components/watchers.js"></script>
    <script src="components/computed-properties-getset.js"></script>
    <script src="components/dynamic-components/cmp1.js"></script>
    <script src="components/dynamic-components/cmp2.js"></script>
    <script src="components/dynamic-components/cmp3.js"></script>
    <script src="components/load-dynamic-components.js"></script>

</head>
<body>
    <div id="app" style="margin-bottom: 100px;">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
        <child-methods ref="childMethod"></child-methods>
        <login-form></login-form>
        <loops></loops>
        <conditionals></conditionals>
        <slots>
            <p>Contenido del slot para el cuerpo</p>
            <template slot="header">
                <h3>Header del layout con slot</h3>
            </template>

            <template slot="footer">
                <p>Footer del layout con Slots</p>
            </template>
        </slots>
        <watchers></watchers>
        <computed-properties-getset></computed-properties-getset>
        <load-dynamic-components></load-dynamic-components>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);

                setTimeout(() => {
                    this.$refs.childMethod.showCmpName();
                },3000);
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

En el componente creamos un array con los nombres de los componentes y decimos cual es el componente actual a mostrar con currentComponent. En methods creamos un método llamdo changeComponent() para modificar el componente actual.

En el template visualizamos todos los botones a través de una directiva v-for y en el evento @click cambiamos a que botón le hemos dado para actualizar su estado.

/components/load-dynamic-components.js

Vue.component('load-dynamic-components', {
    data() {
        return {
            components: ['cmp1', 'cmp2', 'cmp3'],
            currentComponent: 'cmp1',
        }
    },
    methods: {
        changeComponent(cmp) {
            this.currentComponent = cmp;
        }
    },
    template: `
        <div>
            <h2>Componentes dinámicos</h2>
            <button v-for="cmp in components" :key="cmp" @click="changeComponent(cmp)">
                Seleccionar {{ cmp }}
            </button>
            <component :is="currentComponent" />
        </div>
    `
});

Para mostrar el componente actual, utilizamos la etiqueta <component> con la directiva is (v-bind:is es lo mismo que :is) y mostramos que componente es el actual.

Mixins, añadiendo funcionalidad extra a nuestros componentes

Un mixin es una forma de heredar datos para poder reutilizar información.

En el index.html invocaremos como siempre el archivo javascript y el componente, en este caso lo hemos llamado <mixins>. No tenemos que hacer nada más, toda la lógica la lleva el javascript.

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
    <script src="components/child-methods.js"></script>
    <script src="components/login-form.js"></script>
    <script src="components/loops.js"></script>
    <script src="components/conditionals.js"></script>
    <script src="components/slots.js"></script>
    <script src="components/watchers.js"></script>
    <script src="components/computed-properties-getset.js"></script>
    <script src="components/dynamic-components/cmp1.js"></script>
    <script src="components/dynamic-components/cmp2.js"></script>
    <script src="components/dynamic-components/cmp3.js"></script>
    <script src="components/load-dynamic-components.js"></script>
    <script src="components/mixins.js"></script>

</head>
<body>
    <div id="app" style="margin-bottom: 100px;">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
        <child-methods ref="childMethod"></child-methods>
        <login-form></login-form>
        <loops></loops>
        <conditionals></conditionals>
        <slots>
            <p>Contenido del slot para el cuerpo</p>
            <template slot="header">
                <h3>Header del layout con slot</h3>
            </template>

            <template slot="footer">
                <p>Footer del layout con Slots</p>
            </template>
        </slots>
        <watchers></watchers>
        <computed-properties-getset></computed-properties-getset>
        <load-dynamic-components></load-dynamic-components>
        <mixins></mixins>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);

                setTimeout(() => {
                    this.$refs.childMethod.showCmpName();
                },3000);
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

Vamos a crear una variable con todo nuestro mixin.

/components/mixins.js

let myMixin = {
    mounted() {
        console.log("MIXIN init");
        console.log(this.mixinData);
        this.test();
    },
    data() {
        return {
            mixinData: `Mixin Data`
        }
    },
    methods: {
        test() {
            console.log("test from mixin");
        }
    }
};

Vue.component('mixins', {
    mixins: [myMixin],
    mounted() {
        console.log('Mounted from component with Mixin');
    },
    data() {
        return {
            mixinData: `Mixin Data desde el componente`
        }
    },
    template: `
        <div>
            <h2>Uso de Mixins</h2>
            <p>{{ mixinData }}</p>
        </div>
    `
});

A la hora de crear nuestro componente, deberemos llamar a mixins en plural en un array, y ahí llamar a nuesta variable con el mixin. Tenemos que tener cuidado ya que habrán cosas que se ejecutaran antes o después o se pueden reescribir.

Desarrollar nuestra primera directiva, dando el foco a inputs

Las directivas es mejor que se invoquen al principio. Lo único que vamos a hacer en este ejemplo es darle focus a un input. Para darle focus creamos una carpeta llamada directives y dentro de esa carpeta creamos un archivo llamado focus.js.

En el index.html le añadimos el archivo javascript de la directiva. /index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <!-- VUE DIRECTIVES -->
    <script src="directives/focus.js"></script>
    <!-- END VUE DIRECTIVES-->

    <!-- VUE COMPONENTS -->
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
    <script src="components/child-methods.js"></script>
    <script src="components/login-form.js"></script>
    <script src="components/loops.js"></script>
    <script src="components/conditionals.js"></script>
    <script src="components/slots.js"></script>
    <script src="components/watchers.js"></script>
    <script src="components/computed-properties-getset.js"></script>
    <script src="components/dynamic-components/cmp1.js"></script>
    <script src="components/dynamic-components/cmp2.js"></script>
    <script src="components/dynamic-components/cmp3.js"></script>
    <script src="components/load-dynamic-components.js"></script>
    <script src="components/mixins.js"></script>
    <!-- END VUE COMPONENTS-->

</head>
<body>
    <div id="app" style="margin-bottom: 100px;">
        <message></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
        <child-methods ref="childMethod"></child-methods>
        <login-form></login-form>
        <loops></loops>
        <conditionals></conditionals>
        <slots>
            <p>Contenido del slot para el cuerpo</p>
            <template slot="header">
                <h3>Header del layout con slot</h3>
            </template>

            <template slot="footer">
                <p>Footer del layout con Slots</p>
            </template>
        </slots>
        <watchers></watchers>
        <computed-properties-getset></computed-properties-getset>
        <load-dynamic-components></load-dynamic-components>
        <mixins></mixins>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);

                setTimeout(() => {
                    this.$refs.childMethod.showCmpName();
                },3000);
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

Creamos la directiva focus, y le damos focus al elemento el.

/directives/focus.js

Vue.directive('focus', {
    inserted(el) {
        el.focus();
    }
});

En el ejemplo vamos a darle focus al primer input que habíamos creado (vmodel.js). Para asignarle la directiva, se la daremos a través de v-nombredirectiva en este caso v-focus. El archivo modificado de vmodel.js quedaría de la siguiente forma.

/components/vmodel.js

Vue.component('vmodel', {
    data() {
        return {
            framework: 'Vuejs2',
        }
    },
    template: `
        <div>
            <h2>Trabajando con vmodel</h2>
            <input v-model="framework" v-focus/>
            <p>El framework usado es {{ framework }}</p>
        </div>
    `
})

Directiva para aplicar estilos a componentes pasando parámetros

Binding son los datos que vamos a pasar a la directiva para poder acceder desde el archivo.

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <!-- VUE DIRECTIVES -->
    <script src="directives/focus.js"></script>
    <script src="directives/change-styles.js"></script>
    <!-- END VUE DIRECTIVES-->

    <!-- VUE COMPONENTS -->
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
    <script src="components/child-methods.js"></script>
    <script src="components/login-form.js"></script>
    <script src="components/loops.js"></script>
    <script src="components/conditionals.js"></script>
    <script src="components/slots.js"></script>
    <script src="components/watchers.js"></script>
    <script src="components/computed-properties-getset.js"></script>
    <script src="components/dynamic-components/cmp1.js"></script>
    <script src="components/dynamic-components/cmp2.js"></script>
    <script src="components/dynamic-components/cmp3.js"></script>
    <script src="components/load-dynamic-components.js"></script>
    <script src="components/mixins.js"></script>
    <!-- END VUE COMPONENTS-->

</head>
<body>
    <div id="app" style="margin-bottom: 100px;">
        <message v-change-styles="{backgroundColor: 'red', color: 'white'}"></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
        <child-methods ref="childMethod"></child-methods>
        <login-form></login-form>
        <loops></loops>
        <conditionals></conditionals>
        <slots>
            <p>Contenido del slot para el cuerpo</p>
            <template slot="header">
                <h3>Header del layout con slot</h3>
            </template>

            <template slot="footer">
                <p>Footer del layout con Slots</p>
            </template>
        </slots>
        <watchers></watchers>
        <computed-properties-getset></computed-properties-getset>
        <load-dynamic-components></load-dynamic-components>
        <mixins></mixins>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);

                setTimeout(() => {
                    this.$refs.childMethod.showCmpName();
                },3000);
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

Creando la directiva abajo, usando binding podemos cambiar los valores de este. En estamos diciendo de introducir un backgroundColor y un color. Se lo asignamos al componente que queramos con un v-change-styles y se le pasamos los valores de esta manera (ejemplo con el componente message): <message v-change-styles="{backgroundColor: 'red', color: 'white'}"></message>

/directives/change-styles.js

Vue.directive('change-styles', (el, binding) => {
    el.style.background = binding.value.backgroundColor;
    el.style.color = binding.value.color;
});

Desarrollar un filtro con paso de parámetros para establecer la Currency

Para este ejemplo editaremos el archivo computed-properties-getset.js donde añadiremos el nombre del filtro y le pasaremos un valor. En el index.html añadimos el filtro en la carpeta filters con el archivo currency-filter.js.

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <!-- VUE DIRECTIVES -->
    <script src="directives/focus.js"></script>
    <script src="directives/change-styles.js"></script>
    <!-- END VUE DIRECTIVES-->

    <!-- VUE FILTERS -->
    <script src="filters/currency-filter.js"></script>
    <!-- END VUE FILTERS -->

    <!-- VUE COMPONENTS -->
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
    <script src="components/child-methods.js"></script>
    <script src="components/login-form.js"></script>
    <script src="components/loops.js"></script>
    <script src="components/conditionals.js"></script>
    <script src="components/slots.js"></script>
    <script src="components/watchers.js"></script>
    <script src="components/computed-properties-getset.js"></script>
    <script src="components/dynamic-components/cmp1.js"></script>
    <script src="components/dynamic-components/cmp2.js"></script>
    <script src="components/dynamic-components/cmp3.js"></script>
    <script src="components/load-dynamic-components.js"></script>
    <script src="components/mixins.js"></script>
    <!-- END VUE COMPONENTS-->

</head>
<body>
    <div id="app" style="margin-bottom: 100px;">
        <message v-change-styles="{backgroundColor: 'red', color: 'white'}"></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
        <child-methods ref="childMethod"></child-methods>
        <login-form></login-form>
        <loops></loops>
        <conditionals></conditionals>
        <slots>
            <p>Contenido del slot para el cuerpo</p>
            <template slot="header">
                <h3>Header del layout con slot</h3>
            </template>

            <template slot="footer">
                <p>Footer del layout con Slots</p>
            </template>
        </slots>
        <watchers></watchers>
        <computed-properties-getset></computed-properties-getset>
        <load-dynamic-components></load-dynamic-components>
        <mixins></mixins>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);

                setTimeout(() => {
                    this.$refs.childMethod.showCmpName();
                },3000);
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

Creamos el filtro de la siguiente manera, recogiendo el valor y después un currency que será el tipo de moneda. /filters/currency-filter.js

Vue.filter('currency_filter', (value, currency) => {
    return `${value} ${currency}`;
});

Aquí con un pipeline utilizaremos el filtro.

/components/computed-properties-getset.js

Vue.component('computed-properties-getset', {
    data() {
        return {
            amount: 0,
        }
    },
    computed: {
        amountFormatted: {
            get() {
                return `${this.amount}`;
            },
            set(newValue) {
                this.amount = newValue;
            }
        }
    },
    template: `
        <div>
            <h2>Computed properties get && set</h2>
            <input v-model="amount" />
            <p>{{ amountFormatted | currency_filter('€') }}</p>
        </div>
    `
});

Desarrollar plugin con argumentos para mostrar el perfil de un usuario

Un plugin sirve para darle una funcionalidad adicional a VueJS. Para realizar un plugin tenemos que crear un archivo de la siguiente manera: /plugins/aboutMe.js

const AboutMe = {
    install: (Vue, options) => {
        const { job } = options;
        Vue.prototype.$me = (name, age) => {
            return `Mi nombre es ${name} tengo ${age} años y trabajo de ${job}`;
        }
        //options.job es lo mismo que lo de arriba
    }
};

Vue.use(AboutMe, {
    job: 'programador e instructor',
})

Creamos una const con los datos y el método install. Le pasamos el primer parámetro que siempre tiene que ser Vue y después le añadimos unas options. Destructuramos el objeto con const { job } = options y le añadimos un prototype con el nombre $loquesea para poder llamarlo. En este caso vamos a pedir name y age.

/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <!-- VUE DIRECTIVES -->
    <script src="directives/focus.js"></script>
    <script src="directives/change-styles.js"></script>
    <!-- END VUE DIRECTIVES-->

    <!-- VUE FILTERS -->
    <script src="filters/currency-filter.js"></script>
    <!-- END VUE FILTERS -->

    <!-- VUE COMPONENTS -->
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
    <script src="components/child-methods.js"></script>
    <script src="components/login-form.js"></script>
    <script src="components/loops.js"></script>
    <script src="components/conditionals.js"></script>
    <script src="components/slots.js"></script>
    <script src="components/watchers.js"></script>
    <script src="components/computed-properties-getset.js"></script>
    <script src="components/dynamic-components/cmp1.js"></script>
    <script src="components/dynamic-components/cmp2.js"></script>
    <script src="components/dynamic-components/cmp3.js"></script>
    <script src="components/load-dynamic-components.js"></script>
    <script src="components/mixins.js"></script>
    <!-- END VUE COMPONENTS-->
    
    <!-- VUE PLUGIN -->
    <script src="plugins/aboutme.js"></script>
    <!-- END VUE PLUGIN -->

</head>
<body>
    <div id="app" style="margin-bottom: 100px;">
        <message v-change-styles="{backgroundColor: 'red', color: 'white'}"></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
        <child-methods ref="childMethod"></child-methods>
        <login-form></login-form>
        <loops></loops>
        <conditionals></conditionals>
        <slots>
            <p>Contenido del slot para el cuerpo</p>
            <template slot="header">
                <h3>Header del layout con slot</h3>
            </template>

            <template slot="footer">
                <p>Footer del layout con Slots</p>
            </template>
        </slots>
        <watchers></watchers>
        <computed-properties-getset></computed-properties-getset>
        <load-dynamic-components></load-dynamic-components>
        <mixins></mixins>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);

                setTimeout(() => {
                    this.$refs.childMethod.showCmpName();
                },3000);

                console.log(this.$me('José Luis', '33'));
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

Props

Paso de datos a componentes al utilizarlo, tipos y validación

Una vez más añadimos el script de javascript y ponemos el componente con varios datos que pasarle al props. En este caso sería esto: <props name="Jose" surname="García" :age="37"></props>. /index.html

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vuejs2</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <!-- VUE DIRECTIVES -->
    <script src="directives/focus.js"></script>
    <script src="directives/change-styles.js"></script>
    <!-- END VUE DIRECTIVES-->

    <!-- VUE FILTERS -->
    <script src="filters/currency-filter.js"></script>
    <!-- END VUE FILTERS -->

    <!-- VUE COMPONENTS -->
    <script src="components/message.js"></script>
    <script src="components/computed-properties.js"></script>
    <script src="components/methods.js"></script>
    <script src="components/vmodel.js"></script>
    <script src="components/vmodel-checkboxes.js"></script>
    <script src="components/emit.js"></script>
    <script src="components/parent-data.js"></script>
    <script src="components/child-data.js"></script>
    <script src="components/child-methods.js"></script>
    <script src="components/login-form.js"></script>
    <script src="components/loops.js"></script>
    <script src="components/conditionals.js"></script>
    <script src="components/slots.js"></script>
    <script src="components/watchers.js"></script>
    <script src="components/computed-properties-getset.js"></script>
    <script src="components/dynamic-components/cmp1.js"></script>
    <script src="components/dynamic-components/cmp2.js"></script>
    <script src="components/dynamic-components/cmp3.js"></script>
    <script src="components/load-dynamic-components.js"></script>
    <script src="components/mixins.js"></script>
    <script src="components/props.js"></script>
    <!-- END VUE COMPONENTS-->
    
    <!-- VUE PLUGIN -->
    <script src="plugins/aboutme.js"></script>
    <!-- END VUE PLUGIN -->

</head>
<body>
    <div id="app" style="margin-bottom: 100px;">
        <message v-change-styles="{backgroundColor: 'red', color: 'white'}"></message>
        <computed-properties></computed-properties>
        <methods></methods>
        <vmodel></vmodel>
        <vmodel-checkboxes></vmodel-checkboxes>
        <emit @show_car_brand="showCarBrandFromEmitCMP"></emit>
        <parent-data></parent-data>
        <!-- PODEMOS DARLE EL NOMBRE A LA REFERENCIA QUE QUERAMOS-->
        <child-data ref="childData"></child-data>
        <child-methods ref="childMethod"></child-methods>
        <login-form></login-form>
        <loops></loops>
        <conditionals></conditionals>
        <slots>
            <p>Contenido del slot para el cuerpo</p>
            <template slot="header">
                <h3>Header del layout con slot</h3>
            </template>

            <template slot="footer">
                <p>Footer del layout con Slots</p>
            </template>
        </slots>
        <watchers></watchers>
        <computed-properties-getset></computed-properties-getset>
        <load-dynamic-components></load-dynamic-components>
        <mixins></mixins>
        <props name="Jose" surname="García" :age="37"></props>
    </div>
    <script>
        new Vue({
            el: '#app',
            mounted() {
                const cmpName = this.$refs.childData.cmpName;
                console.log(cmpName);

                setTimeout(() => {
                    this.$refs.childMethod.showCmpName();
                },3000);

                console.log(this.$me('José Luis', '33'));
            },
            data() {
                return {
                    appName: 'Iniciando con Vuejs2'
                }
            },
            methods: {
                showCarBrandFromEmitCMP(carBrand) {
                    alert(carBrand);
                }
            }
        });
    </script>
</body>
</html>

En el componente, inicializamos una instancia de Vue con el nombre props, y definimos los valores en el método props que vamos a pasarle: name y age. Además vamos realizar una validación de edad.

/components/.js

Vue.component('props', {
    props: {
        name: {
            type: String,
            required: true    
        },
        surname: {
            type: String,
            required: true
        },
        age: {
            type: Number,
            required: true,
            validator: value => {
                if(value < 18) {
                    console.warn('No eres mayor de edad...');
                    return false;
                } else {
                    return true;
                }
            }
        }
    },
    template: `
        <div>
            <h2>Props con Vuejs2</h2>
            <p>{{ name }} {{ surname }}, Edad {{ age }}</p>
        </div>
    `
});

Props Vs Data y reactividad

Las Props en Vuejs nos permiten pasar datos a un componente al momento de utilizarlo:

<super-componente :nombre="variableNombreSuperComponente" />

En este caso al componente super-componente le estamos pasando un dato de entrada llamado nombre, para utilizarlo en dicho componente haríamos lo siguiente:

<template>
    <div>
        {{ nombre }}
    </div>
</template>
 
<script>
export default {
   props: ['nombre']
}
</script>

El problema está en que si queremos que este dato sea reactivo utilizando v-model tendríamos un error:

<template>
    <div>
        <input v-model="nombre" />
    </div>
</template>
 
<script>
export default {
   props: ['nombre']
}
</script>

[Vue warn]: Avoid mutating a prop directly

Esto significa que no podemos modificar una Prop de forma directa, para solucionar esto realmente existen muchos caminos, pero uno muy común que sirve en la mayoría de los casos es utilizar en lugar de un valor, un objeto:

<super-componente :objetoConNombre="objetoNombreSuperComponente" />
<template>
    <div>
        <input v-model="objetoConNombre.nombre" />
    </div>
</template>
 
<script>
export default {
   props: ['objetoConNombre']
}
</script>
@Gonzalo2310
Copy link

Gonzalo2310 commented Jun 20, 2020

Impresionante. Gracias.

Estoy desarrollando una serie de tutoriales de Vuejs para programadores de jQuery usando el cdn y todo lo de los componentes usados de esta manera me ha quedado muy claro con tu material.

Mil gracias.

@mrcodedev
Copy link
Author

Gracias a tí. Si lo necesitas para algo, sin problema 👍👍👍

@Gonzalo2310
Copy link

Solo hablaré de lo referente a mi proyecto de forma detallada pero para saber más los enviaré a este link. Aquí esta muy bien explicado todo.

@kevinm9
Copy link

kevinm9 commented May 27, 2023

gracias jose

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment