# v-slot
Vue 2.6.0์์ v-slot
๋๋ ํฐ๋ธ๊ฐ ์๋กญ๊ฒ ์๊ฐ๋์์ต๋๋ค. v-slot
์ ๋ค์๋ ์ฌ๋กฏ(Named Slots)๊ณผ ์ค์ฝฅ๋ ์ฌ๋กฏ(Scoped Slot) ์ฌ์ฉ์ ํตํฉํ ์๋ก์ด ๋๋ ํฐ๋ธ ์
๋๋ค. ๊ธฐ์กด์ ์ค์ฝฅ๋ ์ฌ๋กฏ(Scoped Slot) ํํ์ Vue 3.0 ์์ ์ฌ๋ผ์ง๋๋ค.
์ด์ ๋ฒ์ ์์ ์ค์ฝฅ๋ ์ฌ๋กฏ์ด ๊ฐ์ง๊ณ ์์๋ ๋ฌธ์ ์ ๊ณผ ํจ๊ป v-slot
๋๋ ํฐ๋ธ๊ฐ ์ด๋ป๊ฒ ๊ทธ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๋์ง ์ดํด๋ด
์๋ค.
# ์ค์ฝฅ๋ ์ฌ๋กฏ์ ๋ฌธ์ ์
Vue.js์์ ์ฌ๋กฏ์ ์ฌ์ฉํ๋ ์ด์ ๋ ์ฌ์ฌ์ฉ์ฑ์ด ๋์ ์ปดํฌ๋ํธ๋ฅผ ์ค๊ณํ๊ธฐ ์ฝ๊ธฐ ๋๋ฌธ์ ๋๋ค. ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์์ ํจ์๋ฅผ ์์ฑํ ๋ ๋จ์ผ ์ฑ ์ ์์น(Single Responsibility Principle) (opens new window)์ ์ง์ผ์ฃผ๋ฉด ์ข์ ๊ฒ์ฒ๋ผ Vue.js ์ปดํฌ๋ํธ๋ฅผ ์ค๊ณํ ๋์๋ ํ๋์ ์ปดํฌ๋ํธ๊ฐ ํ๋์ ์ญํ ์ ํ ์ ์๋๋ก ์ค๊ณํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์ค์ฝฅ๋ ์ฌ๋กฏ์ ์ฌ๋กฏ์ ์ฌ์ฉํ ๋, ํ์ ์ปดํฌ๋ํธ์ ๊ฐ์ ์์ ์ปดํฌ๋ํธ์์ ์ฐธ์กฐํ ์ ์๊ฒ ํฉ๋๋ค. ์์ ์ปดํฌ๋ํธ์ ๋ฐ์ดํฐ๋ฅผ ํ์ ์ปดํฌ๋ํธ ์ฌ๋กฏ์ผ๋ก ๋ฐ์ธ๋ฉ ํด์ฃผ๋ ๊ฒ์ด ์์ฐ์ค๋ฌ์ ๋ณด์ด์ง๋ง, ํ์ ์ปดํฌ๋ํธ๊ฐ ๋จ์ผ ์ฑ ์์ ์ง๊ธฐ ์ํด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์์ด์ผ ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ฐ์ดํฐ๋ฅผ ์์์์ ์ฐธ์กฐํด์ผ ํ ๋๊ฐ ์์ต๋๋ค. ๊ทธ๋ ์ฌ์ฉํ๋ ๊ฒ์ด ์ค์ฝฅ๋ ์ฌ๋กฏ์ ๋๋ค.
ํ์ง๋ง, Vue.js์์ ์ค์ฝฅ๋ ์ฌ๋กฏ์ ์๊ฐํ์ ๋, slot-scope
์์ฑ์ ์ถ๊ฐํ <template>
ํ๊ทธ๋ฅผ ์ฌ์ฉํด ๊ตฌ๋ฌธ์ด ๊ธธ์ด์ง๋ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค.
<!-- ํ์ ์ปดํฌ๋ํธ(Foo.vue) -->
<template>
<div>
<slot :fooProps="fooProps"></slot>
</div>
</template>
<script>
export default {
data() {
return {
fooProps: {
id: 1,
msg: 'Hello',
}
}
}
}
</script>
<!-- ์์ ์ปดํฌ๋ํธ -->
<template>
<foo>
<template slot-scope="fooProps">
<div>{{ fooProps }}</div>
</template>
</foo>
</template>
<script>
import Foo from './Foo.vue';
export default {
components: {
Foo
}
}
</script>
์ค์ฝฅ๋ ์ฌ๋กฏ์ ์ฌ์ฉํ๊ธฐ ์ํด์ <template>
ํ๊ทธ๋ฅผ ํญ์ ์ฌ์ฉํด์ผ ํ๊ธฐ ๋๋ฌธ์ Vue 2.5์์๋ ์ค์ฝฅ๋ ์ฌ๋กฏ์ <template>
ํ๊ทธ ๋์ , ํํํ๊ณ ์ ํ๋ ํ๊ทธ์ ์ง์ ์์ฑํ ์ ์๋๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค.
<foo>
<div slot-scope="fooProps">{{ fooProps }}</div>
</foo>
์ฌ๊ธฐ์ ๋์ฌ๊ฒจ๋ด์ผ ํ ๋ถ๋ถ์ ํ์ ์ปดํฌ๋ํธ์ธ <foo>
ํ๊ทธ์ ํ๋กญ์ค ์์ฑ์ด ์์ ์ปดํฌ๋ํธ์ <div>
ํ๊ทธ๋ก ์ ๋ฌ๋์๋ค๋ ์ ์
๋๋ค.
๋ํ, HTML์ ๊ธฐ๋ณธ ํ๊ทธ๋ฟ ์๋๋ผ ์ปดํฌ๋ํธ ํ๊ทธ์์๋ ์ค์ฝฅ๋ ์ฌ๋กฏ์ ํํํ ์ ์์ต๋๋ค.
<foo>
<bar slot-scope="fooProps">{{ fooProps }}</bar>
</foo>
ํ์ง๋ง ์์ ๊ฐ์ด ์ฌ์ฉํ์ ๋, ์ปดํฌ๋ํธ์ ๋ณต์ก์ฑ์ด ๋์ด๋๋ฉด ์ด๋ค ์ปดํฌ๋ํธ์ slot-scope
๋ณ์๋ฅผ ์ฌ์ฉํ๋์ง ๋ช
ํํ์ง ์๋ค๋ ๋ฌธ์ ์ ์ด ๋ฐ์ํฉ๋๋ค.
<foo>
<bar slot-scope="fooProps">
<baz slot-scope="barProps">
<div slot-scope="bazProps">
{{ fooProp }} {{ barProp }} {{ bazProp }}
</div>
</baz>
</bar>
</foo>
์์ ์ปดํฌ๋ํธ์ธ <foo>
ํ๊ทธ๊ฐ ์ค์ฝฅ๋ ์ฌ๋กฏ์ ์ฌ์ฉํ๊ธฐ ์ํด <bar>
ํ๊ทธ์ slot-scope
๋ฅผ ์ฌ์ฉํ๊ณ , ์ด์ด์ <bar>
ํ๊ทธ๋ ์ด์ด์ <baz>
ํ๊ทธ์ ์ฌ์ฉํ์ต๋๋ค. ์ด๋ ๊ฒ ์ค์ฒฉ๋ ์ปดํฌ๋ํธ์์ ์ค์ฝฅ๋ ์ฌ๋กฏ์ ์ฌ์ฉํ๊ฒ ๋๋ฉด ์ด๋ค ์ปดํฌ๋ํธ๊ฐ ์ด๋ค props์ ์ฌ๋ ค์ฃผ๊ณ ์๋์ง ๋ช
ํํ์ง ์๊ฒ ๋ฉ๋๋ค.
์ฆ 2.5 ๋ฒ์ ์์ ์ค์ฝฅ๋ ์ฌ๋กฏ์ ์ฌ์ฉํ ๋ slot-scope
์์ฑ์ <template>
ํ๊ทธ์๋ง ์ฌ์ฉํ๋ ๊ฒ์ด ์๋๋ผ, ๊ธฐ์กด ํ๊ทธ์ ์ฌ์ฉํ ์ ์๋๋ก ํ์ฉํ ๊ฒ์ด ๋ฌธ์ ๊ฐ ๋์์ต๋๋ค. ๋ฐ๋ผ์, v-slot
๋๋ ํฐ๋ธ๊ฐ ๋ฑ์ฅํ๊ฒ ๋์์ต๋๋ค.
TIP
Vue 3.0์์๋ slot-scope
๋ฌธ๋ฒ์ด ์ ๊ฑฐ๋์๊ธฐ ๋๋ฌธ์, Vue 3.0์์ slot-scope
๋ฅผ ์ฌ์ฉํ๋ฉด eslint๊ฐ v-slot
์ผ๋ก ๋ณํํด ์ค๋๋ค. (Vue CLI๋ฅผ ์ด์ฉํด Vue 3.0์ ์ค์นํ๋ค๊ณ ๊ฐ์ ํฉ๋๋ค.)
# v-slot ๊ธฐ๋ณธ ์ฌ์ฉ ๋ฐฉ๋ฒ
v-slot
์ ์ฌ๋กฏ์ name ์์ฑ์ ์ง์ ํ์ฌ ์ฌ๋ฌ ๊ฐ ์ฌ์ฉํ ์ ์๋๋ก ํ๋ ๋ค์๋ ์ฌ๋กฏ(Named Slots)๊ณผ ์ค์ฝฅ๋ ์ฌ๋กฏ์ ํ ๋ฒ์ ํํํ ์ ์์ต๋๋ค.
# ๋ค์๋ ์ฌ๋กฏ ํํ
<!-- ํ์ ์ปดํฌ๋ํธ(Foo.vue) -->
<div>
<!-- ํค๋ ์์ญ -->
<slot name="header"></slot>
<!-- ๋ณธ๋ฌธ ์์ญ -->
<slot></slot>
<!-- ํธํฐ ์์ญ -->
<slot name="footer"></slot>
</div>
<!-- ์์ ์ปดํฌ๋ํธ -->
<foo>
<!-- ํค๋ ์์ญ -->
<template v-slot:header>
<h1>Header</h1>
</template>
<!-- ๋ณธ๋ฌธ ์์ญ -->
<template v-slot:default>
<div>Body</div>
</template>
<!-- ํธํฐ ์์ญ -->
<template v-slot:footer>
<div>Footer</div>
</template>
</foo>
TIP
v-slot:default
๋ ์ฌ๋กฏ์ name ์์ฑ์ ๋ถ์ด์ง ์์ ์์ญ์ ํํ๋ฉ๋๋ค.
๋ ๋๋ง ๋ HTML์ ์๋์ ๊ฐ์ต๋๋ค.
<div>
<h1>Header</h1>
<div>Body</div>
<div>Footer</div>
</div>
# ์ค์ฝฅ๋ ์ฌ๋กฏ ํํ
<!-- ํ์ ์ปดํฌ๋ํธ(Foo.vue) -->
<template>
<slot :msg="msg"></slot>
</template>
<script>
export default {
data() {
return {
msg: 'Hello!',
};
},
};
</script>
<!-- ์์ ์ปดํฌ๋ํธ -->
<foo>
<template v-slot:default="slotProps">
<h1>{{ slotProps.msg }}</h1> <!-- <h1>Hello!</h1> -->
</template>
</foo>
# v-slot์ ์ด์
<template>
ํ๊ทธ๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ ์ฅํฉํด์ง๋ ํํ์ ๊ฐ๋ตํ๊ฒ ํ ์ ์์ผ๋ฉฐ, ๋๋ถ์ ๊ฐ๋
์ฑ ๋ํ ์ข์์ง๋๋ค.
<!-- old -->
<foo>
<template slot-scope="{ msg }">
{{ msg }}
</template>
</foo>
<!-- new -->
<foo v-slot="{ msg }">{{ msg }}</foo>
์ด๋ค ์ปดํฌ๋ํธ์ ์ค์ฝฅ๋ ์ฌ๋กฏ์ธ์ง ๋ช ํํ๊ฒ ํํ๋ฉ๋๋ค.
<!-- old -->
<foo>
<bar slot-scope="foo">
<baz slot-scope="bar">
<div slot-scope="baz">
{{ foo }} {{ bar }} {{ baz }}
</div>
</baz>
</bar>
</foo>
<!-- new -->
<foo v-slot="foo">
<bar v-slot="bar">
<baz v-slot="baz">
{{ foo }} {{ bar }} {{ baz }}
</baz>
</bar>
</foo>
# v-slot ์์ฉ ํํ ๋ฐฉ์
# ์ถ์ฝ ํํ
์ค์ฝฅ๋ ์ฌ๋กฏ์ v-slot
๋ค์ props๋ฅผ ์์ฑํด ์ฃผ๋ฉด ํ์ ํ๊ทธ์์ ์ฌ์ฉํ ์ ์๊ฒ ๋ฉ๋๋ค. ์์ Vue 2.5์์ ๋ฌธ์ ๊ฐ ๋์๋ <template>
ํ๊ทธ๋ฅผ ๋ค์ ์ฌ์ฉํด์ผ ํ๋ค๋ ๋จ์ ์ด ์๊ธธ ์ ์์ต๋๋ค. ํ์ง๋ง, ์ฌ๋ฌ ๊ฐ์ ์ฌ๋กฏ์ ์ฌ์ฉํ์ง ์๊ณ default ์ฌ๋กฏ๋ง ์ฌ์ฉํ๋ค๋ฉด ์๋์ ๊ฐ์ด ์ปดํฌ๋ํธ ์์ฒด์ v-slot
์์ฑ์ ์ง์ ํด ์ฌ์ฉํ ์ ์์ต๋๋ค.
<foo v-slot:default="slotProps">
<h1>{{ slotProps.msg }}</h1>
</foo>
WARNING
ํ์ง๋ง ์ฌ๋กฏ์ด ์ฌ๋ฌ ๊ฐ์ผ ๊ฒฝ์ฐ๋ ๋ฐ๋์ <template>
ํ๊ทธ๋ฅผ ์ฌ์ฉํด ์ปดํฌ๋ํธ ํ์์ ํํํด ์ฃผ์ด์ผ ํฉ๋๋ค.
๋ํ v-slot:default
๋ v-slot
์ผ๋ก ์ถ์ฝํ์ฌ ํํํ ์ ์์ต๋๋ค.
<foo v-slot="slotProps">
<h1>{{ slotProps.msg }}</h1>
</foo>
๋จ, ์ปดํฌ๋ํธ ์์ฒด์ v-slot
์ ์ฌ์ฉํ๊ณ , ํ์์ ์ด๋ฆ์ ๊ฐ์ง v-slot
์ ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ์ค์ฝฅ๋ ์ฌ๋กฏ์ ๋ณ์ ๋ฒ์๊ฐ ๋ชจํธํด์ง๊ธฐ ๋๋ฌธ์
๋๋ค. ์๋์ ์์ ์ฝ๋๋ default
์ฌ๋กฏ์ด foo
์ปดํฌ๋ํธ์ ์ ์ธ๋์๊ณ , ํ์์ other
์ด๋ฆ์ ๊ฐ์ง ์ฌ๋กฏ์ด ์กด์ฌํฉ๋๋ค.
<!-- v-slot:other์ด ์๊ธฐ ๋๋ฌธ์ ์ค๋ฅ ๋ฐ์ -->
<foo v-slot="slotProps">
{{ slotProps.msg }}
<template v-slot:other="otherSlotProps">
<!-- ์ด๊ณณ์ slotProps๋ฅผ ์ ์ฉํ ์ ์์. -->
</template>
</foo>
์ ์ฝ๋๊ฐ ๋์ํ๋ ค๋ฉด <template>
ํ๊ทธ๋ก ๋ช
ํํ ๋ฒ์๋ฅผ ์ง์ ํด ์ฃผ์ด์ผ ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ , default name์ ๊ฐ์ง v-slot
์ถ์ฝ ๋ฌธ๋ฒ์ <template>
ํ๊ทธ๋ก ๋ช
ํํ ๋ฒ์๋ฅผ ์ง์ ํด ์ค๋ค๋ฉด, ์ด๋ฆ์ ๊ฐ์ง ์ฌ๋กฏ(<v-slot:other>
๋ฑ)๊ณผ ํผ์ฉํด์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
<foo>
<template v-slot="slotProps">
{{ slotProps.msg }}
</template>
<template v-slot:other="otherSlotProps">
{{ otherSlotProps.something }}
</template>
</foo>
# ํน์ ๊ธฐํธ ํํ
v-slot
์ v-bind(:)
, v-on(@)
๊ณผ ๊ฐ์ด ํน์ ๊ธฐํธ๋ฅผ ํตํด ๋ํ๋ผ ์ ์์ต๋๋ค. ํน์ ๊ธฐํธ๋ #
์
๋๋ค. ์๋ฅผ ๋ค์ด v-slot:default
๋ #default
๋ก ํํ๋ ์ ์์ต๋๋ค.
<foo #default="slotProps">
<h1>{{ slotProps.msg }}</h1>
</foo>
๋จ, #="slotProps"
๊ตฌ๋ฌธ์ ๋ถ๊ฐ๋ฅํฉ๋๋ค. ํน์ ๊ธฐํธ๋ก ํํํ๊ณ ์ถ๋ค๋ฉด, #default="slotProps"
์ ๊ฐ์ด ๋ฐ๋์ ์ฌ๋กฏ ์ด๋ฆ์ ์ง์ ํด ์ฃผ์ด์ผ ํฉ๋๋ค.
# Destructuring ํํ
์ค์ฝฅ๋ ์ฌ๋กฏ์ ๋ณ์์ ES6 ๋ฌธ๋ฒ์ธ, ๊ตฌ์กฐ ๋ถํด ๋ฌธ๋ฒ(Destructuring) ํํ๋ ๊ฐ๋ฅํฉ๋๋ค.
<foo v-slot="{ msg }">
<h1>{{ msg }}</h1>
</foo>
# Dynamic Slot Names ํํ
์ฌ๋กฏ name์ ๋์ ์ผ๋ก ํํํ ์ ์์ต๋๋ค.
<foo>
<template v-slot:[dynamicSlotName]>
...
</template>
</foo>
WARNING
์ค์ฝฅ๋ ์ฌ๋กฏ์ slot-scope
ํํ์ Vue 3.0 ์ดํ์ ๋ฒ์ ์์๋ ๊ณ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋จ Vue 3.0 ์ด์ ๋ฒ์ ์์ ์ญ์ ๋์์ผ๋ฏ๋ก Vue 2.6 ์ด์์ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด, v-slot
๋๋ ํฐ๋ธ๋ฅผ ํตํด ์ฌ๋กฏ์ ์ฌ์ฉํ๋๋ก ๊ถ์ฅํฉ๋๋ค.
โ Scoped Slot Plugins ๐ โ