@pythoughts/vue-skills-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/index.mjs +139 -0
- package/package.json +34 -0
- package/skills/create-adaptable-composable/SKILL.md +76 -0
- package/skills/vue-best-practices/SKILL.md +154 -0
- package/skills/vue-best-practices/references/animation-class-based-technique.md +254 -0
- package/skills/vue-best-practices/references/animation-state-driven-technique.md +291 -0
- package/skills/vue-best-practices/references/component-async.md +97 -0
- package/skills/vue-best-practices/references/component-data-flow.md +350 -0
- package/skills/vue-best-practices/references/component-fallthrough-attrs.md +174 -0
- package/skills/vue-best-practices/references/component-keep-alive.md +137 -0
- package/skills/vue-best-practices/references/component-slots.md +216 -0
- package/skills/vue-best-practices/references/component-suspense.md +228 -0
- package/skills/vue-best-practices/references/component-teleport.md +108 -0
- package/skills/vue-best-practices/references/component-transition-group.md +128 -0
- package/skills/vue-best-practices/references/component-transition.md +125 -0
- package/skills/vue-best-practices/references/composables.md +290 -0
- package/skills/vue-best-practices/references/directives.md +162 -0
- package/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +159 -0
- package/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +182 -0
- package/skills/vue-best-practices/references/perf-virtualize-large-lists.md +187 -0
- package/skills/vue-best-practices/references/plugins.md +166 -0
- package/skills/vue-best-practices/references/reactivity.md +346 -0
- package/skills/vue-best-practices/references/render-functions.md +201 -0
- package/skills/vue-best-practices/references/sfc.md +310 -0
- package/skills/vue-best-practices/references/state-management.md +135 -0
- package/skills/vue-best-practices/references/updated-hook-performance.md +187 -0
- package/skills/vue-debug-guides/SKILL.md +205 -0
- package/skills/vue-debug-guides/reference/animation-key-for-rerender.md +160 -0
- package/skills/vue-debug-guides/reference/animation-transitiongroup-performance.md +241 -0
- package/skills/vue-debug-guides/reference/async-component-error-handling.md +115 -0
- package/skills/vue-debug-guides/reference/async-component-keepalive-ref-issue.md +112 -0
- package/skills/vue-debug-guides/reference/async-component-suspense-control.md +84 -0
- package/skills/vue-debug-guides/reference/async-component-vue-router.md +109 -0
- package/skills/vue-debug-guides/reference/attrs-event-listener-merging.md +205 -0
- package/skills/vue-debug-guides/reference/checkbox-true-false-value-form-submission.md +118 -0
- package/skills/vue-debug-guides/reference/cleanup-side-effects.md +172 -0
- package/skills/vue-debug-guides/reference/click-events-on-components.md +180 -0
- package/skills/vue-debug-guides/reference/component-naming-conflicts.md +159 -0
- package/skills/vue-debug-guides/reference/component-ref-requires-defineexpose.md +176 -0
- package/skills/vue-debug-guides/reference/composable-avoid-hidden-side-effects.md +208 -0
- package/skills/vue-debug-guides/reference/composable-call-location-restrictions.md +141 -0
- package/skills/vue-debug-guides/reference/composable-naming-return-pattern.md +139 -0
- package/skills/vue-debug-guides/reference/composable-tovalue-inside-watcheffect.md +182 -0
- package/skills/vue-debug-guides/reference/composition-api-not-functional-programming.md +120 -0
- package/skills/vue-debug-guides/reference/composition-api-script-setup-async-context.md +203 -0
- package/skills/vue-debug-guides/reference/composition-api-vs-react-hooks-differences.md +156 -0
- package/skills/vue-debug-guides/reference/computed-array-mutation.md +148 -0
- package/skills/vue-debug-guides/reference/computed-conditional-dependencies.md +147 -0
- package/skills/vue-debug-guides/reference/computed-no-parameters.md +159 -0
- package/skills/vue-debug-guides/reference/computed-no-side-effects.md +107 -0
- package/skills/vue-debug-guides/reference/computed-return-value-readonly.md +160 -0
- package/skills/vue-debug-guides/reference/configure-app-before-mount.md +89 -0
- package/skills/vue-debug-guides/reference/declare-emits-for-documentation.md +212 -0
- package/skills/vue-debug-guides/reference/define-expose-before-await.md +192 -0
- package/skills/vue-debug-guides/reference/define-model-default-value-sync.md +139 -0
- package/skills/vue-debug-guides/reference/defineEmits-must-be-top-level.md +164 -0
- package/skills/vue-debug-guides/reference/defineEmits-no-runtime-and-type-mixed.md +170 -0
- package/skills/vue-debug-guides/reference/definemodel-object-mutation-no-emit.md +148 -0
- package/skills/vue-debug-guides/reference/dom-update-timing-nexttick.md +90 -0
- package/skills/vue-debug-guides/reference/dynamic-argument-constraints.md +146 -0
- package/skills/vue-debug-guides/reference/dynamic-component-registration-vite.md +147 -0
- package/skills/vue-debug-guides/reference/event-modifier-order-matters.md +101 -0
- package/skills/vue-debug-guides/reference/exact-modifier-for-precise-shortcuts.md +155 -0
- package/skills/vue-debug-guides/reference/fallthrough-attrs-overwrite-vue3.md +159 -0
- package/skills/vue-debug-guides/reference/in-dom-template-parsing-caveats.md +149 -0
- package/skills/vue-debug-guides/reference/inheritattrs-false-for-wrapper-components.md +230 -0
- package/skills/vue-debug-guides/reference/keepalive-router-nested-double-mount.md +222 -0
- package/skills/vue-debug-guides/reference/keepalive-transition-memory-leak.md +144 -0
- package/skills/vue-debug-guides/reference/keyup-modifier-timing.md +137 -0
- package/skills/vue-debug-guides/reference/lifecycle-dom-access-timing.md +216 -0
- package/skills/vue-debug-guides/reference/lifecycle-hooks-synchronous-registration.md +156 -0
- package/skills/vue-debug-guides/reference/lifecycle-ssr-awareness.md +184 -0
- package/skills/vue-debug-guides/reference/local-components-not-in-descendants.md +151 -0
- package/skills/vue-debug-guides/reference/mount-return-value.md +88 -0
- package/skills/vue-debug-guides/reference/multi-root-component-class-attrs.md +93 -0
- package/skills/vue-debug-guides/reference/native-event-collision-with-emits.md +162 -0
- package/skills/vue-debug-guides/reference/no-passive-with-prevent.md +141 -0
- package/skills/vue-debug-guides/reference/no-v-if-with-v-for.md +136 -0
- package/skills/vue-debug-guides/reference/perf-computed-object-stability.md +157 -0
- package/skills/vue-debug-guides/reference/perf-props-stability-update-optimization.md +140 -0
- package/skills/vue-debug-guides/reference/plugin-global-properties-sparingly.md +109 -0
- package/skills/vue-debug-guides/reference/plugin-install-before-mount.md +124 -0
- package/skills/vue-debug-guides/reference/plugin-prefer-provide-inject-over-global-properties.md +120 -0
- package/skills/vue-debug-guides/reference/plugin-typescript-type-augmentation.md +157 -0
- package/skills/vue-debug-guides/reference/prop-defineprops-scope-limitation.md +161 -0
- package/skills/vue-debug-guides/reference/provide-inject-debugging-challenges.md +203 -0
- package/skills/vue-debug-guides/reference/provide-inject-default-value-factory.md +244 -0
- package/skills/vue-debug-guides/reference/provide-inject-reactivity-not-automatic.md +226 -0
- package/skills/vue-debug-guides/reference/provide-inject-synchronous-setup.md +235 -0
- package/skills/vue-debug-guides/reference/reactive-destructuring.md +89 -0
- package/skills/vue-debug-guides/reference/reactivity-debugging-hooks.md +132 -0
- package/skills/vue-debug-guides/reference/reactivity-markraw-for-non-reactive.md +149 -0
- package/skills/vue-debug-guides/reference/reactivity-proxy-identity-hazard.md +96 -0
- package/skills/vue-debug-guides/reference/reactivity-same-tick-batching.md +166 -0
- package/skills/vue-debug-guides/reference/ref-value-access.md +61 -0
- package/skills/vue-debug-guides/reference/refs-in-collections-need-value.md +81 -0
- package/skills/vue-debug-guides/reference/render-function-avoid-internal-vnode-properties.md +151 -0
- package/skills/vue-debug-guides/reference/render-function-vnodes-must-be-unique.md +133 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-h-import-vue3.md +148 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-return-from-setup.md +148 -0
- package/skills/vue-debug-guides/reference/rendering-render-function-slots-as-functions.md +168 -0
- package/skills/vue-debug-guides/reference/rendering-resolve-component-for-string-names.md +231 -0
- package/skills/vue-debug-guides/reference/select-initial-value-ios-bug.md +91 -0
- package/skills/vue-debug-guides/reference/self-referencing-component-name.md +157 -0
- package/skills/vue-debug-guides/reference/sfc-named-exports-forbidden.md +184 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-child-component-styling.md +156 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-dynamic-content.md +193 -0
- package/skills/vue-debug-guides/reference/sfc-scoped-css-slot-content.md +242 -0
- package/skills/vue-debug-guides/reference/sfc-script-setup-reactivity.md +195 -0
- package/skills/vue-debug-guides/reference/slot-forwarding-to-child-components.md +143 -0
- package/skills/vue-debug-guides/reference/slot-implicit-default-content.md +155 -0
- package/skills/vue-debug-guides/reference/slot-name-reserved-prop.md +109 -0
- package/skills/vue-debug-guides/reference/slot-named-scoped-explicit-default.md +95 -0
- package/skills/vue-debug-guides/reference/slot-render-scope-parent-only.md +135 -0
- package/skills/vue-debug-guides/reference/slot-v-slot-on-components-or-templates-only.md +122 -0
- package/skills/vue-debug-guides/reference/ssr-hydration-mismatch-causes.md +280 -0
- package/skills/vue-debug-guides/reference/ssr-platform-specific-apis.md +256 -0
- package/skills/vue-debug-guides/reference/state-ssr-cross-request-pollution.md +276 -0
- package/skills/vue-debug-guides/reference/suspense-no-builtin-error-handling.md +127 -0
- package/skills/vue-debug-guides/reference/suspense-ssr-hydration-issues.md +159 -0
- package/skills/vue-debug-guides/reference/tailwind-dynamic-class-generation.md +144 -0
- package/skills/vue-debug-guides/reference/teleport-scoped-styles-limitation.md +191 -0
- package/skills/vue-debug-guides/reference/teleport-ssr-hydration.md +152 -0
- package/skills/vue-debug-guides/reference/teleport-target-must-exist.md +113 -0
- package/skills/vue-debug-guides/reference/template-expressions-restrictions.md +114 -0
- package/skills/vue-debug-guides/reference/template-functions-no-side-effects.md +187 -0
- package/skills/vue-debug-guides/reference/template-ref-null-with-v-if.md +123 -0
- package/skills/vue-debug-guides/reference/template-ref-unwrapping-top-level.md +104 -0
- package/skills/vue-debug-guides/reference/template-ref-v-for-order.md +172 -0
- package/skills/vue-debug-guides/reference/textarea-no-interpolation.md +72 -0
- package/skills/vue-debug-guides/reference/transition-group-flip-inline-elements.md +152 -0
- package/skills/vue-debug-guides/reference/transition-group-move-animation-position-absolute.md +130 -0
- package/skills/vue-debug-guides/reference/transition-group-no-default-wrapper-vue3.md +152 -0
- package/skills/vue-debug-guides/reference/transition-js-hooks-done-callback.md +251 -0
- package/skills/vue-debug-guides/reference/transition-nested-duration.md +182 -0
- package/skills/vue-debug-guides/reference/transition-reusable-scoped-style.md +245 -0
- package/skills/vue-debug-guides/reference/transition-router-view-appear.md +193 -0
- package/skills/vue-debug-guides/reference/transition-type-when-mixed.md +172 -0
- package/skills/vue-debug-guides/reference/transition-unmount-hook-timing.md +149 -0
- package/skills/vue-debug-guides/reference/ts-defineprops-boolean-default-false.md +225 -0
- package/skills/vue-debug-guides/reference/ts-defineprops-imported-types-limitations.md +281 -0
- package/skills/vue-debug-guides/reference/ts-event-handler-explicit-typing.md +213 -0
- package/skills/vue-debug-guides/reference/ts-reactive-no-generic-argument.md +196 -0
- package/skills/vue-debug-guides/reference/ts-shallowref-for-dynamic-components.md +218 -0
- package/skills/vue-debug-guides/reference/ts-template-ref-null-handling.md +249 -0
- package/skills/vue-debug-guides/reference/ts-template-type-casting.md +214 -0
- package/skills/vue-debug-guides/reference/ts-withdefaults-mutable-factory-function.md +171 -0
- package/skills/vue-debug-guides/reference/undeclared-emits-double-firing.md +195 -0
- package/skills/vue-debug-guides/reference/use-template-ref-vue35.md +158 -0
- package/skills/vue-debug-guides/reference/v-else-must-follow-v-if.md +136 -0
- package/skills/vue-debug-guides/reference/v-for-component-props.md +95 -0
- package/skills/vue-debug-guides/reference/v-for-computed-reverse-sort.md +86 -0
- package/skills/vue-debug-guides/reference/v-for-key-attribute.md +90 -0
- package/skills/vue-debug-guides/reference/v-for-range-starts-at-one.md +66 -0
- package/skills/vue-debug-guides/reference/v-if-null-check-order.md +171 -0
- package/skills/vue-debug-guides/reference/v-model-ignores-html-attributes.md +83 -0
- package/skills/vue-debug-guides/reference/v-model-ime-composition.md +83 -0
- package/skills/vue-debug-guides/reference/v-model-number-modifier-behavior.md +124 -0
- package/skills/vue-debug-guides/reference/v-show-template-limitation.md +124 -0
- package/skills/vue-debug-guides/reference/watch-async-cleanup.md +180 -0
- package/skills/vue-debug-guides/reference/watch-async-creation-memory-leak.md +176 -0
- package/skills/vue-debug-guides/reference/watch-deep-same-object-reference.md +165 -0
- package/skills/vue-debug-guides/reference/watch-flush-timing.md +189 -0
- package/skills/vue-debug-guides/reference/watch-reactive-property-getter.md +108 -0
- package/skills/vue-debug-guides/reference/watcheffect-async-dependency-tracking.md +173 -0
- package/skills/vue-debug-guides/reference/watcheffect-flush-post-for-refs.md +176 -0
- package/skills/vue-jsx-best-practices/SKILL.md +12 -0
- package/skills/vue-jsx-best-practices/reference/render-function-jsx-vue-vs-react.md +141 -0
- package/skills/vue-options-api-best-practices/SKILL.md +23 -0
- package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-lifecycle-hooks.md +95 -0
- package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-methods.md +68 -0
- package/skills/vue-options-api-best-practices/reference/stateful-methods-lifecycle.md +61 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-arrow-functions-validators.md +141 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-computed-return-types.md +192 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-proptype-complex-types.md +212 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-provide-inject-limitations.md +135 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-type-event-handlers.md +202 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-use-definecomponent.md +172 -0
- package/skills/vue-options-api-best-practices/reference/ts-strict-mode-options-api.md +197 -0
- package/skills/vue-pinia-best-practices/SKILL.md +21 -0
- package/skills/vue-pinia-best-practices/reference/pinia-no-active-pinia-error.md +248 -0
- package/skills/vue-pinia-best-practices/reference/pinia-setup-store-return-all-state.md +227 -0
- package/skills/vue-pinia-best-practices/reference/pinia-store-destructuring-breaks-reactivity.md +193 -0
- package/skills/vue-pinia-best-practices/reference/state-url-for-ephemeral-filters.md +238 -0
- package/skills/vue-pinia-best-practices/reference/state-use-pinia-for-large-apps.md +262 -0
- package/skills/vue-pinia-best-practices/reference/store-method-binding-parentheses.md +191 -0
- package/skills/vue-router-best-practices/SKILL.md +23 -0
- package/skills/vue-router-best-practices/reference/router-beforeenter-no-param-trigger.md +167 -0
- package/skills/vue-router-best-practices/reference/router-beforerouteenter-no-this.md +176 -0
- package/skills/vue-router-best-practices/reference/router-guard-async-await-pattern.md +227 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-infinite-loop.md +187 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-next-deprecated.md +150 -0
- package/skills/vue-router-best-practices/reference/router-param-change-no-lifecycle.md +181 -0
- package/skills/vue-router-best-practices/reference/router-simple-routing-cleanup.md +209 -0
- package/skills/vue-router-best-practices/reference/router-use-vue-router-for-production.md +183 -0
- package/skills/vue-testing-best-practices/SKILL.md +29 -0
- package/skills/vue-testing-best-practices/reference/async-component-testing.md +163 -0
- package/skills/vue-testing-best-practices/reference/teleport-testing-complexity.md +158 -0
- package/skills/vue-testing-best-practices/reference/testing-async-await-flushpromises.md +175 -0
- package/skills/vue-testing-best-practices/reference/testing-browser-vs-node-runners.md +208 -0
- package/skills/vue-testing-best-practices/reference/testing-component-blackbox-approach.md +144 -0
- package/skills/vue-testing-best-practices/reference/testing-composables-helper-wrapper.md +238 -0
- package/skills/vue-testing-best-practices/reference/testing-e2e-playwright-recommended.md +242 -0
- package/skills/vue-testing-best-practices/reference/testing-no-snapshot-only.md +197 -0
- package/skills/vue-testing-best-practices/reference/testing-pinia-store-setup.md +228 -0
- package/skills/vue-testing-best-practices/reference/testing-suspense-async-components.md +229 -0
- package/skills/vue-testing-best-practices/reference/testing-vitest-recommended-for-vue.md +204 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Checkbox true-value/false-value Not Submitted in Forms
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: true-value and false-value attributes don't affect form submission - unchecked boxes send nothing
|
|
5
|
+
type: capability
|
|
6
|
+
tags: [vue3, v-model, forms, checkbox, form-submission]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Checkbox true-value/false-value Not Submitted in Forms
|
|
10
|
+
|
|
11
|
+
**Impact: MEDIUM** - Vue's `true-value` and `false-value` attributes only affect the JavaScript binding, NOT the actual form submission. Unchecked checkboxes are never included in form submissions by browsers, regardless of `false-value`.
|
|
12
|
+
|
|
13
|
+
This is a browser limitation, not a Vue issue. If you need to submit one of two values (like "yes"/"no" or "active"/"inactive"), use radio buttons instead of a checkbox.
|
|
14
|
+
|
|
15
|
+
## Task Checklist
|
|
16
|
+
|
|
17
|
+
- [ ] Don't rely on `false-value` for form submissions - it won't be sent
|
|
18
|
+
- [ ] Use radio buttons when you need to submit one of exactly two values
|
|
19
|
+
- [ ] Remember `true-value`/`false-value` are for JavaScript state only
|
|
20
|
+
- [ ] For form submissions with custom values, handle the transformation server-side or in submit handler
|
|
21
|
+
|
|
22
|
+
**Problem - false-value not submitted:**
|
|
23
|
+
```html
|
|
24
|
+
<script setup>
|
|
25
|
+
import { ref } from 'vue'
|
|
26
|
+
|
|
27
|
+
const status = ref('no') // JavaScript value works correctly
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<form action="/api/update" method="POST">
|
|
32
|
+
<!-- PROBLEM: When unchecked, nothing is submitted for this field -->
|
|
33
|
+
<!-- Server receives no "status" field at all, not "no" -->
|
|
34
|
+
<input
|
|
35
|
+
type="checkbox"
|
|
36
|
+
v-model="status"
|
|
37
|
+
true-value="yes"
|
|
38
|
+
false-value="no"
|
|
39
|
+
name="status"
|
|
40
|
+
>
|
|
41
|
+
<label>Active</label>
|
|
42
|
+
|
|
43
|
+
<!-- status.value correctly shows "yes" or "no" in Vue -->
|
|
44
|
+
<!-- But form submission only sends "status=yes" when checked -->
|
|
45
|
+
<!-- When unchecked, "status" field is completely missing -->
|
|
46
|
+
</form>
|
|
47
|
+
</template>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Solution 1 - Use radio buttons for two-value submission:**
|
|
51
|
+
```html
|
|
52
|
+
<script setup>
|
|
53
|
+
import { ref } from 'vue'
|
|
54
|
+
|
|
55
|
+
const status = ref('no')
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<template>
|
|
59
|
+
<form action="/api/update" method="POST">
|
|
60
|
+
<!-- CORRECT: Radio buttons always submit a value -->
|
|
61
|
+
<label>
|
|
62
|
+
<input type="radio" v-model="status" value="yes" name="status">
|
|
63
|
+
Active
|
|
64
|
+
</label>
|
|
65
|
+
<label>
|
|
66
|
+
<input type="radio" v-model="status" value="no" name="status">
|
|
67
|
+
Inactive
|
|
68
|
+
</label>
|
|
69
|
+
|
|
70
|
+
<!-- Form always submits "status=yes" or "status=no" -->
|
|
71
|
+
</form>
|
|
72
|
+
</template>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Solution 2 - Handle in submit handler (for SPA/AJAX):**
|
|
76
|
+
```html
|
|
77
|
+
<script setup>
|
|
78
|
+
import { ref } from 'vue'
|
|
79
|
+
|
|
80
|
+
const isActive = ref(false)
|
|
81
|
+
|
|
82
|
+
async function submitForm() {
|
|
83
|
+
// Transform checkbox state to desired value before sending
|
|
84
|
+
const payload = {
|
|
85
|
+
status: isActive.value ? 'yes' : 'no'
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
await fetch('/api/update', {
|
|
89
|
+
method: 'POST',
|
|
90
|
+
body: JSON.stringify(payload)
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<template>
|
|
96
|
+
<!-- For AJAX submission, checkbox is fine - transform in handler -->
|
|
97
|
+
<input type="checkbox" v-model="isActive">
|
|
98
|
+
<label>Active</label>
|
|
99
|
+
|
|
100
|
+
<button @click="submitForm">Save</button>
|
|
101
|
+
</template>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Solution 3 - Hidden input fallback:**
|
|
105
|
+
```html
|
|
106
|
+
<template>
|
|
107
|
+
<form action="/api/update" method="POST">
|
|
108
|
+
<!-- Hidden input provides fallback value -->
|
|
109
|
+
<input type="hidden" name="status" value="no">
|
|
110
|
+
<!-- Checkbox overrides with "yes" when checked -->
|
|
111
|
+
<input type="checkbox" name="status" value="yes" v-model="isActive">
|
|
112
|
+
<label>Active</label>
|
|
113
|
+
</form>
|
|
114
|
+
</template>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Reference
|
|
118
|
+
- [Vue.js Form Input Bindings - Checkbox](https://vuejs.org/guide/essentials/forms.html#checkbox)
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Clean Up Event Listeners and Intervals in onUnmounted
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Failing to clean up side effects causes memory leaks and ghost event handlers
|
|
5
|
+
type: capability
|
|
6
|
+
tags: [vue3, lifecycle, memory-leak, event-listeners, intervals, cleanup]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Clean Up Event Listeners and Intervals in onUnmounted
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - Failing to clean up event listeners, intervals, timeouts, and subscriptions when a component unmounts causes memory leaks and ghost handlers that continue running, leading to performance degradation and subtle bugs in Single Page Applications.
|
|
12
|
+
|
|
13
|
+
When using custom events, timers, WebSocket connections, or third-party libraries, always clean up in `onUnmounted` (Composition API) or `unmounted` (Options API).
|
|
14
|
+
|
|
15
|
+
## Task Checklist
|
|
16
|
+
|
|
17
|
+
- [ ] Track all addEventListener calls and remove them in onUnmounted
|
|
18
|
+
- [ ] Clear all setInterval and setTimeout calls in onUnmounted
|
|
19
|
+
- [ ] Unsubscribe from external event emitters and observables
|
|
20
|
+
- [ ] Disconnect WebSocket connections and third-party library instances
|
|
21
|
+
- [ ] Use `onBeforeUnmount` if cleanup must happen before DOM removal
|
|
22
|
+
|
|
23
|
+
**Incorrect:**
|
|
24
|
+
```javascript
|
|
25
|
+
// Composition API - WRONG: No cleanup
|
|
26
|
+
import { onMounted } from 'vue'
|
|
27
|
+
|
|
28
|
+
export default {
|
|
29
|
+
setup() {
|
|
30
|
+
onMounted(() => {
|
|
31
|
+
// These keep running after component unmounts!
|
|
32
|
+
window.addEventListener('resize', handleResize)
|
|
33
|
+
setInterval(pollServer, 5000)
|
|
34
|
+
socket.on('message', handleMessage)
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
// Options API - WRONG: No cleanup
|
|
42
|
+
export default {
|
|
43
|
+
mounted() {
|
|
44
|
+
window.addEventListener('scroll', this.handleScroll)
|
|
45
|
+
this.timer = setInterval(this.refresh, 10000)
|
|
46
|
+
}
|
|
47
|
+
// Component unmounts, but listeners and timers persist!
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Correct:**
|
|
52
|
+
```javascript
|
|
53
|
+
// Composition API - CORRECT: Proper cleanup
|
|
54
|
+
import { onMounted, onUnmounted, ref } from 'vue'
|
|
55
|
+
|
|
56
|
+
export default {
|
|
57
|
+
setup() {
|
|
58
|
+
const intervalId = ref(null)
|
|
59
|
+
|
|
60
|
+
const handleResize = () => {
|
|
61
|
+
// handle resize
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const handleMessage = (msg) => {
|
|
65
|
+
// handle message
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
onMounted(() => {
|
|
69
|
+
window.addEventListener('resize', handleResize)
|
|
70
|
+
intervalId.value = setInterval(pollServer, 5000)
|
|
71
|
+
socket.on('message', handleMessage)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
onUnmounted(() => {
|
|
75
|
+
// Clean up everything!
|
|
76
|
+
window.removeEventListener('resize', handleResize)
|
|
77
|
+
|
|
78
|
+
if (intervalId.value) {
|
|
79
|
+
clearInterval(intervalId.value)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
socket.off('message', handleMessage)
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
// Options API - CORRECT: Proper cleanup
|
|
90
|
+
export default {
|
|
91
|
+
data() {
|
|
92
|
+
return {
|
|
93
|
+
timer: null
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
mounted() {
|
|
97
|
+
window.addEventListener('scroll', this.handleScroll)
|
|
98
|
+
this.timer = setInterval(this.refresh, 10000)
|
|
99
|
+
},
|
|
100
|
+
unmounted() {
|
|
101
|
+
window.removeEventListener('scroll', this.handleScroll)
|
|
102
|
+
if (this.timer) {
|
|
103
|
+
clearInterval(this.timer)
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
methods: {
|
|
107
|
+
handleScroll() { /* ... */ },
|
|
108
|
+
refresh() { /* ... */ }
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Using Composable Pattern for Auto-Cleanup
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
// Reusable composable with automatic cleanup
|
|
117
|
+
import { onMounted, onUnmounted } from 'vue'
|
|
118
|
+
|
|
119
|
+
export function useEventListener(target, event, handler) {
|
|
120
|
+
onMounted(() => {
|
|
121
|
+
target.addEventListener(event, handler)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
onUnmounted(() => {
|
|
125
|
+
target.removeEventListener(event, handler)
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function useInterval(callback, delay) {
|
|
130
|
+
let intervalId = null
|
|
131
|
+
|
|
132
|
+
onMounted(() => {
|
|
133
|
+
intervalId = setInterval(callback, delay)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
onUnmounted(() => {
|
|
137
|
+
if (intervalId) clearInterval(intervalId)
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Usage - cleanup is automatic
|
|
142
|
+
import { useEventListener, useInterval } from './composables'
|
|
143
|
+
|
|
144
|
+
export default {
|
|
145
|
+
setup() {
|
|
146
|
+
useEventListener(window, 'resize', handleResize)
|
|
147
|
+
useInterval(pollServer, 5000)
|
|
148
|
+
// No manual cleanup needed!
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## VueUse Alternative
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
// VueUse provides cleanup-aware composables
|
|
157
|
+
import { useEventListener, useIntervalFn } from '@vueuse/core'
|
|
158
|
+
|
|
159
|
+
export default {
|
|
160
|
+
setup() {
|
|
161
|
+
// Automatically cleaned up on unmount
|
|
162
|
+
useEventListener(window, 'resize', handleResize)
|
|
163
|
+
|
|
164
|
+
const { pause, resume } = useIntervalFn(pollServer, 5000)
|
|
165
|
+
// Also provides pause/resume controls
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Reference
|
|
171
|
+
- [Vue.js Lifecycle Hooks](https://vuejs.org/guide/essentials/lifecycle.html)
|
|
172
|
+
- [VueUse - useEventListener](https://vueuse.org/core/useEventListener/)
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Click Events on Custom Components Require Emit or Fallthrough
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Native click events on custom components won't work without proper emit declaration or attribute fallthrough
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, events, components, emit, click, migration]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Click Events on Custom Components Require Emit or Fallthrough
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - Unlike native HTML elements, custom Vue components don't automatically forward native DOM events like `click`. You must either emit the event explicitly, rely on attribute fallthrough to a single root element, or use the `.native` modifier (Vue 2 only, removed in Vue 3). This is a common source of confusion and migration issues.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Declare emitted events using `defineEmits` in child components
|
|
16
|
+
- [ ] Emit click events from child component when needed
|
|
17
|
+
- [ ] Understand that single-root components automatically forward attrs to root
|
|
18
|
+
- [ ] Remove `.native` modifier when migrating from Vue 2 to Vue 3
|
|
19
|
+
- [ ] For multi-root components, explicitly bind `$attrs` or emit events
|
|
20
|
+
|
|
21
|
+
**Incorrect:**
|
|
22
|
+
```html
|
|
23
|
+
<!-- WRONG: Expecting native click to work on custom component -->
|
|
24
|
+
<template>
|
|
25
|
+
<MyButton @click="handleClick">Click me</MyButton>
|
|
26
|
+
<!-- This may not work as expected! -->
|
|
27
|
+
</template>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```html
|
|
31
|
+
<!-- WRONG: Vue 2 .native modifier doesn't exist in Vue 3 -->
|
|
32
|
+
<template>
|
|
33
|
+
<MyButton @click.native="handleClick">Click me</MyButton>
|
|
34
|
+
<!-- Error in Vue 3: .native modifier removed -->
|
|
35
|
+
</template>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```html
|
|
39
|
+
<!-- WRONG: Multi-root component with no attr binding -->
|
|
40
|
+
<!-- MyButton.vue -->
|
|
41
|
+
<template>
|
|
42
|
+
<span>Icon</span>
|
|
43
|
+
<button>{{ label }}</button>
|
|
44
|
+
<!-- No root element to receive click! -->
|
|
45
|
+
</template>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Correct:**
|
|
49
|
+
```html
|
|
50
|
+
<!-- CORRECT: Child component emits the click event -->
|
|
51
|
+
<!-- MyButton.vue -->
|
|
52
|
+
<template>
|
|
53
|
+
<button @click="$emit('click', $event)">
|
|
54
|
+
<slot></slot>
|
|
55
|
+
</button>
|
|
56
|
+
</template>
|
|
57
|
+
|
|
58
|
+
<script setup>
|
|
59
|
+
defineEmits(['click'])
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<!-- Parent.vue -->
|
|
63
|
+
<template>
|
|
64
|
+
<MyButton @click="handleClick">Click me</MyButton>
|
|
65
|
+
</template>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<!-- CORRECT: Single root element with automatic fallthrough -->
|
|
70
|
+
<!-- MyButton.vue -->
|
|
71
|
+
<template>
|
|
72
|
+
<button>
|
|
73
|
+
<slot></slot>
|
|
74
|
+
</button>
|
|
75
|
+
<!-- @click from parent automatically falls through to button -->
|
|
76
|
+
</template>
|
|
77
|
+
|
|
78
|
+
<!-- Parent.vue -->
|
|
79
|
+
<template>
|
|
80
|
+
<MyButton @click="handleClick">Click me</MyButton>
|
|
81
|
+
</template>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```html
|
|
85
|
+
<!-- CORRECT: Multi-root component with explicit $attrs binding -->
|
|
86
|
+
<!-- MyButton.vue -->
|
|
87
|
+
<template>
|
|
88
|
+
<span>Icon</span>
|
|
89
|
+
<button v-bind="$attrs">
|
|
90
|
+
<slot></slot>
|
|
91
|
+
</button>
|
|
92
|
+
</template>
|
|
93
|
+
|
|
94
|
+
<script setup>
|
|
95
|
+
defineOptions({
|
|
96
|
+
inheritAttrs: false
|
|
97
|
+
})
|
|
98
|
+
</script>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Component Events Don't Bubble
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
// Important: Component-emitted events do NOT bubble
|
|
105
|
+
// You can only listen to events from direct children
|
|
106
|
+
|
|
107
|
+
// WRONG: Trying to catch grandchild events
|
|
108
|
+
<GrandParent @child-event="handle"> <!-- Won't receive! -->
|
|
109
|
+
<Parent>
|
|
110
|
+
<Child @click="$emit('child-event')" />
|
|
111
|
+
</Parent>
|
|
112
|
+
</GrandParent>
|
|
113
|
+
|
|
114
|
+
// CORRECT: Each level must relay the event
|
|
115
|
+
<GrandParent @child-event="handle">
|
|
116
|
+
<Parent @child-event="$emit('child-event', $event)">
|
|
117
|
+
<Child @click="$emit('child-event')" />
|
|
118
|
+
</Parent>
|
|
119
|
+
</GrandParent>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Vue 3 Native Event Behavior
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
// In Vue 3, if you declare an event in emits:
|
|
126
|
+
defineEmits(['click'])
|
|
127
|
+
|
|
128
|
+
// Then @click on the component ONLY listens to emitted events
|
|
129
|
+
// NOT native click events
|
|
130
|
+
|
|
131
|
+
// If you don't declare 'click' in emits:
|
|
132
|
+
defineEmits(['custom-event'])
|
|
133
|
+
|
|
134
|
+
// Then @click on single-root component will:
|
|
135
|
+
// 1. Fall through to root element as native listener
|
|
136
|
+
// 2. Fire on native click
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Composition API Emit Pattern
|
|
140
|
+
|
|
141
|
+
```vue
|
|
142
|
+
<script setup>
|
|
143
|
+
// Define what events this component emits
|
|
144
|
+
const emit = defineEmits(['click', 'update', 'delete'])
|
|
145
|
+
|
|
146
|
+
function handleClick(event) {
|
|
147
|
+
// Do component logic
|
|
148
|
+
processClick()
|
|
149
|
+
|
|
150
|
+
// Then emit to parent
|
|
151
|
+
emit('click', event)
|
|
152
|
+
}
|
|
153
|
+
</script>
|
|
154
|
+
|
|
155
|
+
<template>
|
|
156
|
+
<button @click="handleClick">
|
|
157
|
+
<slot></slot>
|
|
158
|
+
</button>
|
|
159
|
+
</template>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Migration from Vue 2
|
|
163
|
+
|
|
164
|
+
```html
|
|
165
|
+
<!-- Vue 2: Used .native for native events on components -->
|
|
166
|
+
<MyComponent @click.native="handleClick" />
|
|
167
|
+
|
|
168
|
+
<!-- Vue 3: Remove .native, ensure component handles the event -->
|
|
169
|
+
<MyComponent @click="handleClick" />
|
|
170
|
+
|
|
171
|
+
<!-- Make sure MyComponent either:
|
|
172
|
+
1. Has single root that receives fallthrough attrs
|
|
173
|
+
2. Explicitly emits 'click' event
|
|
174
|
+
3. Uses v-bind="$attrs" on intended element -->
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Reference
|
|
178
|
+
- [Vue.js Component Events](https://vuejs.org/guide/components/events.html)
|
|
179
|
+
- [Vue.js Fallthrough Attributes](https://vuejs.org/guide/components/attrs.html)
|
|
180
|
+
- [Vue 3 Migration - .native Modifier Removed](https://v3-migration.vuejs.org/breaking-changes/v-on-native-modifier-removed.html)
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Avoid Component Naming Conflicts Between Global and Local
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Naming conflicts cause unexpected component rendering and hard-to-debug issues
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, component-registration, naming-conflicts, global-local, debugging]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Avoid Component Naming Conflicts Between Global and Local
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - When a global component and a local component have the same name (or resolve to the same name due to casing differences), unexpected behavior occurs. The precedence rules can be confusing, and the wrong component may render silently without any error. This is particularly problematic when using third-party component libraries.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Use unique, prefixed names for global components (e.g., `BaseButton`, `AppHeader`)
|
|
16
|
+
- [ ] Check for naming conflicts when adding global components
|
|
17
|
+
- [ ] Explicitly alias local components if there's potential conflict
|
|
18
|
+
- [ ] When overriding third-party components, document and test thoroughly
|
|
19
|
+
|
|
20
|
+
**Incorrect:**
|
|
21
|
+
```javascript
|
|
22
|
+
// main.js
|
|
23
|
+
import { createApp } from 'vue'
|
|
24
|
+
import Button from './components/Button.vue'
|
|
25
|
+
|
|
26
|
+
const app = createApp(App)
|
|
27
|
+
app.component('Button', Button) // Global Button
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```vue
|
|
31
|
+
<!-- SomeComponent.vue -->
|
|
32
|
+
<script setup>
|
|
33
|
+
// This local Button might conflict with global Button
|
|
34
|
+
import Button from './local/Button.vue'
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<template>
|
|
38
|
+
<!-- Which Button renders? Behavior may be unexpected -->
|
|
39
|
+
<Button>Click me</Button>
|
|
40
|
+
</template>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```vue
|
|
44
|
+
<!-- Another confusing scenario -->
|
|
45
|
+
<script setup>
|
|
46
|
+
// Registering with camelCase
|
|
47
|
+
import MyButton from './MyButton.vue'
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<template>
|
|
51
|
+
<!-- Using kebab-case - might match a global 'my-button' instead -->
|
|
52
|
+
<my-button>Click</my-button>
|
|
53
|
+
</template>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Correct:**
|
|
57
|
+
```javascript
|
|
58
|
+
// main.js - use prefixes for global components
|
|
59
|
+
import { createApp } from 'vue'
|
|
60
|
+
import BaseButton from './components/BaseButton.vue'
|
|
61
|
+
import BaseIcon from './components/BaseIcon.vue'
|
|
62
|
+
|
|
63
|
+
const app = createApp(App)
|
|
64
|
+
app.component('BaseButton', BaseButton)
|
|
65
|
+
app.component('BaseIcon', BaseIcon)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```vue
|
|
69
|
+
<!-- SomeComponent.vue -->
|
|
70
|
+
<script setup>
|
|
71
|
+
// Local components have distinct names
|
|
72
|
+
import SubmitButton from './local/SubmitButton.vue'
|
|
73
|
+
</script>
|
|
74
|
+
|
|
75
|
+
<template>
|
|
76
|
+
<!-- No ambiguity - each name is unique -->
|
|
77
|
+
<BaseButton>Generic button</BaseButton>
|
|
78
|
+
<SubmitButton>Submit form</SubmitButton>
|
|
79
|
+
</template>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Explicit Aliasing for Clarity
|
|
83
|
+
|
|
84
|
+
When you intentionally want to override or have similar names, use explicit aliasing:
|
|
85
|
+
|
|
86
|
+
```vue
|
|
87
|
+
<script setup>
|
|
88
|
+
// Explicit alias to avoid confusion
|
|
89
|
+
import { default as LocalButton } from './Button.vue'
|
|
90
|
+
</script>
|
|
91
|
+
|
|
92
|
+
<template>
|
|
93
|
+
<LocalButton>Local version</LocalButton>
|
|
94
|
+
</template>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```vue
|
|
98
|
+
<!-- Options API with explicit component name -->
|
|
99
|
+
<script>
|
|
100
|
+
import ThirdPartyModal from 'some-library'
|
|
101
|
+
import CustomModal from './CustomModal.vue'
|
|
102
|
+
|
|
103
|
+
export default {
|
|
104
|
+
components: {
|
|
105
|
+
// Explicit names prevent ambiguity
|
|
106
|
+
LibraryModal: ThirdPartyModal,
|
|
107
|
+
CustomModal
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
</script>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Resolution Order
|
|
114
|
+
|
|
115
|
+
Understanding Vue's component resolution order helps debug issues:
|
|
116
|
+
|
|
117
|
+
1. **Local registration** takes precedence over global
|
|
118
|
+
2. **Exact case match** takes precedence over case-insensitive match
|
|
119
|
+
3. Self-referencing component name (file name) has lowest priority
|
|
120
|
+
|
|
121
|
+
```vue
|
|
122
|
+
<!-- If all exist: GlobalButton, local Button, and file is Button.vue -->
|
|
123
|
+
<script setup>
|
|
124
|
+
import Button from './Button.vue' // Local registration
|
|
125
|
+
</script>
|
|
126
|
+
|
|
127
|
+
<template>
|
|
128
|
+
<!-- Resolves to locally imported Button, not global -->
|
|
129
|
+
<Button />
|
|
130
|
+
</template>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Third-Party Library Conflicts
|
|
134
|
+
|
|
135
|
+
```vue
|
|
136
|
+
<script setup>
|
|
137
|
+
// Be explicit when using components from multiple libraries
|
|
138
|
+
import { Button as AntButton } from 'ant-design-vue'
|
|
139
|
+
import { Button as ElButton } from 'element-plus'
|
|
140
|
+
</script>
|
|
141
|
+
|
|
142
|
+
<template>
|
|
143
|
+
<AntButton>Ant Design</AntButton>
|
|
144
|
+
<ElButton>Element Plus</ElButton>
|
|
145
|
+
</template>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Naming Convention Strategy
|
|
149
|
+
|
|
150
|
+
| Component Type | Naming Pattern | Example |
|
|
151
|
+
|----------------|---------------|---------|
|
|
152
|
+
| Base/Global | `Base*` or `App*` prefix | `BaseButton`, `AppHeader` |
|
|
153
|
+
| Domain-specific | Domain prefix | `UserCard`, `ProductList` |
|
|
154
|
+
| Page components | `*Page` or `*View` suffix | `HomePage`, `UserView` |
|
|
155
|
+
| Layout components | `*Layout` suffix | `DefaultLayout`, `AdminLayout` |
|
|
156
|
+
|
|
157
|
+
## Reference
|
|
158
|
+
- [Vue.js Component Registration](https://vuejs.org/guide/components/registration.html)
|
|
159
|
+
- [GitHub Issue: Global component naming conflicts](https://github.com/vuejs/vue/issues/4434)
|