作用域插槽是Vue 2中父组件获取子组件内部数据并自定义渲染的核心机制,子组件通过v-bind在slot上绑定数据,父组件用v-slot解构接收并在自身作用域直接使用。
作用域插槽在 Vue 2 中是让父组件拿到子组件内部数据、实现自定义渲染的关键机制。它不是简单地“塞内容进去”,而是“带数据地交出渲染权”。
子组件负责发数据,父组件负责收数据并决定怎么画
子组件在 <slot> 标签上用 slot-scope(Vue 2.6 之前)或 v-bind(Vue 2.6+ 推荐)绑定变量,把内部状态、循环项、索引等“托付”给插槽。
Vue 2.5 及更早写法(已过时但需兼容时可见):
<slot :user="currentUser" :index="i" slot-scope="props"></slot>
Vue 2.6+ 正确写法(推荐):
<slot :user="currentUser" :index="i"></slot>
注意:这里没有 slot-scope,也不需要 props;绑定的是真实数据,不是占位符。
关键点:
: 或 v-bind: 绑定属性,比如 :user="xxx",否则父组件收不到<slot></slot> 是普通插槽,不带数据父组件用 v-slot(或简写 #default)解构接收,变量就在当前模板作用域里直接可用。
<ChildComponent :list="users"><template v-slot:default="{ user, index }"><div class="item"><strong>{{ user.name }}</strong><span>第 {{ index + 1 }} 位</span><small v-if="user.isAdmin">(管理员)</small></div></template></ChildComponent>
常见写法变体:
v-slot="{ user, index, isActive }"
v-slot="slotProps" → 用 {{ slotProps.user.name }}
v-slot:header="{ title }",对应子组件 <slot name="header" :title="pageTitle"></slot>
v-slot:default 或 #default,直接写在标签内会失效假设子组件只管请求和遍历用户数据,不关心怎么展示:
<!-- UserList.vue(子组件) --><template><ul class="user-list"><li v-for="(u, i) in users" :key="u.id"><slot :user="u" :index="i" :is-even="i % 2 === 0"></slot></li></ul></template>
父组件自由定制:
<UserList :users="data"><template #default="{ user, isEven }"><div :class="{ 'highlight': isEven }">? {{ user.name }} —— {{ user.email }}</div></template></UserList>
slot-scope 在 Vue 2.6+ 已废弃,混用会导致编译警告甚至不生效v-slot,哪怕子组件绑了数据,也拿不到——作用域插槽必须显式接收user 是响应式对象,父组件中修改 user.xxx 会同步影响子组件(除非深度冻结),但一般只读使用更安全ref 或 this.$refs.xxx.users 替代:耦合重、无法精准对应到某一项、非声明式、难维护本质上,作用域插槽是一次声明式的“数据委托”,子组件专注逻辑,父组件掌控视图,各司其职。