.
.
.
.
# 作用域插槽 - 干嘛用
需求:老板对 子组件
的<mark>数据展示</mark>不满意,想在 根样式
里面自定义样式(如下)
由于要在父组件拿到子组件数据,就需要用到作用域插槽。
改前:
改后:
改前代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 父组件模板 -->
<div id='app'>
<books-info></books-info>
</div>
<!-- 子组件模板 -->
<template id="booksInfo">
<div>
<!-- 推荐书目 -->
<slot>
<h2>畅销书:{{hotBook.name}}</h2>
<hr>
</slot>
<!-- 展示 -->
<slot>
<ul>
<li v-for="book in books">{{book}}</li>
</ul>
<hr>
</slot>
<!--总价-->
<slot>
<p>总价:{{totalPrice}}</p>
</slot>
</div>
</template>
<script src="../dist/vue.js"></script>
<script> // 子组件 const booksInfo = { template: '#booksInfo', computed: { // 获取总价格 totalPrice() { return this.books.reduce((total, current) => total += current.price * current.count, 0).toFixed(2); }, // 获取畅销书(价格最高) hotBook() { return this.books.sort((a, b) => b.price - a.price)[0]; } }, data() { return { books: [{ id: 1, name: 'International Mobility Agent', date: 'Mon Nov 04 2019 19:26:59 GMT+0800 (中国标准时间)', price: 348.10, count: 4 }, { id: 2, name: 'Regional Metrics Developer', date: 'Sat Sep 28 2019 13:24:49 GMT+0800 (中国标准时间)', price: 867.67, count: 11 }, { id: 3, name: 'Product Applications Technician', date: 'Mon Nov 25 2019 01:23:04 GMT+0800 (中国标准时间)', price: 751.74, count: 2 }, { id: 4, name: 'Internal Identity Supervisor', date: 'Wed May 29 2019 23:08:32 GMT+0800 (中国标准时间)', price: 52.83, count: 3 }, { id: 5, name: 'Future Web Facilitator', date: 'Sat Sep 14 2019 13:16:19 GMT+0800 (中国标准时间)', price: 897.66, count: 5 }, { id: 6, name: 'Legacy Infrastructure Strategist', date: 'Fri Nov 08 2019 12:35:13 GMT+0800 (中国标准时间)', price: 851.90, count: 8 }, ] } } } // 父组件 const app = new Vue({ el: '#app', components: { booksInfo: booksInfo } }) </script>
</body>
</html>
# 解决方案
想要修改数据的样式,前提要拿到数据
而想要在父组件调用子组件数据,普遍做法是用事件,比较麻烦。
<mark>而且我现在只需要展示数据,那么就能用作用域槽轻松完成需求。</mark>
步骤:
- 给
slot
标签加上名字。如:<slot name='header'>
(字符串随意) - 给
slot
标签加上要绑定的数据。如:<slot name='header' :hot='hotBook'>
(属性名随意) - 使用:
<template v-slot:header='headerScope'>
改后代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 父组件模板 -->
<div id='app'>
<books-info>
<template v-slot:header='headerScope'>
<div style="background-color:#1abc9c">
<h1>热卖畅销书:《{{headerScope.hot.name}}》,现在仅需 ¥{{headerScope.hot.price}}</h1>
</div>
</template>
<template v-slot:default='tableScope'>
<ul>
<li v-for="book in tableScope.books">《{{book.name}}》 - ¥{{book.price}}</li>
</ul>
</template>
<template v-slot:footer='footerScope'>
<div>
<h3>不用998,不用688,现在全部购买,仅需<font color='red'>{{footerScope.price}}</font>元! 仅需<font color='red'>
{{footerScope.price}}</font>元!</h3>
</div>
</template>
</books-info>
</div>
<!-- 子组件模板 -->
<template id="booksInfo">
<div>
<!-- 推荐书目 -->
<slot name='header' :hot='hotBook'>
<h2>畅销书:{{hotBook.name}}</h2>
<hr>
</slot>
<!-- 展示 -->
<!--不给slot加name值,默认值为default-->
<slot :books='books'>
<ul>
<li v-for="book in books">{{book}}</li>
</ul>
<hr>
</slot>
<!--总价-->
<slot name='footer' :price='totalPrice'>
<p>总价:{{totalPrice}}</p>
</slot>
</div>
</template>
<script src="../dist/vue.js"></script>
<script> // 子组件 const booksInfo = { template: '#booksInfo', computed: { // 获取总价格 totalPrice() { return this.books.reduce((total, current) => total += current.price * current.count, 0).toFixed(2); }, // 获取畅销书(价格最高) hotBook() { return this.books.sort((a, b) => b.price - a.price)[0]; } }, data() { return { books: [{ id: 1, name: 'International Mobility Agent', date: 'Mon Nov 04 2019 19:26:59 GMT+0800 (中国标准时间)', price: 348.10, count: 4 }, { id: 2, name: 'Regional Metrics Developer', date: 'Sat Sep 28 2019 13:24:49 GMT+0800 (中国标准时间)', price: 867.67, count: 11 }, { id: 3, name: 'Product Applications Technician', date: 'Mon Nov 25 2019 01:23:04 GMT+0800 (中国标准时间)', price: 751.74, count: 2 }, { id: 4, name: 'Internal Identity Supervisor', date: 'Wed May 29 2019 23:08:32 GMT+0800 (中国标准时间)', price: 52.83, count: 3 }, { id: 5, name: 'Future Web Facilitator', date: 'Sat Sep 14 2019 13:16:19 GMT+0800 (中国标准时间)', price: 897.66, count: 5 }, { id: 6, name: 'Legacy Infrastructure Strategist', date: 'Fri Nov 08 2019 12:35:13 GMT+0800 (中国标准时间)', price: 851.90, count: 8 }, ] } } } // 父组件 const app = new Vue({ el: '#app', components: { booksInfo: booksInfo } }) </script>
</body>
</html>
# 后话
注意1
- 默认插槽名为
default
,可以省略default
直接写v-slot
。
缩写为#
时不能不写参数,写成#default
(这点所有指令都一样,v-bind、v-on) - 多个插槽混用时,
v-slot
不能省略default
- 只要出现多个插槽,请始终为所有的插槽使用完整的基于
<template>
的语法
注意2
2.5及之前有 slot-scope
的写法。
这种写法在官网上说了,会在3.0之后完全弃用。
参考