一. 什么是插槽呢?
1. 生活中的插槽有哪些呢?
usb插槽, 插线板插槽
2. 插槽有什么作用?
同样的插线板, 可以插电视机, 电冰箱, 洗衣机
电脑的usb接口, 可以查鼠标, 插键盘, 还可以外接移动硬盘
插槽的扩展性更强.
二. 组件的插槽
1. 作用: 让组件的更加具有扩展性
例: 我们一个网站有很多搜多功能. 每一个页面的搜索样式,文案可能都不一样.
搜索栏由背景底色, 左侧文案, 搜索样式, 右侧搜索按钮等几部分组成
每一个搜索栏的这几个部分可能都不一样, 这样, 我们就可以将其定义为一个组件, 然后, 将变化的部分定义为插槽.
在不同的页面, 我们需要什么样的样式就可以往插槽中定义什么样内容
2. 如何封装组件?
抽取共性, 保留不同.
将共性抽取到组件中, 然后不同的地方暴露为插槽,一旦预留了插槽, 就可以根据需求, 决定插槽的内容
三. 插槽的使用方法
1. 插槽的定义
在模板中使用<slot></slot>标签定义插槽
可以给插槽设置一个默认值, 插槽里可以有多个值
2. 插槽的调用
我们可以在调用组件的时候, 在组建中直接定义内容
3. 插槽的基本使用方法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <comp1><button>插槽里放了一个按钮</button></comp1> <br> <comp1><p>插槽里放了一个p标签</p></comp1> <br> <comp1> <span>插槽里放了一个span标签</span><span>, 又放了一个span标签</span></comp1> <br> <comp1></comp1><br> </div> <template id="comp1"> <div> <p>这是一个模板</p> <slot><button>这是插槽默认的按钮</button></slot> </div> </template> <script src="../../js/vue.js"></script> <script> Vue.component("comp1", { template: "#comp1" }) const app = new Vue({ el: "#app", data: { message:"hello" } }) </script> </body> </html>
第一步: 定义了一个new Vue()模板
const app = new Vue({ el: "#app", data: { message:"hello" } })
第二步: 定一个了一个组件. 并在组件中使用slot设置插槽. 这个插槽有一个默认值. 是一个button
<template id="comp1"> <div> <p>这是一个模板</p> <slot><button>这是插槽默认的按钮</button></slot> </div> </template>
第三步: 调用组件, 并定制个性化插槽内容
<div id="app"> <comp1><button>插槽里放了一个按钮</button></comp1> <br> <comp1><p>插槽里放了一个p标签</p></comp1> <br> <comp1> <span>插槽里放了一个span标签</span><span>, 又放了一个span标签</span> </comp1> <br> <comp1></comp1><br> </div>
案例效果
四. 插槽的具名
如果有多个插槽, 想要分别替换每一个插槽, 应该怎么办呢?
可以分两步:
第一步: 给插槽设置一个名字
第二步: 替换的时候指定插槽的名字
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <comp1></comp1> <br> ---------------- <br> <comp1><p slot="second">替换第二个插槽的默认值</p></comp1> <br> -----------------<br> <comp1><p>不设置名字,将不会替换</p></comp1> <br> <br> </div> <template id="comp1"> <div> <p>这是一个模板</p> <slot name="zero"><button>这是插槽默认的按钮</button></slot> <br> <slot name="first"><span>第一个插槽</span></slot> <br> <slot name="second"><span>第二个插槽</span></slot> <br> <slot name="third"><span>第三个插槽</span></slot> <br> </div> </template> <script src="../../js/vue.js"></script> <script> Vue.component("comp1", { template: "#comp1" }) const app = new Vue({ el: "#app", data: { message:"hello" } }) </script> </body> </html>
第一步: 定义组件, 并设置四个插槽, 给每个插槽定义一个名字
<template id="comp1"> <div> <p>这是一个模板</p> <slot name="zero"><button>这是插槽默认的按钮</button></slot> <br> <slot name="first"><span>第一个插槽</span></slot> <br> <slot name="second"><span>第二个插槽</span></slot> <br> <slot name="third"><span>第三个插槽</span></slot> <br> </div> </template>
第二步: 调用组件, 指定替换插槽的内容
<comp1><p slot="second">替换第二个插槽的默认值</p></comp1>
五. 变量的作用域
1. 在vue实例中定义的data变量, 作用域都是vue实例
2. 在模板中定义的变量, 作用域是模板范围内
看下面的案例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <p>对象的作用域</p> <comp1 v-show="isShow"></comp1> </div> <template id="comp1"> <div> <p>这是一个模板</p> <button v-show="isShow">按钮</button> </div> </template> <script src="../../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { message:"hello", name: "vue对象里的name", isShow: true }, components: { comp1: { template: comp1, data() { return { "name": "模板里的name", isShow: false } } } } }) </script> </body> </html>
第一步: 定义了一个vue对象, 在父组件中定义一个变脸isShow为true, 在子组件中定一个一个变量isShow:false.
const app = new Vue({ el: "#app", data: { message:"hello", name: "vue对象里的name", isShow: true }, components: { comp1: { template: comp1, data() { return { "name": "模板里的name", isShow: false } } } } })
第二步: 在模板中使用isShow变量. 这里使用的是模板中定义的isShow变量
<template id="comp1"> <div> <p>这是一个模板</p> <button v-show="isShow">按钮</button> </div> </template>
第三步: 在dom元素中中使用isShow变量, 这里的作用域是父组件
<div id="app"> <p>对象的作用域</p> <comp1 v-show="isShow"></comp1> </div>
父组件的isShow是true, 所以, 会显示子组件的内容. 子组件的isShow是false, 所以不会显示button按钮
效果和我们预期的一样.
总结:
- 父组件模板的所有东西都会在父级作用域内编译; 子组件模板的所有东西都会在子级作用域内编译
- <comp1 v-show="isShow"></comp1>整个组件的使用过程是在父组件中出现的, 所以它的作用域是父组件
六. slot的作用域
首先, 我们创建一个Vue实例, 然后在Vue的data中定义一个books, 在组件中定义一个books
然后, 在模板中定义一个插槽, 遍历books. 我们发现调用的是组件中的books
<template id="comp1"> <slot> <div> <p>这是一个模板</p> <ul> <li v-for="item in books">{{item}}</li> </ul> </div> </slot> </template> <script src="../../js/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { message:"hello", books:["book1", "book2", "book3", "book4", "book5"] }, components: { comp1: { template: comp1, data() { return { books: ["go语言", "java编程实战", "python人工智能", "php高阶开发"] } } } } }) </script>
直接调用模板
<div id="app"> <p>slot的作用域</p> <br>---------------<br> <p>原模板展示</p> <comp1 ></comp1> </div>
展示效果:
问题: 这时, 如果我们想要换一种展示方式, 但是展示的数据还是books. 怎么办呢?
也就是说, 我们要替换所有的模板内容和样式, 但是, 模板的数据还是原来的数据.
方法是: 给slot定义一个name, 调用的时候指定slot为name的名称. 并设置当前模板的作用域
第一步: 给模板的插槽定义一个名字
<template id="comp1"> <slot :data="books" name="showbooks"> <div> <p>这是一个模板</p> <ul> <li v-for="item in books">{{item}}</li> </ul> </div> </slot> </template>
第二步: 在替换组件内容的地方定义一个新的template. 指定替换的名字, 并设置作用于为slot
<p>替换模板的内容: 按照 index - item展示, 并换颜色</p> <comp1> <template slot-scope="slot" slot="showbooks"> <ul> <li style="color: cornflowerblue" v-for="(item, index) in slot.data">{{index}} -- {{item}}</li> </ul> </template> </comp1>
在调用的时候, 使用slot.data作为数据调用.
展示效果: