El primer caso va a ser simplemente un hola mundo para pasar un componente sencillo de Vue 2 a Vue 3 utilizando la nueva api de composición que Vue 3 nos ofrece.
hola-mundo-vue-2.js
Vue.component('hola-mundo', {
data () {
return {
message: 'Hola Mundo'
}
},
template: `
<div>
<h2>Componente Hola Mundo en Vue 2</h2>
<p>{{ message }}</p>
</div>
`
});hola-mundo-vue-3.js
app.component('hola-mundo', {
setup() {
const message = ref("Hola Mundo")
return { message }
},
template: `
<h2>Componente Hola Mundo en Vue 3</h2>
<p>{{ message }}</p>
`
});
Computed Properties
Ahora vamos a ver cómo pasar un componente en Vue 2 que utilice computed properties a Vue 3 con la api de composición.
computed-properties-vue-2.js
Vue.component('computed-properties', {
data () {
return {
name: 'Israel',
surname: 'Parra'
}
},
computed: {
fullName () {
return `${this.name} ${this.surname}`;
}
},
template: `
<div>
<h2>Computed properties</h2>
<p>{{ fullName }}</p>
</div>
`
});computed-properties-vue-3.js
app.component('computed-properties', {
setup() {
const name = ref("Israel");
const surname = ref("Parra");
const fullName = computed(() => {
return `${name.value} ${surname.value}`;
});
return { name, surname, fullName };
},
template: `
<h2>Computed properties en Vue 3</h2>
<p>Nombre: {{ name }} | Apellido: {{ surname }}</p>
<p>Nombre completo: {{ fullName }}</p>
`
});Methods
Ahora vamos a ver cómo pasar un componente en Vue 2 que utillice methods a Vue 3 con la api de composición.
methods-vue-2.js
Vue.component('methods', {
data () {
return {
name: 'Israel',
surname: 'Parra'
}
},
computed: {
fullName () {
return `${this.name} ${this.surname}`;
}
},
methods: {
helloUser () {
alert(this.fullName);
}
},
template: `
<div>
<h2>Ejecutar métodos con Vue 2</h2>
<p @click="helloUser">Pulsa aquí para ejecutar el método helloUser</p>
</div>
`
});methods-vue-3.js
app.component('methods', {
setup() {
const name = ref("Israel");
const surname = ref("Parra");
const fullName = computed(() => {
return `${name.value} ${surname.value}`;
});
const helloUser = () => {
alert(`Hola ${fullName.value}`);
}
return { helloUser };
},
template: `
<h2>Ejecutar métodos con Vue 3</h2>
<p @click="helloUser">Pulsa aquí para ejecutar el método helloUser</p>
`
});V-MODEL básico
La directiva v-model ha sido mejorada considerablemente, en esta ocasión simplemente vamos a ver un sencillo ejemplo de uso haciendo uso del método setup de Vue 3.
v-model-vue-2.js
Vue.component('vmodel', {
data () {
return {
framework: 'Vue 2'
}
},
template: `
<div>
<h2>Trabajando con v-model en Vue 2</h2>
<input v-model="framework" />
<p>El framework escogido es: {{ framework }}</p>
</div>
`
})v-model-vue-3.js
app.component('vmodel', {
setup() {
const framework = ref("Vue 3");
return { framework };
},
template: `
<h2>Trabajando con v-model en Vue 3</h2>
<input v-model="framework" />
<p>El framework escogido es: {{ framework }}</p>
`
});V-MODEL con Arrays
El trabajo con v-model utilizando Arrays es igual al v-model con un String, en este caso la diferencia es modificar el tipo de dato por un Array de la siguiente forma.
v-model-arrays-vue-2.js
Vue.component('vmodel-arrays', {
data () {
return {
frameworks: []
}
},
template: `
<div>
<h2>vmodel con arrays en Vue 2</h2>
<input type="checkbox" id="vue" value="Vue" v-model="frameworks" />
<label for="vuejs2">Vue</label>
<input type="checkbox" id="laravel" value="Laravel" v-model="frameworks" />
<label for="reactjs">Laravel</label>
<input type="checkbox" id="django" value="Django" v-model="frameworks" />
<label for="django">Django</label>
<p>Frameworks seleccionados: {{ frameworks }}</p>
</div>
`
})v-model-arrays-vue-3.js
app.component("vmodel-arrays", {
setup() {
const frameworks = ref([]);
return { frameworks };
},
template: `
<h2>v-model con arrays en Vue 3</h2>
<input type="checkbox" id="vue" value="Vue" v-model="frameworks" />
<label for="vuejs2">Vue</label>
<input type="checkbox" id="laravel" value="Laravel" v-model="frameworks" />
<label for="reactjs">Laravel</label>
<input type="checkbox" id="django" value="Django" v-model="frameworks" />
<label for="django">Django</label>
<p>Frameworks seleccionados: {{ frameworks }}</p>
`
})Comunicación entre componentes padre/hijo
La comunicación parent/child entre componentes en Vue 3 si que ha sufrido más cambios, veamos un ejemplo en Vue 2 y Vue 3.
parent-child-vue-2.js
Vue.component('child', {
data () {
return {
carBrand: 'Hyundai'
}
},
methods: {
emitShowCarBrand() {
this.$emit("showCarBrand", this.carBrand)
}
},
template: `
<div>
<h2>Emitir eventos con Vue 2</h2>
<p>{{ $parent.parentData }}</p>
<p @click="$emit('showCarBrand', carBrand)">
Emitir un evento al componente Parent desde la template
</p>
<p @click="emitShowCarBrand">
Emitir un evento al componente Parent desde el setup
</p>
</div>
`
});
Vue.component('parent', {
data() {
return {
parentData: "Datos del componente padre",
}
},
methods: {
eventReceived(cardBrand) {
console.log(cardBrand);
}
},
template: `
<div>
<h2>Comunicación a través de eventos padre hijo en Vue 3</h2>
<child @showCarBrand="eventReceived"></child>
</div>
`
})parent-child-vue-3.js
app.component("child", {
emits: ['showCarBrand'],
setup(props, { emit }) {
const carBrand = ref("Hyundai");
const emitShowCarBrand = () => {
emit("showCarBrand", carBrand.value)
}
return { carBrand, emitShowCarBrand };
},
template: `
<h2>Emitir eventos con Vue 3</h2>
<u>{{ $parent.parentData }}</u>
<p @click="$emit('showCarBrand', carBrand)">
Emitir un evento al componente Parent desde la template
</p>
<p @click="emitShowCarBrand">
Emitir un evento al componente Parent desde el setup
</p>
`
})
app.component('parent', {
setup() {
const parentData = ref("Datos del componente padre");
const eventReceived = (cardBrand) => {
console.log(cardBrand);
}
return { parentData, eventReceived };
},
template: `
<h2>Comunicación a través de eventos padre hijo en Vue 3</h2>
<child @showCarBrand="eventReceived"></child>
`
})Refs en templates
Un tema que también ha sufrido algunos cambios es la forma de utilizar refs en las templates, ya que si bien en Vue 2 únicamente teníamos refs en las templates y accedíamos desde los componentes con this.$refs, ahora también podemos definir datos haciendo uso de ref con los tipos primitivos más comunes.
refs-vue-2.js
Vue.component('refs', {
mounted() {
console.log(this.$refs.childRef.carBrand); // Hyundai
},
data() {
return {
parentData: "Datos del componente padre",
}
},
template: `
<div>
<h2>Refs en Vue 2</h2>
<child ref="childRef"></child>
</div>
`
})refs-vue-3.js
app.component('refs', {
setup() {
const childRef = ref(null);
const parentData = ref("Datos del componente padre");
onMounted(() => {
console.log(childRef.value.carBrand); // Hyundai
})
return { childRef, parentData };
},
template: `
<h2>Refs en Vue 3</h2>
<child ref="childRef"></child>
`
})Obtener datos externos, ejemplo con Fetch
El acceso a datos remotos de forma asíncrona también ha cambiado y ahora debemos modificar nuestra forma de trabajar.
fetch-vue-2.js
Vue.component('fetch', {
data () {
return {
users: []
}
},
async mounted() {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
this.users = await response.json()
}
},
template: `
<div>
<h2>Fetch con Vue 2</h2>
<ul v-if="users.length">
<li v-for="user in users" :key="user.id">
{{ user.name }} - {{ user.email }}
</li>
</ul>
<p v-else>No hay usuarios disponibles</p>
</div>
`
})fetch-vue-3.js
app.component("fetch", {
setup () {
const users = ref([]);
onMounted(async () => {
const response = await fetch("https://jsonplaceholder.typicode.com/users");
users.value = await response.json()
});
return { users };
},
template: `
<h2>Fetch en Vue 3</h2>
<ul v-if="users.length">
<li v-for="user in users" :key="user.id">
{{ user.name }} - {{ user.email }}
</li>
</ul>
<p v-else>No hay usuarios disponibles</p>
`
});Desarrollo de plugins
En Vue 2 la base para desarrollar un plugin es crear un objeto con el método install y utilizarlo con Vue.use. Esto en Vue 3 es posible, pero al utilizar el método setup perdemos el contexto del componente y debemos hacerlo de otra forma.
plugin-vue-2.js
const Profile = {
install: (Vue, options) => {
const { skills } = options;
Vue.prototype.$profile = (name, age) => {
return `Mi nombre es ${name}, tengo ${age} años y trabajo de ${skills}`;
}
}
};
Vue.use(Profile, {
skills: 'programador e instructor en Cursosdesarrolloweb'
});plugin-vue-3.js
const createProfile = config => ({
name: config.name,
age: config.age,
skills: config.skills,
$skill(key) {
return this.skills[key];
}
});
const profileSymbol = Symbol();
function provideProfile(profileConfig) {
const profile = createProfile(profileConfig);
provide(profileSymbol, profile);
}
function useProfile() {
const profile = inject(profileSymbol);
if (!profile) throw new Error("Debes ejecutar provideProfile para utilizar este plugin");
return profile;
}Hasta aquí bien, pero ahora debemos saber cómo utilizar nuestro plugin en cada versión, veamos.
use-plugin-vue-2.js
Vue.component("use-plugin", {
mounted() {
console.log(this.$profile('Israel', 39));
// Mi nombre es Israel, tengo 39 años y trabajo de programador e instructor en Cursosdesarrolloweb"
}
});use-plugin-vue-3.js
app.component("use-plugin", {
setup() {
provideProfile({
name: "Israel",
age: 39,
skills: {
programmer: "Programador PHP, JavaScript y Python",
instructor: "Instructor de cursos en línea de desarrollo web y móvil en Cursosdesarrolloweb"
}
})
const profile = useProfile();
return { profile };
},
template: `
<h2>Crear plugins en Vue 3</h2>
<p>
Nombre: {{ profile.name }}<br />
Edad: {{ profile.age }}<br />
Skills: {{ profile.$skill('programmer') }}
</p>
`
});Filtros, desaparecen en Vue 3
Los filtros ya no existen en Vue 3, ahora simplemente podemos utilizar computed properties para formatear los datos a nuestras necesidades.
filters-vue-2.js
Vue.filter('currencyFilter', (value, currency) => {
return `${value}${currency}`
});
Vue.component('filters', {
data () {
return {
totalAmount: 9.99
}
},
template: `
<div>
<h2>Filtros en Vue 2</h2>
<input v-model="totalAmount" />
<p>Cantidad total: {{ totalAmount | currencyFilter('€') }}</p>
</div>
`
});filters-vue-3.js
app.component("filters", {
setup() {
const totalAmount = ref(9.99);
const totalAmountFormatted = computed(() => {
return `${totalAmount.value}€`;
});
return { totalAmountFormatted };
},
template: `
<h2>Reemplazo de filtros en Vue 3</h2>
<input v-model="totalAmount" />
<p>Cantidad total: {{ totalAmountFormatted }}</p>
`
})