Common Vue2 Code Smells and How to Refactor Them
This article examines typical Vue2 code‑smell patterns—such as chaotic project structures, confusing naming conventions, oversized components, complex expressions, repetitive markup, tangled conditional logic, hard‑coded values, overused mixins, missing component names, and lack of comments—and provides concrete refactoring strategies to improve maintainability and readability.
Introduction – Vue’s options‑based API often leads to “code‑mountain” (屎山) problems; the article lists common pitfalls and how to address them.
1. Directory Chaos – Projects may contain duplicate folders like src/views and src/pages or both api and services. Consolidating similar directories reduces navigation overhead.
src/<br/>├── App.vue<br/>├── api<br/>├── components<br/>├── constants<br/>├── main.js<br/>├── pages<br/>├── router<br/>├── services<br/>├── utils<br/>│ └── hash.js<br/>└── views2. Weird Naming Conventions – Using full‑pinyin, initials, mixed Chinese‑English, or arbitrary abbreviations (e.g., dazhe.vue, dz.vue) makes component discovery difficult. The recommendation is to name components with clear English words.
3. Undivided Components – Vue single‑file components can become thousands of lines, violating the Single Responsibility Principle.
<template>…</template><br/><script>…</script><br/><style>…</style>4. Complex Expressions – Overly long class bindings and v‑if conditions obscure intent.
<div class="files" :class="{ disabled: !isAllowRead && hasNotPassed && aaa && (bbb || ccc) }" @click="toDetail()"><br/> <a/><br/> <b v‑if="!isAllowRead && hasNotPassed && aaa && (bbb || ccc)"/><br/></div>Refactor by moving logic to a computed property:
<div class="files" :class="{ disabled: isFileDisabled }" @click="toDetail()"><br/> <a/><br/> <b v‑if="isFileDisabled"/><br/></div><br/><br/>export default {<br/> computed: {<br/> isFileDisabled() {<br/> return !isAllowRead && hasNotPassed && aaa && (bbb || ccc);<br/> }<br/> }<br/>}5. Repeated Nodes – Repeating similar <span> elements can be replaced with a v‑for loop.
<div><br/> <span v‑for="item in textConfigs" :key="item.valueKey">{{ response[item.valueKey] }}</span><br/></div><br/><br/>data() {<br/> return {<br/> textConfigs: [<br/> { label: "性别", valueKey: "name" },<br/> { label: "年龄", valueKey: "age" },<br/> { label: "性别", valueKey: "gender" },<br/> { label: "身高", valueKey: "height" },<br/> { label: "体重", valueKey: "weight" },<br/> { label: "爱好", valueKey: "habit" }<br/> ]<br/> };<br/>}6. If‑Else Chains – Long if‑else blocks for validation become hard to extend. Using a validator array decouples messages from logic.
const validators = [<br/> { message: "用户名不能为空", required: true, key: "username" },<br/> { message: "密码不能为空", required: true, key: "password" },<br/> { message: "手机号不能为空", required: true, key: "phoneNumber" }<br/>];<br/><br/>export default {<br/> methods: {<br/> validator(values) {<br/> const result = validators.some(el => {<br/> if (el.required && !values[el.key]) {<br/> this.$message.error(el.message);<br/> return true;<br/> }<br/> });<br/> return result;<br/> },<br/> submit(values) {<br/> if (this.validator(values)) return;<br/> // …call API<br/> }<br/> }<br/>};7. Backend Parameter Handling – Manually assigning each field is verbose; destructuring simplifies the code.
// before<br/>handleParams() {<br/> const params = {};<br/> params.id = this.formItem.id;<br/> params.startDate = this.formItem.startDate.format("YYYY-MM-DD");<br/> // …many lines<br/>}<br/><br/>// after<br/>handleParams() {<br/> const { startDate, endDate, price, ...params } = this.formItem;<br/> params.startDate = startDate.format("YYYY-MM-DD");<br/> params.endDate = endDate.format("YYYY-MM-DD");<br/> params.price = price.toString();<br/> // …remaining fields stay in params<br/>}8. Hard‑Coding – Repeating literal values (e.g., type === 1) should be replaced by constants.
// constants.js<br/>export const GOODS_TYPE = { good: 1, bad: 0 };9. Mixins Overuse – Multiple mixins can cause data collisions and obscure origins. Prefer composition or dynamic mixins when necessary.
// a.mixin.js<br/>export default { data() { return { username: "", password: "", age: 18 }; }, created() { this.fetchUserInfo(); }, methods: { fetchUserInfo() {} } };
<br/>
// b.mixin.js<br/>export default { data() { return { height: "", weight: "" }; }, created() { this.fetchBodyFat(); }, methods: { fetchBodyFat() {} } };
<br/>
// c.vue<br/>import a from "./a.mixin";
import b from "./b.mixin";
export default { mixins: [a, b], data() { return { degree: DEGREEMAP.doctor }; }, methods: { log() { if (this.age < 30 && this.height > 180 && this.degree === DEGREEMAP.doctor) { alert("真牛!"); } } } };10. Unused Code – Leaving dead code or duplicate files inflates the codebase and confuses newcomers; remove or comment out obsolete parts.
11. Inconsistent Class Naming – Mixing kebab‑case, snake_case, and PascalCase leads to style inconsistency. Adopt a single convention such as BEM.
#id {}<br/>#App {}<br/>.AppBuy {}<br/>.app-buy {}<br/>.app_buy {}<br/>.App_Buy {}12. Repetitive Styles – Duplicate CSS rules increase bundle size; extract common utilities into shared classes.
.a { display: flex; align-items: center; justify-content: center; }<br/>.b { display: flex; align-items: center; justify-content: center; font-size: 16px; color: red; }13. Missing Comments – Lack of documentation makes the codebase a “black box”; brief comments greatly aid future maintenance.
14. Components Without name – Omitting the name option causes identical names in Vue DevTools, hindering debugging. Always set name to match the file name.
Reference Articles – The author cites the 2021 Alibaba Front‑End Code Specification, design patterns for front‑end, BEM naming, and explanations of hard‑coding.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
