# 无缝焦点图
:-: ![](https://img.kancloud.cn/0a/a3/0aa36db21dc6a5531028d343c58d3a04_1201x462.png)
## 基本结构和样式
```
<style>
* {margin: 0;padding: 0; list-style: none;border: none;}
.banner { width: 1200px; height: 460px; margin: 100px auto; position: relative; overflow: hidden;}
.banner ul { position: absolute; left: 0; top: 0; width: 9999999px; height: 100%;}
.banner ul li { float: left;}
.banner ol { width: 100%; height: 12px; position: absolute;left: 0; bottom: 10px;text-align: center;}
.banner ol li { width: 12px; height: 12px; background: pink; display: inline-block; vertical-align: top; border-radius: 6px; box-shadow: 0 0 3px; cursor: pointer;margin: 0 3px;}
.banner .left,.banner .right{ width: 30px; height: 50px; position: absolute;top: 50%; margin-top: -25px;font-family: "黑体"; font-size: 30px; background: rgba(0,0,0,0.3); color: #fff; text-align: center; line-height: 50px; cursor: pointer;}
.banner .left{left: 0;}
.banner .right{right: 0;}
</style>
<div id="app">
<div class="banner">
<ul>
<li><img src="./images/01.png" alt=""></li>
<li><img src="./images/02.jpg" alt=""></li>
<li><img src="./images/03.jpg" alt=""></li>
<li><img src="./images/04.jpg" alt=""></li>
</ul>
<ol>
<li></li><li></li><li></li><li></li>
</ol>
<div class="control">
<span class="left"><</span>
<span class="right">></span>
</div>
</div>
</div>
```
## 普通组件化
> 整个banner会将其做为一个组件。
~~~
<div id="app">
<banner :data="banner"></banner>
</div>
<script src="js/vue.js"></script>
<script>
Vue.component('banner', {
props:['data'],
template: `
<div class="banner">
<ul>
<li v-for="(item,index) in data"><img :src="item" alt="">
</ul>
<ol>
<li></li><li></li><li></li><li></li>
</ol>
<div class="control">
<span class="left"><</span>
<span class="right">></span>
</div>
</div>`
})
var vm = new Vue({
el: "#app",
data: {
banner: ['./images/01.png', './images/02.jpg', './images/03.jpg', './images/04.jpg',]
}
})
</script>
~~~
## 无缝实现
>[success] 其实就是将最后一张图,复制最后一下拿到第一张前面。我们在vue中制作时,是不操作dom的,而是希望操作数据。
```
Vue.component('banner', {
props:['data'],
computed:{
image(){
var last = this.data[this.data.length-1]
return [last].concat(this.data)
}
},
template: `
<div class="banner">
<ul>
<li v-for="(item,index) in image"><img :src="item" alt=""></li>
</ul>
<ol>
<li></li><li></li><li></li><li></li>
</ol>
<div class="control">
<span class="left"><</span>
<span class="right">></span>
</div>
</div>`
})
```
>[success] 我们要对外面传递的`data`进行修改一下。利用计算属性,将数组中的最后一项拷贝一份,然后再通过数组拼接形成`[4,1,2,3,4]`来完成。
## 插槽
>[warning] 组件的作用是为了**封装:解耦、高内聚**,组件书写完毕后,尽可能的不再修改组件,那么如果组件内部的结构如`banner` 我们除了有图片之外我们还希望它有文本。
> 例如:**在首页焦点图,不仅有图片还有文本描述,在详情页我只要图片,而且仅有图片的这种用的比较多**!!如何实现这种组件?
```
<div id="app">
<banner :data="banner">
<img :src="item" alt="">
</banner>
</div>
<script src="js/vue.js"></script>
<script>
Vue.component('banner', {
props:['data'],
computed:{
image(){
var last = this.data[this.data.length-1]
return [last].concat(this.data)
}
},
template: `
<div class="banner">
<ul>
<li v-for="(item,index) in image">
<slot>
<img :src="item" alt="">
</slot>
</li>
</ul>
……
`
})
</script>
```
代码改造成上面。我们来看一下产生的错误
```
vue.js:584 [Vue warn]: Property or method "item" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property
```
>[warning] 原因是因为父组件 `<banner :data="banner"><img :src="item" alt=""> </banner>` 它处在编译作用域中,此时`item` 在实例中不存在这个数据。所以会报错。
>[success] 这个数据其实是子组件的数据,那么子组件来影响父组件插槽的数据,如何实现,在这里使用`作用域插槽` 就可以完美解决这个问题。
~~~
<div id="app">
<banner :data="banner">
<template slot-scope="abc">
<img :src="abc.item" alt="">
</template>
</banner>
</div>
<script src="js/vue.js"></script>
<script>
Vue.component('banner', {
……,
template: `
<div class="banner">
<ul>
<li v-for="(item,index) in image">
<slot :item="item">
<img :src="item" alt="">
</slot>
</li>
</ul>
……`
})
var vm = new Vue({
el: "#app",
data: {
banner: ['./images/01.png', './images/02.jpg', './images/03.jpg', './images/04.jpg']
}
})
</script>
~~~
## 体验改造后的无缝焦点图组件
```
.banner ul li { float: left;position: relative;}
.banner ul li p{position: absolute; left: 0;bottom: 30px; width: 100%; height: 30px; background: #fff;}
```
```
<banner :data="banner">
<template slot-scope="abc">
<img :src="abc.item" alt="">
</template>
</banner>
<banner :data="banner">
<template slot-scope="abc">
<img :src="abc.item" alt="">
<p>这是说明文本</p>
</template>
</banner>
```
![](https://img.kancloud.cn/89/a5/89a5e1a339beaa78a9c819d0df7da0b9_965x820.png)
## 总结
至此组件化章节已经全部完成。