Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Coding Patterns: Bridging Vue 2 and Vue 3

Tech 2

1. Project Creation

Vue 2 (using Vue CLI):

vue create my-app
cd my-app
npm run serve

Vue 3 (using create‑vue):

npm create vue@latest
cd my-app
npm run dev

During initialisation you are prompted to add TypeScript, Router, Pinia, testing tools, and linter formatters.


2. Component Template

Vue 2 – Options API

<template>
  <div></div>
</template>

<script>
export default {
  props: {},
  data() {
    return {
      // local state
    };
  },
  created() {},
  methods: {},
  mounted() {},
  watch: {},
  computed: {},
  components: {}
};
</script>

<style scoped></style>

Vue 3 – Composition API (<script setup>)

<template>
  <div>{{ greeting }}</div>
</template>

<script setup>
import { ref, reactive, toRefs, toRef, computed, watch, watchEffect } from 'vue';

// reactive primitive
const greeting = ref('Hello');

// reactive object
const user = reactive({ name: 'Alice', age: 30 });

// destructure reactive object keeping reactivity
const { name } = toRefs(user);
const age = toRef(user, 'age');

// computed (read‑only)
const upperGreeting = computed(() => greeting.value.toUpperCase());

// writable computed
const fullName = computed({
  get: () => user.name + ' (read)',
  set: (val) => { user.name = val; }
});

// watcher
watch(user, (newVal, oldVal) => {
  console.log('user changed', newVal, oldVal);
}, { deep: true });

// watchEffect – auto‑detect dependencies
watchEffect(() => {
  console.log('current user name:', user.name);
});
</script>

<style scoped></style>

3. Lifecycle Hooks

Vue 2 (Options API) Vue 3 (Composition API)
beforeCreate not needed (setup replaces it)
created not needed (setup)
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeDestroy onBeforeUnmount
destroyed onUnmounted
errorCaptured onErrorCaptured

Vue 2 example:

export default {
  mounted() { console.log('mounted'); }
}

Vue 3 example:

import { onMounted } from 'vue';
onMounted(() => console.log('mounted'));

4. Component Communication

4.1 Parent → Child (props)

Vue 2

<!-- parent -->
<Child :items="list" :callback="onCallback" />

<!-- child -->
<script>
export default {
  props: ['items', 'callback']
}
</script>

Vue 3

<!-- parent -->
<Child :items="list" :callback="onCallback" />

<!-- child -->
<script setup>
defineProps(['items', 'callback'])
</script>

4.2 Child → Parent (custom events)

Vue 2

<!-- child -->
<button @click="$emit('update', payload)">Update</button>

Vue 3

<!-- child -->
<script setup>
const emit = defineEmits(['update']);
emit('update', payload);
</script>

4.3 Event Bus

Vue 2 – global bus on prototype

Vue.prototype.$bus = new Vue();
// emit
this.$bus.$emit('my-event', data);
// listen
this.$bus.$on('my-event', handler);

Vue 3 – external library mitt

npm install mitt
// emitter.ts
import mitt from 'mitt';
export const emitter = mitt();

// usage
emitter.emit('my-event', data);
emitter.on('my-event', handler);

4.4 Two‑way binding (v‑model)

Vue 2 – single v-model bound to value and input

<!-- parent -->
<Child v-model="keyword" />

<!-- child -->
<input :value="value" @input="$emit('input', $event.target.value)">

Vue 3 – multiple v-model bindings possible, default prop modelValue

<!-- parent -->
<Child v-model:title="pageTitle" v-model:content="body" />

<!-- child -->
<script setup>
const props = defineProps(['modelValue', 'title', 'content'])
const emit = defineEmits(['update:modelValue', 'update:title', 'update:content'])
</script>

.sync modifier from Vue 2 is removed in Vue 3; use v-model: instead.

4.5 Provide / Inject

Vue 2

// ancestor
provide() { return { api: this.api } }
// descendant
inject: ['api']

Vue 3

// ancestor
import { provide } from 'vue';
provide('api', api);

// descendant
import { inject } from 'vue';
const api = inject('api');

4.6 State Management

Vue 2 – Vuex

  • Store: new Vuex.Store({ state, mutations, actions, getters })
  • Covered by mapState, mapActions helpers.

Vue 3 – Pinia

  • Define: defineStore('counter', { state, getters, actions })
  • Access: const store = useCounterStore(); store.increment()
  • Reactivity preserving: storeToRefs(store) to destructuring.

5. Routing

Installation

  • Vue 2: npm install vue-router@3
  • Vue 3: npm install vue-router@4

Router setup

Aspect Vue 2 Vue 3
Instance new VueRouter({ routes }) createRouter({ history: createWebHashHistory(), routes })
Mode mode: 'history' inside options alen history: createWebHistory()
Navigation this.$router.push('/about') import { useRouter } from 'vue-router'; router.push('/about')
Dynamic segments { path: '/user/:id' } – same in both same
Nested routes children: [...] – same same
Route props props: true (params) or props: route => route.query same
Redirect redirect: '/home' – same same

Link and navigation guards are95% identical.


6. Composables (Replace Mixins)

In Vue 2 reusable logic is often shared via mixins. Vue 3 encourages extracting pure functions (composables).

encoding example

// composables/useMouse.ts
import { ref, onUnmounted } from 'vue';

export function useMouse() {
  const x = ref(0);
  const y = ref(0);
  const update = (e: MouseEvent) => {
    x.value = e.pageX;
    y.value = e.pageY;
  };
  window.addEventListener('mousemove', update);
  onUnmounted(() => window.removeEventListener('mousemove', update));
  return { x, y };
}

console.log


7. UI Frameworks

  • Element – Vue 2: element‑ui | Vue 3: element‑plus
  • Vant – Vue 2: vant@2 | Vue 3: vant@3 (or vant@next)
  • Vuetify – Vue 2: vuetify@2 | Vue 3: vuetify@3
  • Naive UI – designed for Vue 3 only
  • View UI (iview) – Vue 2: view‑ui | Vue 3: view‑ui‑plus

Always check the library’s documentation for the correct version to your Vue release.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.