In the process of working with Vuejs, everyone must have used slots before, but is there any other effect besides the function of adding html
content from the parent component to the child component?
Let’s go through the examples and methods below to see if you really understand slots?
Component packaging
Problem
For example, with a simple dialog component like this with the library ElementUI
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> div</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> el-button</span> <span class="token attr-name">@click</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> handleOpen <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> Open <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> el-button</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> el-dialog</span> <span class="token attr-name">:visible</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> isVisible <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> el-button</span> <span class="token attr-name">@click</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> handleClose <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> Cancel <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> el-button</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> el-dialog</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> div</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> script</span> <span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token function">data</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> isVisible <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> methods <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">handleOpen</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> isVisible <span class="token operator">=</span> <span class="token boolean">true</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token function">handleClose</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> isVisible <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span> script</span> <span class="token punctuation">></span></span> |
This component has an isVisible
variable and functions that open and close dialog
But as the component expands and has more dialogs, the variables and functions increase
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <span class="token operator"><</span> script <span class="token operator">></span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token function">data</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> isVisible1 <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> isVisible2 <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> isVisible3 <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> isVisible4 <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> isVisible5 <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> methods <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">handleOpen1</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> isVisible1 <span class="token operator">=</span> <span class="token boolean">true</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token function">handleClose1</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> isVisible1 <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token function">handleOpen2</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> isVisible2 <span class="token operator">=</span> <span class="token boolean">true</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token function">handleClose2</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> isVisible2 <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token function">handleOpen3</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> isVisible3 <span class="token operator">=</span> <span class="token boolean">true</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token function">handleClose3</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> isVisible3 <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">...</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> script <span class="token operator">></span> |
Iterative opening and closing functions, so how to optimize, we will go to the next part
Handle
Create a component called SlotDialog
, this component will set a default slot, and has an isVisible
variable with 2 functions used to open and close the dialog
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // SlotDialog <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> div</span> <span class="token punctuation">></span></span> <span class="token comment"><!-- Truyền ngược lại các biến và hàm cần dùng vào slot theo kiểu truyền prop --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">:isVisible</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> isVisible <span class="token punctuation">"</span></span> <span class="token attr-name">:open</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> handleOpen <span class="token punctuation">"</span></span> <span class="token attr-name">:close</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> handleClose <span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> div</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> script</span> <span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token function">data</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> isVisible <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> methods <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">handleOpen</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> isVisible <span class="token operator">=</span> <span class="token boolean">true</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token function">handleClose</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> isVisible <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span> script</span> <span class="token punctuation">></span></span> |
And when used, we can get the props passed in 2 ways: v-slot
or slot-scope
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <span class="token comment"><!-- Cách 1 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> SlotDialog</span> <span class="token punctuation">></span></span> <span class="token comment"><!-- Dùng destructing để lấy các biến --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">v-slot</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> { isVisible, open, close } <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> el-button</span> <span class="token attr-name">@click</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> open <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> click <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> el-button</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> el-dialog</span> <span class="token attr-name">:visible</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> isVisible <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> el-button</span> <span class="token attr-name">@click</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> close <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> Cancel <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> el-button</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> el-dialog</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> SlotDialog</span> <span class="token punctuation">></span></span> <span class="token comment"><!-- Cách 2 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> SlotDialog</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">slot-scope</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> el-button</span> <span class="token attr-name">@click</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope.open <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> click <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> el-button</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> el-dialog</span> <span class="token attr-name">:visible</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope.isVisible <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token comment"><!-- Nếu muốn xử lý thêm logic thì chỉ cần truyền vào 1 function callback --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> el-button</span> <span class="token attr-name">@click</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> handleClose(scope.close) <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> Cancel <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> el-button</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> el-dialog</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> SlotDialog</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> script</span> <span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> methods <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token function">handleClose</span> <span class="token punctuation">(</span> <span class="token parameter">close</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Hàm này sẽ xử lý logic và gọi lại hàm đóng dialog</span> <span class="token function">close</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span> script</span> <span class="token punctuation">></span></span> |
For the default
slot, we can write as above, and for the slot example named body
, the syntax will be
1 2 3 4 5 6 | <span class="token comment"><!-- Cách 1 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name"><span class="token namespace">v-slot:</span> body</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token comment"><!-- Cách 2 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">slot</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> body <span class="token punctuation">"</span></span> <span class="token attr-name">slot-scope</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> |
So in the above example we have seen that it is possible to use multiple dialogs without having to create the same variables and functions.
Nested Slots
Problem
Component Counter
has 1 counter
variable that will increment every second placed in the body
slot slot
Header
and Footer
cards are also placed in their respective slots
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | // Counter.vue <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> div</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> header <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> h1</span> <span class="token punctuation">></span></span> Header <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> h1</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> slot</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> body <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> p</span> <span class="token punctuation">></span></span> Counter: {{ counter }} <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> p</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> slot</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> footer <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> h2</span> <span class="token punctuation">></span></span> Footer <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> h2</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> slot</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> div</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> script</span> <span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> <span class="token function">data</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> counter <span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token function">beforeMount</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> $options <span class="token punctuation">.</span> counter <span class="token operator">=</span> <span class="token function">setInterval</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> counter <span class="token operator">+=</span> <span class="token number">1</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token number">1000</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> <span class="token function">$on</span> <span class="token punctuation">(</span> <span class="token string">'hook:beforeDestroy'</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">clearInterval</span> <span class="token punctuation">(</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> $options <span class="token punctuation">.</span> counter <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span> script</span> <span class="token punctuation">></span></span> |
This component will be used in many places, each place has a different requirement, is to change the content of the body
or header
, footer
The first way we think of would be to pass the condition props
in and if
else
to change
And then every 1 request will be a new prop
and add the if else
, it will eventually become a pile of garbage
Thinking when designing a component that is shared in many places is how it can still be edited and extended without affecting other parts.
Component Counter
nested inside Child
and Parent
components
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // ChildComponent <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> Counter</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">slot</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> header <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> header <span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">slot</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> body <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> body <span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">slot</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> footer <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> footer <span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> Counter</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> script</span> <span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">import</span> Counter <span class="token keyword">from</span> <span class="token string">'./Counter.vue'</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> components <span class="token operator">:</span> <span class="token punctuation">{</span> Counter <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span> script</span> <span class="token punctuation">></span></span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // ParentComponent <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> ChildComponent</span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> script</span> <span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">import</span> ChildComponent <span class="token keyword">from</span> <span class="token string">"./ChildComponent.vue"</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> components <span class="token operator">:</span> <span class="token punctuation">{</span> ChildComponent <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span> script</span> <span class="token punctuation">></span></span> |
The Child
component will call the Counter
component and will have slot
tags available so that slots can be passed from the Parent
component
Note that when passing a 2-tier slot like this, we will use the template
tag, because if we use the div
tag, the Counter
component will understand that we are passing the slot with empty content from the outside and it will override the default slot. inside the slot
If using a div tag, you must add a condition so that only when there is a slot passed in from the Parent
, it will be rendered
1 2 3 4 | <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> div</span> <span class="token attr-name">v-if</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> $slots.body <span class="token punctuation">"</span></span> <span class="token attr-name">slot</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> body <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> body <span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> div</span> <span class="token punctuation">></span></span> |
Handle
And now, we will use scoped slots
technique to get the counter
value from the Counter
component out of the Parent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // Counter.vue <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> div</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> header <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> h1</span> <span class="token punctuation">></span></span> Header <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> h1</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> slot</span> <span class="token punctuation">></span></span> <span class="token comment"><!-- Truyền biến counter vào slot body --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> body <span class="token punctuation">"</span></span> <span class="token attr-name">:counter</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> counter <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> p</span> <span class="token punctuation">></span></span> Counter: {{ counter }} <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> p</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> slot</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> footer <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> h2</span> <span class="token punctuation">></span></span> Footer <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> h2</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> slot</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> div</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // ChildComponent <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> Counter</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">slot</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> header <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> header <span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token comment"><!-- Lấy biến counter từ scope rồi truyền ngược ra 1 lần nữa vào slot body --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">slot</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> body <span class="token punctuation">"</span></span> <span class="token attr-name">slot-scope</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> body <span class="token punctuation">"</span></span> <span class="token attr-name">:counter</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope.counter <span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">slot</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> footer <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> footer <span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> Counter</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // ParentComponent <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> ChildComponent</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">slot</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> header <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> h1</span> <span class="token punctuation">></span></span> Custom Header <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> h1</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">slot</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> body <span class="token punctuation">"</span></span> <span class="token attr-name">slot-scope</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> h1</span> <span class="token punctuation">></span></span> {{ scope.counter }} <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> h1</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> ChildComponent</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> |
We can finally change the content from the Parent
and still get the values from within the Counter
component
Optimal
The Child
component’s way of writing above works, but when there are many slots and props, we have to rewrite a lot.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | // ChildComponent <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> Counter</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">slot</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> header <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> header <span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">slot</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> body <span class="token punctuation">"</span></span> <span class="token attr-name">slot-scope</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> body <span class="token punctuation">"</span></span> <span class="token attr-name">:prop1</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope.prop1 <span class="token punctuation">"</span></span> <span class="token attr-name">:prop2</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope.prop2 <span class="token punctuation">"</span></span> <span class="token attr-name">:prop3</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope.prop3 <span class="token punctuation">"</span></span> <span class="token attr-name">...</span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">slot</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> footer <span class="token punctuation">"</span></span> <span class="token attr-name">slot-scope</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> footer <span class="token punctuation">"</span></span> <span class="token attr-name">:prop1</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope.prop1 <span class="token punctuation">"</span></span> <span class="token attr-name">:prop2</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope.prop2 <span class="token punctuation">"</span></span> <span class="token attr-name">:prop3</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope.prop3 <span class="token punctuation">"</span></span> <span class="token attr-name">...</span> <span class="token punctuation">/></span></span> ... <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> Counter</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> |
So we will use the for
loop to render the slot cards
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | // ChildComponent <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> Counter</span> <span class="token punctuation">></span></span> <span class="token comment"><!-- Lấy các slot name từ $slots và truyền vào thẻ <slot> --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">v-for</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> slotName in $slots <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">:name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> slotName <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> slot</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token comment"><!-- Đôi với scoped slots thì sẽ lấy các key $scopedSlots --></span> <span class="token comment"><!-- Truyền slotName theo cú pháp dynamic slot để lấy scope --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">v-for</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> slotName in Object.keys($scopedSlots) <span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">v-slot:</span> [slotName]</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token comment"><!-- Thay vì phải viết từng prop ra, chúng ta sẽ v-bind scope luôn --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">:name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> slotName <span class="token punctuation">"</span></span> <span class="token attr-name">v-bind</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> slot</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token comment"><!-- Scoped slots cũng có thể loop theo cách này --></span> <span class="token comment"><!-- Biến đầu tiền sẽ là 1 function, chúng ta không dùng mà sẽ chỉ dùng slot name thôi --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> template</span> <span class="token attr-name">v-for</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> (_, slotName) in $scopedSlots <span class="token punctuation">"</span></span> <span class="token attr-name">#[slotName]</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token comment"><!-- Có thể truyền thêm các prop sau v-bind --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> slot</span> <span class="token attr-name">:name</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> slotName <span class="token punctuation">"</span></span> <span class="token attr-name">v-bind</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> scope <span class="token punctuation">"</span></span> <span class="token attr-name">:newProp</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> 1 <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> slot</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> Counter</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> template</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> script</span> <span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"> <span class="token keyword">import</span> Counter <span class="token keyword">from</span> <span class="token string">'./Counter.vue'</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> components <span class="token operator">:</span> <span class="token punctuation">{</span> Counter <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span> script</span> <span class="token punctuation">></span></span> |
Conclusion
Scoped slot is a method that helps us to encapsulate variables and logic in one component, to avoid redundancy in code
But as the name implies, the scope of props taken from the slot can only work within that scope
So depending on each case, we will consider whether to use it or not, if used correctly, the effect of this method is great.