从一个需求出发如何更优雅写代码
刀刀
0字
0分钟
2026/8/16
需求分析
需求如下:
- 四个商品推荐栏目,基本样式一致,但文字部分不同。
- 颜色和排行类型固定,如热销排行固定第一个红色、第二个橘色,利润排行固定粉色,低价好物固定灰色。
- 数据统一返回。循环展示四个商品栏目,数据结构中只有栏目名称、栏目商品售价和利润率。

后端返回的数据通过一个接口返回数组对象,包含标题、商品价格、商品利润和商品地址。
数据结构
js
let data = [
{
title: '热销排行',
goodsData: [
{
price: '100.0',
profit: 30,
src: '',
},
{
price: '78.0',
profit: 20,
src: '',
},
],
},
{
title: '利润排行',
goodsData: [
{
price: '30.0',
profit: 130,
src: '',
},
{
price: '333.0',
profit: 55,
src: '',
},
],
},
{
title: '热门主题',
goodsData: [
{
price: '137.0',
src: '',
},
{
price: '78.0',
src: '',
},
],
},
{
title: '低价好物',
goodsData: [
{
price: '100.0',
profit: 30,
src: '',
},
{
price: '78.0',
profit: 20,
src: '',
},
],
},
]思路分析
首先通过 v-for 渲染出四个模块。
html
<div v-for="(item, index) in data" :key="index">
<div>{{ item.title }}</div>
<div>
<div v-for="(goods, i) in item.goodsData" :key="i">
<el-image src="" />
</div>
</div>
</div>接下来分析栏目如何处理渲染,分几种情况:是否渲染、渲染的颜色、渲染的文本等。
处理方案有以下思路:
- 四个栏目写成四种文本,通过
v-if判断显示哪个 - 文本部分通过函数返回不同样式
- 利用 JSX 根据不同栏目渲染不同样式
- 修改源数据
实现
v-if
首先看第一种:通过 v-if 判断文本和索引,渲染不同内容和样式。
html
<div v-for="(item, index) in data" :key="index">
<div>{{ item.title }}</div>
<div>
<div v-for="(goods, i) in item.goodsData" :key="i">
<el-image src="" />
<div
v-if="item.title ==='热销排行' && i === 0"
style="background: red; color: #fff;"
>
Top1
</div>
<div
v-if="item.title ==='热销排行' && i === 1"
style="background: orange; color: #fff;"
>
Top2
</div>
<div
v-if="item.title ==='利润排行'"
style="background: pink; color: #000;"
>
{{ goods.profit }}%
</div>
<div
v-if="item.title ==='低价好物'"
style="background: #555; color: #000;"
>
{{ goods.price }}
</div>
</div>
</div>
</div>该方式简单直接,缺点是 HTML 代码量多且冗余,后续不易维护,不推荐使用。
函数返回
div 盒子内容一致,可通过一个函数统一返回,减少代码量。
vue
<script setup>
const createStyle = (title, index) => {
console.log('执行了该方法')
let styleObj = {}
switch (title) {
case '热销排行':
styleObj.color = '#fff'
if (index === 0) styleObj.background = 'red'
else styleObj.background = 'orange'
break
case '利润排行':
styleObj.color = '#000'
styleObj.background = 'pink'
break
case '低价好物':
styleObj.color = '#000'
styleObj.background = 'gray'
break
case '热门主题':
styleObj.display = 'none'
break
default:
break
}
return styleObj
}
const createText = (title, index, good) => {
console.log('执行了该方法')
let txt = ''
switch (title) {
case '热销排行':
if (index === 0) txt = 'Top1'
else txt = 'Top2'
break
case '利润排行':
txt = good.profit + '%'
break
case '低价好物':
txt = good.price
break
default:
break
}
return txt
}
</script>
<template>
<div
@click="
() => {
num += 1
}
"
>
点击事件触发,createStyle与createText函数依旧触发:{{ num }}
</div>
<div v-for="(item, index) in data" :key="index">
<div>{{ item.title }}</div>
<div>
<div v-for="(goods, i) in item.goodsData" :key="i">
<el-image src="" />
<div :style="createStyle(item.title, i)">
{{ createText(item.title, i, goods) }}
</div>
</div>
</div>
</div>
</template>虽然 template 内的代码量减少了,但是函数被执行了多次,且在操作 num 的点击事件时,因为该Vue文件的渲染依赖于变量 num ,在 num 发生变化时,整个组件都会触发更新,因此函数方法都会重新执行,造成一定的性能压力。
JSX
vue
<script setup lang="jsx">
function TextComponent({ title, index, goods }) {
console.log('执行了。')
let styleObj = {}
let text = ''
switch (title) {
case '热销排行':
if (index === 0) {
styleObj.background = 'red'
styleObj.color = '#fff'
text = 'Top1'
} else {
styleObj.background = 'orange'
styleObj.color = '#fff'
text = 'Top2'
}
break
case '利润排行':
styleObj.background = 'pink'
styleObj.color = '#000'
text = goods.profit + '%'
break
case '热门主题':
styleObj.display = 'none'
break
case '低价好物':
styleObj.background = 'gray'
styleObj.color = '#000'
text = goods.price
break
default:
break
}
return <div style={styleObj}>{text}</div>
}
</script>
<template>
<div
@click="
() => {
num += 1
}
"
>
{{ num }}
</div>
<div v-for="(item, index) in data" :key="index">
<div>{{ item.title }}</div>
<div>
<div v-for="(goods, i) in item.goodsData" :key="i">
<el-image src="" />
<TextComponent
:title="item.title"
:index="i"
:goods="goods"
></TextComponent>
</div>
</div>
</div>
</template>该方法仅在初始时执行了八次,后续修改无关变量(如 num)时不会额外触发,性能更佳。
代码层面,还可使用策略模式进一步简化。
jsx
function TextComponent({ title, index, goods }) {
console.log('执行了。')
let styleObj = {}
let text = ''
let emnu = {
热销排行: function () {
if (index === 0) {
styleObj.background = 'red'
styleObj.color = '#fff'
text = 'Top1'
} else {
styleObj.background = 'orange'
styleObj.color = '#fff'
text = 'Top2'
}
},
利润排行: function () {
styleObj.background = 'pink'
styleObj.color = '#000'
text = goods.profit + '%'
},
热门主题: function () {
styleObj.display = 'none'
},
低价好物: function () {
styleObj.background = 'gray'
styleObj.color = '#000'
text = goods.price
},
}
obj[title]()
return <div style={styleObj}>{text}</div>
}修改源数据
通过修改源数据统一字段,渲染时直接渲染无需判断。
vue
<script setup>
data.forEach((item, index) => {
switch (item.title) {
case '热销排行':
item.goodsData.forEach((goods, i) => {
goods.styleObj = {
background: 'red',
color: '#fff',
}
goods.text = 'Top1'
if (i !== 0) {
goods.styleObj.background = 'orange'
goods.text = 'Top2'
}
})
break
// ...省略
default:
break
}
})
</script>
<template>
<div v-for="(item, index) in data" :key="index">
<div>{{ item.title }}</div>
<div>
<div v-for="(goods, i) in item.goodsData" :key="i">
<el-image src="" />
<div :style="goods.styleObj">{{ goods.text }}</div>
</div>
</div>
</div>
</template>比较
以上几种方法各有优缺点:
- 函数方法在组件数据变化引发更新时,等于组件重新执行渲染,造成性能浪费
- JSX 要求使用者了解相关内容,可读性较差
- 源数据改写在数据复杂时较麻烦,若该数据还需传回后端则需取出额外内容
总体效果
跳转预览:点击跳转