As a PHP developer you have probably had some contact with jQuery and maybe a bit of plain JS. Vue.js is the next step – a reactive framework that increasingly appears in e-commerce projects as a frontend layer for headless Magento or as a replacement for the older knockout.js. I show the basics from the perspective of someone who thinks in PHP day to day.
Why Vue rather than React or Angular?
React requires thinking in JSX and has a steeper learning curve. Angular is a full framework with an elaborate architecture – overkill for small components. Vue sits in the middle: simple template syntax close to HTML, built-in reactivity without ceremony, good documentation. For a PHP developer who is not a frontend developer by choice, Vue is the gentlest entry into the world of components.
Basic Vue 3 component structure – Options API
// Vue 3 component - Options API (simpler for PHP newcomers)
const ProductCard = {
// Component data - equivalent to PHP class properties
data() {
return {
quantity: 1,
addedToCart: false,
};
},
// Properties passed from outside - equivalent to method parameters
props: {
product: { type: Object, required: true },
maxQuantity: { type: Number, default: 99 },
},
// Computed properties - equivalent to PHP getters
computed: {
totalPrice() {
return (this.product.price * this.quantity).toFixed(2);
},
canAddMore() {
return this.quantity < this.maxQuantity;
},
},
// Methods - equivalent to PHP class methods
methods: {
addToCart() {
if (!this.canAddMore) return;
this.$emit('add-to-cart', { productId: this.product.id, quantity: this.quantity });
this.addedToCart = true;
},
increment() { if (this.quantity < this.maxQuantity) this.quantity++; },
decrement() { if (this.quantity > 1) this.quantity--; },
},
template: `
<div class="product-card">
<h3>{{ product.name }}</h3>
<p>{{ totalPrice }} PLN</p>
<div>
<button @click="decrement" :disabled="quantity <= 1">-</button>
<span>{{ quantity }}</span>
<button @click="increment" :disabled="!canAddMore">+</button>
</div>
<button @click="addToCart" :class="{ 'btn-success': addedToCart }">
{{ addedToCart ? 'Added!' : 'Add to cart' }}
</button>
</div>
`,
};
Vue directives - equivalents from PHP
| Vue directive | What it does | PHP/Twig analogy |
|---|---|---|
{{ variable }} |
Outputs a value | <?= $var ?> |
v-if="condition" |
Conditional rendering | {% if condition %} |
v-for="item in items" |
Loop over array | {% for item in items %} |
v-model="variable" |
Two-way input binding | No direct equivalent |
@click="method" |
Handle click event | No equivalent (this is JS) |
:class="object" |
Dynamic CSS classes | class="{{ condition ? 'a' : 'b' }}" |
Communicating with the Magento API from Vue
const ProductList = {
data() {
return { products: [], loading: false, error: null };
},
async mounted() {
await this.fetchProducts();
},
methods: {
async fetchProducts() {
this.loading = true;
this.error = null;
try {
const response = await fetch(
'/rest/V1/products?searchCriteria[pageSize]=12&searchCriteria[currentPage]=1',
{ headers: { 'Content-Type': 'application/json' } }
);
if (!response.ok) throw new Error('API error: ' + response.status);
const data = await response.json();
this.products = data.items;
} catch (err) {
this.error = err.message;
} finally {
this.loading = false;
}
},
},
template: `
<div>
<div v-if="loading">Loading...</div>
<div v-else-if="error">Error: {{ error }}</div>
<product-card v-else v-for="product in products" :key="product.id" :product="product" />
</div>
`,
};
Composition API - more PHP-like approach
import { ref, computed, onMounted } from 'vue';
export default {
props: ['productId'],
setup(props) {
const product = ref(null); // ref() = reactive class property
const quantity = ref(1);
const loading = ref(false);
const totalPrice = computed(() => // computed = getter
product.value ? (product.value.price * quantity.value).toFixed(2) : '0.00'
);
async function loadProduct() {
loading.value = true;
const response = await fetch('/rest/V1/products/' + props.productId);
product.value = await response.json();
loading.value = false;
}
onMounted(loadProduct); // lifecycle hook
return { product, quantity, totalPrice, loading };
},
};
Summary
Vue.js has a gentle learning curve - a component with Options API is structurally similar to a PHP class with properties and methods. Reactivity (automatic view updates when data changes) is the biggest mindset shift from classic PHP, where rendering is a one-time process. If you plan to work with Vue Storefront or build interactive components for a Magento shop - Vue is worth a few weekends.
