SFC and Script Setup

Back

Loading concept...

🏠 Vue.js Single File Components: Building Your Dream House

Imagine you’re building a LEGO house. You have three types of blocks:

  • The shape blocks (what it looks like)
  • The brain blocks (how it thinks)
  • The paint blocks (the colors and style)

In Vue.js, a Single File Component (SFC) is exactly like that LEGO house. Everything you need is in ONE file with the .vue extension!


🎯 What is a Single File Component?

Think of an SFC like a recipe card. One card has:

  1. A picture of the dish (Template)
  2. The cooking steps (Script)
  3. How to plate it prettily (Style)
<!-- MyComponent.vue -->
<template>
  <!-- What users SEE -->
</template>

<script setup>
  // How it THINKS
</script>

<style scoped>
  /* How it LOOKS */
</style>

Why is this amazing?

  • Everything in ONE place
  • Easy to find things
  • Like having your whole recipe on one card!

📝 The Template Section: The Face of Your Component

The <template> is what people SEE. It’s like the front of a greeting card.

<template>
  <div class="greeting-card">
    <h1>{{ message }}</h1>
    <button @click="sayHello">
      Click Me!
    </button>
  </div>
</template>

Key Rules:

  • Must have ONE root element (the wrapper <div>)
  • Uses {{ }} to show data (like a window to your data)
  • Uses @click to listen for clicks
graph TD A["Template Section"] --> B["HTML Structure"] B --> C["Shows Data with curly braces"] B --> D["Listens for Events"] B --> E["One Root Element"]

🧠 The Script Section: The Brain

The <script> is where your component THINKS. It holds:

  • Data (what the component remembers)
  • Methods (what the component can do)
  • Logic (how the component decides)

Old Way (Options API):

<script>
export default {
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
</script>

Think of this like filling out a form with specific boxes for each thing.


🎨 The Style Section: The Fashion Designer

The <style> section makes things PRETTY. It’s the makeup and clothes for your component.

<style scoped>
.greeting-card {
  background: #42b883;
  padding: 20px;
  border-radius: 10px;
}

button {
  background: white;
  color: #42b883;
}
</style>

The Magic Word: scoped

  • Without scoped: Styles apply to EVERYTHING (messy!)
  • With scoped: Styles only apply to THIS component (clean!)

It’s like wearing a name tag. Only YOUR clothes stay with YOU.


⚡ Script Setup Syntax: The Shortcut

Remember the “old way” with export default? There’s a faster, cleaner way!

<script setup>
import { ref } from 'vue'

const count = ref(0)

function increment() {
  count.value++
}
</script>

What Changed?

Old Way Script Setup
export default Not needed!
data() Use ref()
this.count Just count.value
More typing Less typing!

Script Setup automatically makes everything available in your template. No more “exporting” things!


🪄 Script Setup Macros: Magic Words

Macros are special helper words that only work inside <script setup>. They’re like magic spells!

defineProps - Receiving Gifts

When a parent gives your component data:

<script setup>
const props = defineProps({
  name: String,
  age: Number
})
</script>

<template>
  <p>Hello, {{ name }}! You are {{ age }}.</p>
</template>

defineEmits - Sending Messages

When your component wants to tell the parent something:

<script setup>
const emit = defineEmits(['save', 'cancel'])

function handleSave() {
  emit('save', { data: 'my data' })
}
</script>

defineExpose - Sharing Secrets

Let parents access your component’s inner things:

<script setup>
import { ref } from 'vue'

const secretNumber = ref(42)

defineExpose({
  secretNumber
})
</script>
graph TD A["Script Setup Macros"] --> B["defineProps"] A --> C["defineEmits"] A --> D["defineExpose"] B --> E["Receive data from parent"] C --> F["Send events to parent"] D --> G["Share inner data with parent"]

🛠️ Composition API Helpers: Your Toolbox

The Composition API gives you powerful tools to organize your code.

ref - A Box for One Value

<script setup>
import { ref } from 'vue'

const message = ref('Hello!')
// To read: message.value
// To change: message.value = 'Bye!'
</script>

reactive - A Box for Many Values

<script setup>
import { reactive } from 'vue'

const user = reactive({
  name: 'Alex',
  age: 10,
  hobby: 'coding'
})
// To read: user.name
// To change: user.age = 11
</script>

computed - Auto-Calculating Values

<script setup>
import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed(() => {
  return firstName.value + ' ' + lastName.value
})
// fullName updates automatically!
</script>

watch - The Spy

<script setup>
import { ref, watch } from 'vue'

const count = ref(0)

watch(count, (newVal, oldVal) => {
  console.log(`Changed from ${oldVal} to ${newVal}`)
})
</script>
Helper Purpose Think of it as…
ref Single value A labeled box
reactive Object with values A labeled drawer
computed Auto-calculated A calculator
watch React to changes A spy watching

⚔️ Composition vs Options API: The Big Choice

Options API (The Form Approach)

<script>
export default {
  data() {
    return { count: 0 }
  },
  computed: {
    doubled() {
      return this.count * 2
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
</script>

Good for: Beginners, simple components

Composition API (The Toolbox Approach)

<script setup>
import { ref, computed } from 'vue'

const count = ref(0)
const doubled = computed(() => count.value * 2)

function increment() {
  count.value++
}
</script>

Good for: Complex logic, reusable code

graph LR A["Choose Your Style"] --> B["Options API"] A --> C["Composition API"] B --> D["Organized by type"] B --> E["Uses &&#35;39;this&&#35;39; keyword"] B --> F["Great for beginners"] C --> G["Organized by feature"] C --> H["No &&#35;39;this&&#35;39; needed"] C --> I["Better for complex apps"]

The Big Difference

Feature Options API Composition API
Organization By type By feature
Learning curve Easier Slightly harder
Code reuse Mixins Composables
TypeScript OK Great!
this keyword Required Not needed

🎉 Putting It All Together

Here’s a complete SFC using everything we learned:

<template>
  <div class="counter-app">
    <h1>{{ title }}</h1>
    <p>Count: {{ count }}</p>
    <p>Doubled: {{ doubled }}</p>
    <button @click="increment">
      Add One
    </button>
    <button @click="reset">
      Reset
    </button>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

// Props from parent
const props = defineProps({
  title: {
    type: String,
    default: 'My Counter'
  }
})

// Emit events to parent
const emit = defineEmits(['updated'])

// Reactive data
const count = ref(0)

// Computed property
const doubled = computed(() => count.value * 2)

// Methods
function increment() {
  count.value++
  emit('updated', count.value)
}

function reset() {
  count.value = 0
  emit('updated', count.value)
}
</script>

<style scoped>
.counter-app {
  background: linear-gradient(135deg, #42b883, #35495e);
  padding: 20px;
  border-radius: 12px;
  color: white;
  text-align: center;
}

button {
  margin: 5px;
  padding: 10px 20px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
}
</style>

🌟 Summary: Your SFC Checklist

Template = What users see (HTML)

Script = How it thinks (JavaScript)

Style = How it looks (CSS)

Script Setup = The modern, clean way to write logic

Macros = defineProps, defineEmits, defineExpose

Helpers = ref, reactive, computed, watch

Two Styles = Options API (form) vs Composition API (toolbox)


You did it! 🎊 You now understand Vue.js Single File Components. Each .vue file is like a complete LEGO set - everything you need in one place, ready to build amazing things!

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.