Vue 可组合项是开发 Vue 应用时非常有用的工具。它们让开发者能够轻松地在应用中复用逻辑。除了允许“无状态”逻辑(例如格式化或常规计算)之外,可组合项还使我们能够在整个应用中复用有状态逻辑。
为什么要使用可组合项?
可组合函数允许您在应用中复用有状态逻辑。当某个逻辑在两个以上的地方使用时,我们通常希望将其合并到其自己的函数中。大多数情况下,该逻辑被认为是“无状态的”,这意味着它接受输入并返回输出。文档中提到了日期格式,但这也可能包括货币计算或字符串验证之类的功能。
在现代 Web 应用中,经常会有一些逻辑需要随时间推移管理状态。在典型的组件内部,我们能够根据组件内不同变量的“状态”来调整应用程序。有时,这些逻辑,或者至少是其中的一部分,会在整个应用中重复使用。
例如,在电商应用中,你可能有一些逻辑来增加或减少用户添加到购物车中的商品数量。这种逻辑既可以在产品页面上使用,也可以在购物车内部使用。
这两个地方的外观和感觉会有所不同,因此复用整个组件毫无意义——但我们仍然希望将逻辑集中化,以便于代码维护。这就是可组合组件 (Composables) 的用武之地。
简单的可组合示例
我们来看一个简单的计数器示例。这是一个非常简单的Counter组件的代码。
<span class="token operator"><</span>script setup lang<span class="token operator">=</span><span class="token string">"ts"</span><span class="token operator">></span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>
<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> Ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>
<span class="token keyword">const</span> count<span class="token operator">:</span> Ref<span class="token operator"><</span><span class="token builtin">number</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> <span class="token function-variable function">increment</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
count<span class="token punctuation">.</span>value<span class="token operator">++</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> <span class="token function-variable function">decrement</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
count<span class="token punctuation">.</span>value<span class="token operator">--</span>
<span class="token punctuation">}</span>
<span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span>
<span class="token operator"><</span>template<span class="token operator">></span>
<span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"bg-teal-100 border-2 border-gray-800 rounded-xl p-4 w-64"</span><span class="token operator">></span>
<span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"text-center mb-4"</span><span class="token operator">></span>
<span class="token operator"><</span>span <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"text-lg font-medium text-gray-800"</span><span class="token operator">></span>Count<span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">{</span> count <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span>
<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span>
<span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"flex gap-2 justify-center"</span><span class="token operator">></span>
<span class="token operator"><</span>button
<span class="token decorator"><span class="token at operator">@</span><span class="token function">click</span></span><span class="token operator">=</span><span class="token string">"decrement"</span>
<span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"bg-red-100 border-2 border-gray-800 rounded px-4 py-0 text-gray-800 font-medium hover:bg-red-500 transition-colors"</span>
<span class="token operator">></span>
<span class="token operator">-</span>
<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span>
<span class="token operator"><</span>button
<span class="token decorator"><span class="token at operator">@</span><span class="token function">click</span></span><span class="token operator">=</span><span class="token string">"count = 0"</span>
<span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"bg-gray-100 border-2 border-gray-800 rounded px-4 py-0 text-gray-800 font-medium hover:bg-gray-300 transition-colors"</span>
<span class="token operator">></span>
Reset
<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span>
<span class="token operator"><</span>button
<span class="token decorator"><span class="token at operator">@</span><span class="token function">click</span></span><span class="token operator">=</span><span class="token string">"increment"</span>
<span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"bg-green-100 border-2 border-gray-800 rounded px-4 py-0 text-gray-800 font-medium hover:bg-green-500 transition-colors"</span>
<span class="token operator">></span>
<span class="token operator">+</span>
<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span>
<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span>
<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span>
<span class="token operator"><</span><span class="token operator">/</span>template<span class="token operator">></span>
该组件的输出如下所示:

这很好用,但如果我们最终需要在另一个外观和感觉完全不同的组件中使用相同的计数器逻辑,那么我们最终会重复这个逻辑。我们可以将逻辑提取到可组合组件中,并在任何需要的地方访问相同的状态逻辑。
<span class="token comment">// counter.ts</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>
<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> Ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">useCounter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> Readonly<span class="token operator"><</span><span class="token punctuation">{</span>
count<span class="token operator">:</span> Ref<span class="token operator"><</span><span class="token builtin">number</span><span class="token operator">></span>
<span class="token function-variable function">increment</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">void</span>
<span class="token function-variable function">decrement</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">void</span>
<span class="token punctuation">}</span><span class="token operator">></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> count<span class="token operator">:</span> Ref<span class="token operator"><</span><span class="token builtin">number</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> <span class="token function-variable function">increment</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
count<span class="token punctuation">.</span>value<span class="token operator">++</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> <span class="token function-variable function">decrement</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
count<span class="token punctuation">.</span>value<span class="token operator">--</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token punctuation">{</span> count<span class="token punctuation">,</span> increment<span class="token punctuation">,</span> decrement <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
然后我们更新组件中的脚本标签以使用可组合项:
<span class="token operator"><</span>script setup<span class="token operator">></span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useCounter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@/counter.ts'</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> count<span class="token punctuation">,</span> increment<span class="token punctuation">,</span> decrement <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">useCounter</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>
<span class="token operator"><</span>template<span class="token operator">></span>
<span class="token operator">...</span>
<span class="token operator"><</span><span class="token operator">/</span>template<span class="token operator">></span>
现在我们可以在整个应用程序的多个组件中使用此逻辑。


您会注意到,只有逻辑被复制,每个组件仍然拥有各自的count状态副本。使用可组合组件并不意味着状态会在组件之间共享,而只是有状态逻辑会被共享。
复杂可组合示例
Vue 文档中给出了一个使用可组合项处理异步数据获取的示例。
Util 函数fetch
在开始使用可组合函数之前,我们需要为 API 设置一个实用函数fetch。这是因为我们希望确保每个请求在失败时都会抛出错误。fetch如果请求返回错误状态,API 不会抛出错误。我们必须检查response.ok以验证状态,然后在必要时抛出错误。
<span class="token comment">// utils.ts</span>
<span class="token keyword">export</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">handleFetch</span><span class="token punctuation">(</span>url<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">,</span> options<span class="token operator">:</span> RequestInit <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator"><</span>Response<span class="token operator">></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function" style="color: #ff0000;">fetch</span><span class="token punctuation">(</span>url<span class="token punctuation">,</span> options<span class="token punctuation">)</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>res<span class="token punctuation">.</span>ok<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> err <span class="token operator">=</span> <span class="token keyword">await</span> res<span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> res
<span class="token punctuation">}</span>
useAsyncState 可组合
当使用异步状态时,请求可以处于几种不同的状态:
- 待办的
- 已解决
- 被拒绝
除了这些状态之外,我们还想跟踪从请求返回的数据或错误。
<span class="token comment">// useAsyncState.ts</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> shallowRef <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>
<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> Ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>
<span class="token comment">// Specify a type for the response</span>
<span class="token keyword">export</span> <span class="token keyword">type</span> <span class="token class-name">AsyncState<span class="token operator"><</span><span class="token constant">T</span><span class="token operator">></span></span> <span class="token operator">=</span> <span class="token punctuation">{</span>
data<span class="token operator">:</span> Ref<span class="token operator"><</span><span class="token constant">T</span> <span class="token operator">|</span> <span class="token keyword">null</span><span class="token operator">></span>
error<span class="token operator">:</span> Ref<span class="token operator"><</span>Error <span class="token operator">|</span> <span class="token keyword">null</span><span class="token operator">></span>
isPending<span class="token operator">:</span> Ref<span class="token operator"><</span><span class="token builtin">boolean</span><span class="token operator">></span>
isResolved<span class="token operator">:</span> Ref<span class="token operator"><</span><span class="token builtin">boolean</span><span class="token operator">></span>
isRejected<span class="token operator">:</span> Ref<span class="token operator"><</span><span class="token builtin">boolean</span><span class="token operator">></span>
<span class="token punctuation">}</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token generic-function"><span class="token function">useAsyncState</span><span class="token generic class-name"><span class="token operator"><</span><span class="token constant">T</span><span class="token operator">></span></span></span><span class="token punctuation">(</span>promise<span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator"><</span><span class="token constant">T</span><span class="token operator">></span><span class="token punctuation">)</span><span class="token operator">:</span> AsyncState<span class="token operator"><</span><span class="token constant">T</span><span class="token operator">></span> <span class="token punctuation">{</span>
<span class="token comment">// I used shallowRef instead of ref to avoid deep reactivity</span>
<span class="token comment">// I only care about the top-level properties being reactive</span>
<span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token generic-function"><span class="token function">shallowRef</span><span class="token generic class-name"><span class="token operator"><</span><span class="token constant">T</span> <span class="token operator">|</span> <span class="token keyword">null</span><span class="token operator">></span></span></span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> error <span class="token operator">=</span> <span class="token generic-function"><span class="token function">shallowRef</span><span class="token generic class-name"><span class="token operator"><</span>Error <span class="token operator">|</span> <span class="token keyword">null</span><span class="token operator">></span></span></span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> isPending <span class="token operator">=</span> <span class="token function">shallowRef</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> isResolved <span class="token operator">=</span> <span class="token function">shallowRef</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> isRejected <span class="token operator">=</span> <span class="token function">shallowRef</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span>
data<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">null</span>
error<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">null</span>
isPending<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token boolean">true</span>
isRejected<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token boolean">false</span>
isResolved<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token boolean">false</span>
promise<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
data<span class="token punctuation">.</span>value <span class="token operator">=</span> result
isPending<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token boolean">false</span>
isResolved<span class="token punctuation">.</span>value <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">catch</span><span class="token punctuation">(</span>err <span class="token operator">=></span> <span class="token punctuation">{</span>
error<span class="token punctuation">.</span>value <span class="token operator">=</span> err
isPending<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token boolean">false</span>
isRejected<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token boolean">true</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token punctuation">{</span> data<span class="token punctuation">,</span> error<span class="token punctuation">,</span> isPending<span class="token punctuation">,</span> isResolved<span class="token punctuation">,</span> isRejected <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
这为不同的状态提供了一些更明确的属性,而不是依赖于data和中的值error。您还会注意到,这个可组合项接受的是 Promise,而不是像文档中显示的那样接受 URL 字符串。不同的端点会有不同的响应类型,我希望能够处理这个可组合项之外的响应类型。
在组件中的使用
我设置了一个端点,它会等待随机秒数,然后才返回成功或错误。我的组件正在使用可组合项调用此端点,并使用可组合项中的数据来更新模板。

错误状态显示如下:

为了使其更容易解释和理解,我将<script>标签和<template>组件的各个部分分开。
脚本
<span class="token operator"><</span>script lang<span class="token operator">=</span><span class="token string">"ts"</span> setup<span class="token operator">></span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> ref<span class="token punctuation">,</span> unref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>
<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> Ref <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue'</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> useAsyncState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@/composables'</span>
<span class="token keyword">import</span> <span class="token keyword">type</span> <span class="token punctuation">{</span> AsyncState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@/composables'</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> handleFetch <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@/utils'</span>
<span class="token keyword">interface</span> <span class="token class-name">RandomResponse</span> <span class="token punctuation">{</span>
msg<span class="token operator">:</span> <span class="token builtin">string</span>
<span class="token punctuation">}</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getRandomResponse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">Promise</span><span class="token operator"><</span>RandomResponse<span class="token operator">></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">handleFetch</span><span class="token punctuation">(</span><span class="token string">'https://briancbarrow.com/api/random'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> text <span class="token operator">=</span> <span class="token keyword">await</span> response<span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token punctuation">{</span> msg<span class="token operator">:</span> text <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> randomResponseData<span class="token operator">:</span> Ref<span class="token operator"><</span>AsyncState<span class="token operator"><</span>RandomResponse<span class="token operator">></span> <span class="token operator">|</span> <span class="token keyword">null</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token function">ref</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> <span class="token function-variable function">handleMakeRequest</span> <span class="token operator">=</span> <span class="token keyword">async</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">const</span> data <span class="token operator">=</span> <span class="token function">getRandomResponse</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
randomResponseData<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token function">useAsyncState</span><span class="token punctuation">(</span>data<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>
这里我们有一个方法,getRandomResponse它调用一个端点并返回一个 Promise。这个 Promise 随后被传入useAsyncStatewhenhandleMakeRequest函数。这将完整的返回值放入randomResponseDataref 中,然后我们可以在模板中使用它。
我不会展示完整的模板,而只展示其中的几个部分。
这里你可以看到两个按钮根据不同的状态被使用。我使用了一个单独的按钮元素来指示“加载”状态,但实际上你可以使用可组合属性来设置disabled按钮的属性并更改文本。
<span class="token tag"><span class="token punctuation"><</span>button
<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>
!randomResponseData?.isPending &&
!randomResponseData?.error &&
!randomResponseData?.data
<span class="token punctuation">"</span></span>
<span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2<span class="token punctuation">"</span></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>handleMakeRequest<span class="token punctuation">"</span></span>
<span class="token punctuation">></span></span>
Make Request
<span class="token tag"><span class="token punctuation"></</span>button<span class="token punctuation">></span></span>
<span class="token comment"><!-- Loading State Button --></span>
<span class="token tag"><span class="token punctuation"><</span>button
<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>randomResponseData?.isPending<span class="token punctuation">"</span></span>
<span class="token attr-name">disabled</span>
<span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>px-6 py-3 bg-blue-600 text-white font-medium rounded-lg opacity-75 cursor-not-allowed flex items-center mx-auto<span class="token punctuation">"</span></span>
<span class="token punctuation">></span></span>
<span class="token tag"><span class="token punctuation"><</span>svg
<span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>animate-spin -ml-1 mr-3 h-5 w-5 text-white<span class="token punctuation">"</span></span>
<span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://www.w3.org/2000/svg<span class="token punctuation">"</span></span>
<span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>none<span class="token punctuation">"</span></span>
<span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 24 24<span class="token punctuation">"</span></span>
<span class="token punctuation">></span></span>
<span class="token tag"><span class="token punctuation"><</span>circle
<span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>opacity-25<span class="token punctuation">"</span></span>
<span class="token attr-name">cx</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span>
<span class="token attr-name">cy</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>12<span class="token punctuation">"</span></span>
<span class="token attr-name">r</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>10<span class="token punctuation">"</span></span>
<span class="token attr-name">stroke</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>currentColor<span class="token punctuation">"</span></span>
<span class="token attr-name">stroke-width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>4<span class="token punctuation">"</span></span>
<span class="token punctuation">></span></span><span class="token tag"><span class="token punctuation"></</span>circle<span class="token punctuation">></span></span>
<span class="token tag"><span class="token punctuation"><</span>path
<span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>opacity-75<span class="token punctuation">"</span></span>
<span class="token attr-name">fill</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>currentColor<span class="token punctuation">"</span></span>
<span class="token attr-name">d</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z<span class="token punctuation">"</span></span>
<span class="token punctuation">></span></span><span class="token tag"><span class="token punctuation"></</span>path<span class="token punctuation">></span></span>
<span class="token tag"><span class="token punctuation"></</span>svg<span class="token punctuation">></span></span>
Loading...
<span class="token tag"><span class="token punctuation"></</span>button<span class="token punctuation">></span></span>
以下是表中的几行:
<span class="token tag"><span class="token punctuation"><</span>tr <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>divide-x divide-gray-200<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token punctuation"><</span>td <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>py-4 pr-4 pl-4 text-sm font-medium whitespace-nowrap text-gray-900 sm:pl-0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
isPending
<span class="token tag"><span class="token punctuation"></</span>td<span class="token punctuation">></span></span>
<span class="token tag"><span class="token punctuation"><</span>td
<span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>p-4 text-sm whitespace-nowrap text-gray-500<span class="token punctuation">"</span></span>
<span class="token attr-name">:class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>randomResponseData?.isPending ? 'bg-blue-500' : 'bg-gray-300'<span class="token punctuation">"</span></span>
<span class="token punctuation">></span></span><span class="token tag"><span class="token punctuation"></</span>td<span class="token punctuation">></span></span>
<span class="token tag"><span class="token punctuation"><</span>td <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>p-4 text-sm whitespace-nowrap text-gray-500<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
{{ randomResponseData?.isPending }}
<span class="token tag"><span class="token punctuation"></</span>td<span class="token punctuation">></span></span>
<span class="token tag"><span class="token punctuation"></</span>tr<span class="token punctuation">></span></span>
<span class="token tag"><span class="token punctuation"><</span>tr <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>divide-x divide-gray-200<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token punctuation"><</span>td <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>py-4 pr-4 pl-4 text-sm font-medium whitespace-nowrap text-gray-900 sm:pl-0<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
data
<span class="token tag"><span class="token punctuation"></</span>td<span class="token punctuation">></span></span>
<span class="token tag"><span class="token punctuation"><</span>td
<span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>p-4 text-sm whitespace-nowrap text-gray-500<span class="token punctuation">"</span></span>
<span class="token attr-name">:class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>randomResponseData?.data ? 'bg-green-500' : 'bg-gray-300'<span class="token punctuation">"</span></span>
<span class="token punctuation">></span></span><span class="token tag"><span class="token punctuation"></</span>td<span class="token punctuation">></span></span>
<span class="token tag"><span class="token punctuation"><</span>td <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>p-4 text-sm whitespace-nowrap text-gray-500<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
{{ unref(randomResponseData?.data)?.msg }}
<span class="token tag"><span class="token punctuation"></</span>td<span class="token punctuation">></span></span>
<span class="token tag"><span class="token punctuation"></</span>tr<span class="token punctuation">></span></span>
在这些tr标签中,您可以看到模板根据来自可组合项的状态渲染不同的内容。
结论
可组合项是 Vue 3 中非常有用的工具。随着项目规模和范围的增长,了解如何以及何时使用可组合项可以长期提高项目的可维护性。
关键是确定何时需要跨组件重用状态逻辑,然后将其提取到结构良好的可组合中,以正确处理边缘情况。
如需更完整地查看代码,可下载附件。

评论(0)