插槽实现列表项个性化定制的核心是将行数据通过作用域插槽暴露给父组件,支持默认插槽、具名插槽及动态插槽名三种方式,且插槽内容在父组件作用域编译。

用插槽实现列表项的个性化模板定制,核心是把每一行的渲染逻辑“交出去”,让使用者决定怎么展示某一行的数据。关键不在列表本身,而在如何把当前行的数据暴露给父组件,并通过插槽接收自定义结构。
默认插槽 + 作用域插槽传递行数据
最常用的方式是结合作用域插槽:子组件在遍历数据时,把当前 row、index 等上下文作为插槽属性传出去,父组件用 v-slot 接收并自由组织 DOM。
- 子组件(如
MyList.vue)中这样写:
<template>
<div class="list">
<div v-for="(item, idx) in list" :key="idx" class="item">
<slot :row="item" :index="idx"></slot>
</div>
</div>
</template>
- 父组件使用时,用
v-slot="{ row, index }"解构出数据,任意写模板:
<MyList :list="users">
<template #default="{ row, index }">
<div class="user-card">
<span>{{ index + 1 }}.</span>
<strong>{{ row.name }}</strong>
<small>{{ row.email }}</small>
<button @click="edit(row)">编辑</button>
</div>
</template>
</MyList>
立即学习“前端免费学习笔记(深入)”;
具名插槽区分不同区域
如果一行里有标题区、操作区、状态区等固定位置,适合用具名插槽分工协作。
- 子组件定义多个命名插槽:
<slot name="header" :row="row"></slot>
<slot name="body" :row="row"></slot>
<slot name="actions" :row="row"></slot>
- 父组件按需填充:
<MyList :list="orders">
<template #header="{ row }"><h3>订单 #{{ row.id }}</h3></template>
<template #body="{ row }"><p>{{ row.desc }}</p></template>
<template #actions="{ row }">
<button @click="confirm(row)">确认</button>
<button @click="cancel(row)">取消</button>
</template>
</MyList>
配合动态插槽名适配多列场景
当列表列是动态配置的(比如后台返回字段),可用 v-slot:[`cell-${col.prop}`] 实现按列名精准接管渲染。
- 子组件中为每列生成带 prop 名的插槽:
<el-table-column v-for="col in columns" :key="col.prop">
<template #default="{ row }">
<slot :name="`cell-${col.prop}`" :row="row">{{ row[col.prop] }}</slot>
</template>
</el-table-column>
- 父组件只覆盖需要定制的列:
<MyTable :columns="cols" :data="rows">
<template #["cell-status"]="{ row }">
<span :class="'status-' + row.status">{{ statusText[row.status] }}</span>
</template>
<template #["cell-actions"]="{ row }">
<el-button size="small" @click="handleDelete(row)">删除</el-button>
</template>
</MyTable>
注意作用域与编译时机
插槽内容始终在父组件作用域中编译,所以能直接访问父组件的 data、methods、computed;而子组件内部逻辑(比如 row 的计算属性)不能直接在插槽里用——除非你把它作为插槽属性传出去。
- 错误写法:在插槽里写
{{ computedValue }}却没在父组件定义 - 正确做法:子组件把
formattedTime作为插槽属性传:<slot :formatted-time="formatTime(row.time)"></slot> - 父组件就能安全使用:
{{ formattedTime }}


















