用Vue實現一個簡單的圖片輪播

本文已收錄至//github.com/likekk/studyBlog歡迎大家star,共同學習,共同進步。如果文章有錯誤的地方,歡迎大家指出。後期將在將GitHub上規劃前端學習的路線和資源分享。

寫在前面

每一篇文章都希望您有所收穫,每一篇文章都希望您能靜下心來瀏覽、閱讀。每一篇文章都是作者精心打磨的作品。

如果您覺得楊戩這個小白還有點東西的話,楊戩希望正在看文章的您可以幫忙點亮那個點贊的按鈕(效果更加),對於楊戩這個暖男來說,真的真的非常重要,這將是我持續寫作的動力。

前言

寫這篇文章的目的主要是將以前所學的知識結合起來,進一步鞏固一下自己的記憶,防止遺忘(主要是害怕老年痴呆),當然更重要的是學以致用,畢竟學過的東西不拿來用的話就會很容易忘記,永遠不要太相信自己的記憶,編程這東西,幾天不弄,忘的就很快,回過頭再看,心裡想著:這是我寫的程式碼嗎?本篇部落格也是秉著這樣的初心去寫的。

整體分析

在我看來,我覺得做每一件事情都必須弄清楚這件事情的前因後果,當然了如果有是實在不太了解的,姑且可以先實現效果。

然後再返回去慢慢理解,不過我一般比較喜歡先分析整體結構,然後一步一步去實現,有些事情不可能做到盡善盡美的,不是嗎?先上效果圖吧!

這張圖打了一波廣告,我想你們應該不會介意的吧!不過說實話這裡面的老師講課真的是特別優秀,感興趣的讀者可以去嘗試一下,畢竟暖男戩是不會騙人的。

本來想著弄一下輪播圖的動態效果的,奈何不會弄,所以放棄了,靜態的湊合看吧!

分析第一步

布局的話,一個是顯示圖片,另一個是顯示小圓點,圖片切換的時候,小圓點也隨著切換,當切換到最後一張的時候圖片重從第一張開始重新輪播。

分析第二步

我們需要明確哪些數據是需要通過外部傳輸,哪些數據是我們自己可以控制,從效果圖分析主要的話是圖片,當然控制小圓點也是可以的,我們知道vue是可以實現組件的復用的,那麼對於輪播圖而言,也可以實現其復用性。

例如:在其它地方我們也需要用到輪播圖,但是輪播的圖片不一樣,輪播的速度不一樣等等。

總結:分析哪些數據是可控的,哪些數據是不可控的。

分析第三步

這裡主要是輪播整體的實現,滑鼠經過,輪播停止,滑鼠移出,輪播繼續,點擊小圓點,實現輪播。

涉及知識點

文章中輪播圖的實現涉及的知識點我整理了一下,如果有知識點不太清楚的讀者可以去了解相關的內容。

  • vue的父子組件通訊
  • 靜態資源的導入
  • v-if和v-for的使用
  • 事件處理
  • class和sytle綁定
  • Vue的生命周期
  • 組件的校驗

輪播的實現

將步驟分析和涉及的知識點整理之後,一切應該都是遊刃有餘吧!那麼我們一步一步實現輪播的效果。

介面布局

1、全局css樣式引入

全局css樣式,我已經會搭建準備好了,一個是reset.css,一個是global.css,靜態圖片資源放在了github上,大家可以自行下載

reset.css

  1/* //meyerweb.com/eric/tools/css/reset/ 
2   v2.0 | 20110126
3   License: none (public domain)
4*/

5
6html,
7body,
8div,
9span,
10applet,
11object,
12iframe,
13h1,
14h2,
15h3,
16h4,
17h5,
18h6,
19p,
20blockquote,
21pre,
22a,
23abbr,
24acronym,
25address,
26big,
27cite,
28code,
29del,
30dfn,
31em,
32img,
33ins,
34kbd,
35q,
36s,
37samp,
38small,
39strike,
40strong,
41sub,
42sup,
43tt,
44var,
45b,
46u,
47i,
48center,
49dl,
50dt,
51dd,
52ol,
53ul,
54li,
55fieldset,
56form,
57label,
58legend,
59table,
60caption,
61tbody,
62tfoot,
63thead,
64tr,
65th,
66td,
67article,
68aside,
69canvas,
70details,
71embed,
72figure,
73figcaption,
74footer,
75header,
76hgroup,
77menu,
78nav,
79output,
80ruby,
81section,
82summary,
83time,
84mark,
85audio,
86video {
87  margin0;
88  padding0;
89  border0;
90  font-size100%;
91  font: inherit;
92  vertical-align: baseline;
93}
94/* HTML5 display-role reset for older browsers */
95article,
96aside,
97details,
98figcaption,
99figure,
100footer,
101header,
102hgroup,
103menu,
104nav,
105section {
106  display: block;
107}
108body {
109  line-height1;
110}
111ol,
112ul {
113  list-style: none;
114}
115blockquote,
116q {
117  quotes: none;
118}
119blockquote:before,
120blockquote:after,
121q:before,
122q:after {
123  content"";
124  content: none;
125}
126table {
127  border-collapse: collapse;
128  border-spacing0;
129}

global.css

 1@import "//at.alicdn.com/t/font_1811699_2hvkwp7upcz.css";
2
3a {
4  color#409eff;
5  text-decoration: none;
6}
7a:hover{
8  color#66b1ff;
9}
10* {
11  box-sizing: border-box;
12}
13
14.container {
15  width1080px;
16  margin0 auto;
17}
18
19input {
20  background-color#fff;
21  background-image: none;
22  border-radius4px;
23  border1px solid #dcdfe6;
24  color#606266;
25  display: inline-block;
26  font-size: inherit;
27  height40px;
28  line-height40px;
29  outline: none;
30  padding0 15px;
31  transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
32}
33input:focus {
34  outline: none;
35  border-color#409eff;
36}
37
38body {
39  min-width1100px;
40  line-height1.5;
41  color#333;
42}
43
44button {
45  outline: none;
46  border: none;
47  width170px;
48  font-size: inherit;
49  color#fff;
50  background-color#409eff;
51  border-color#409eff;
52  line-height1;
53  white-space: nowrap;
54  cursor: pointer;
55  transition0.1s;
56  font-weight500;
57  font-size14px;
58  border-radius4px;
59  padding12px;
60}
61button:hover {
62  background#66b1ff;
63  border-color#66b1ff;
64}

全局導入

main.js

 1// The Vue build version to load with the `import` command
2// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3import Vue from 'vue'
4import "./assets/css/reset.css"
5import "./assets/css/global.css"
6import router from './router'
7import store from "./store/index"
8import Vuex from "vuex"
9Vue.use(Vuex)
10Vue.config.productionTip = false
11
12/* eslint-disable no-new */
13new Vue({
14  el'#app',
15  router,
16  store,
17  components: {},
18  template''
19})

2、在components/slider文件夾下新建Slider.vue和sliderIndex.vue這兩個組件

Slider.vue

 1<template>
2    <div class="banner-container">
3      <ul class="images">
4        <li><a href=""><img src="../../assets/img/banner/banner1.jpeg" alt=""></a></li>
5        <li><a href=""><img src="../../assets/img/banner/banner2.jpeg" alt=""></a></li>
6        <li><a href=""><img src="../../assets/img/banner/banner3.jpeg" alt=""></a></li>
7      </ul>
8      <ul class="dots">
9        <li class="active"></li>
10        <li></li>
11        <li></li>
12      </ul>
13    </div>
14</template>
15
16<script>
17    export default {
18        name: "Slider",
19    }
20</script>
21
22<style scoped>
23  /* 樣式 */
24  .banner-container {
25    height: 350px;
26    position: relative;
27    overflow: hidden;
28  }
29  .banner-container li {
30    display: block;
31    width: 1080px;
32    height: 100%;
33    float: left;
34  }
35  .images {
36    height: 100%;
37    transition: 0.5s;
38  }
39  .banner-container img {
40    width: 1080px;
41    height: 100%;
42  }
43  .dots {
44    position: absolute;
45    bottom: 10px;
46    right: 10px;
47    display: flex;
48  }
49  .dots li {
50    width: 10px;
51    cursor: pointer;
52    height: 10px;
53    margin: 0 3px;
54    border-radius: 50%;
55    border: 1px solid;
56    color: #fff;
57  }
58  .dots li.active {
59    background: #fff;
60  }
61</style>

SliderIndex.vue

 1<template>
2    <div style="width:1080px;margin: 0 auto ">
3      <slider></slider>
4    </div>
5</template>
6<script>
7  import slider from "./Slider"
8    export default {
9        name: "SliderIndex",
10        components:{
11          slider:slider
12        },
13    }
14</script>
15
16<style scoped>
17
18</style>

這樣,整體的布局效果就已經出來了。這裡就不進行截圖了。

組件通訊和靜態資源導入

在Slider.vue這個組件中,我們是將圖片直接寫死的,上面分析也提到過,哪些數據是可控的,哪些數據是不可控的,圖片的話,我們動態引入。

資源導入

資源導入有兩種方式,一種是import,另一種是require導入。

  • import 導入
1  import banner1 from "../../assets/img/banner/banner1.jpeg"
2  import banner2 from "../../assets/img/banner/banner2.jpeg"
3  import banner3 from "../../assets/img/banner/banner3.jpeg"
  • require導入
1require("./../../assets/img/banner/banner1.jpeg")
2require("./../../assets/img/banner/banner2.jpeg")
3require("./../../assets/img/banner/banner3.jpeg")

這兩種方式都可以,

SliderIndex.vue

 1<template>
2    <div style="width:1080px;margin: 0 auto ">
3      <slider :sliderArray="sliderArray"></slider>
4    </div>
5</template>
6<script>
7  import slider from "./Slider"
8  import banner1 from "../../assets/img/banner/banner1.jpeg"
9  import banner2 from "../../assets/img/banner/banner2.jpeg"
10  import banner3 from "../../assets/img/banner/banner3.jpeg"
11    export default {
12        name: "SliderIndex",
13        components:{
14          slider:slider
15        },
16        data(){
17          return{
18            sliderArray:[banner1,banner2,banner3]
19          }
20        }
21    }
22</script>
23
24<style scoped>
25
26</style>

Slide.vue

 1<template>
2    <div class="banner-container">
3      <ul class="images">
4        <li v-for="(item,i) of sliderArray" :key="i">
5          <a href="javascript:void(0)"><img :src=item alt=""></a>
6        </li>
7      </ul>
8      <ul class="dots">
9        <li v-for="(item,i) of sliderArray" :key='i'></li>
10      </ul>
11    </div>
12</template>
13
14<script>
15    export default {
16        name: "Slider",
17      props:{
18          sliderArray:{
19            require:true,
20            type:Array,
21          }
22      }
23    }
24</script>
25
26<style scoped>
27  /* 樣式 */
28  .banner-container {
29    height: 350px;
30    position: relative;
31    overflow: hidden;
32  }
33  .banner-container li {
34    display: block;
35    width: 1080px;
36    height: 100%;
37    float: left;
38  }
39  .images {
40    height: 100%;
41    transition: 0.5s;
42  }
43  .banner-container img {
44    width: 1080px;
45    height: 100%;
46  }
47  .dots {
48    position: absolute;
49    bottom: 10px;
50    right: 10px;
51    display: flex;
52  }
53  .dots li {
54    width: 10px;
55    cursor: pointer;
56    height: 10px;
57    margin: 0 3px;
58    border-radius: 50%;
59    border: 1px solid;
60    color: #fff;
61  }
62  .dots li.active {
63    background: #fff;
64  }
65</style>

到這一步的時候,有幾個問題,第一個是默認我們圖片顯示第一張,小圓點默認第一個顯示,容器的總寬度計算是總圖片的長度*100%,Slide.vue定義內部數據index=0,當index和i相等時,添加active類

 1<template>
2    <div class="banner-container">
3      <ul class="images" :style="{
4        width:sliderArray.length*100+'%',
5        marginLeft:-index*100+'%'
6      }">
7        <li v-for="(item,i) of sliderArray" :key="i">
8          <a href="javascript:void(0)"><img :src=item alt=""></a>
9        </li>
10      </ul>
11      <ul class="dots">
12        <li v-for="(item,i) of sliderArray" :class="{
13          active:i===index
14        }" :key="i"></li>
15      </ul>
16    </div>
17</template>
18
19<script>
20    export default {
21        name: "Slider",
22      props:{
23          sliderArray:{
24            require:true,
25            type:Array,
26          }
27      },
28      data(){
29          return{
30            index:0,
31          }
32      }
33    }
34</script>
35
36<style scoped>
37  /* 樣式 */
38  .banner-container {
39    height: 350px;
40    position: relative;
41    overflow: hidden;
42  }
43  .banner-container li {
44    display: block;
45    width: 1080px;
46    height: 100%;
47    float: left;
48  }
49  .images {
50    height: 100%;
51    transition: 0.5s;
52  }
53  .banner-container img {
54    width: 1080px;
55    height: 100%;
56  }
57  .dots {
58    position: absolute;
59    bottom: 10px;
60    right: 10px;
61    display: flex;
62  }
63  .dots li {
64    width: 10px;
65    cursor: pointer;
66    height: 10px;
67    margin: 0 3px;
68    border-radius: 50%;
69    border: 1px solid;
70    color: #fff;
71  }
72  .dots li.active {
73    background: #fff;
74  }
75</style>

這時,可以實現基本的輪播效果,在這裡我們無需關注視圖,只需要關注數據即可,因為數據改變了,視圖之然就變了,可以用控制台改變index的值。

小圓點切換時,圖片切換

這個功能的實現特別簡單,只需要在點擊的時候將i的值賦值給index即可,即index改變,視圖重新渲染。

1      <ul class="dots">
2        <li v-for="(item,i) of sliderArray" :class="{
3          active:i===index
4        }" :key="i" @click="index=i"></li>
5      </ul>

自動輪播和停止輪播

實現自動輪播的關鍵是在組件掛載時調用方法,停止輪播的關鍵是組件銷毀時,銷毀定時器。

滑鼠懸停,輪播停止。滑鼠離開,錄播繼續。

 1<template>
2    <div class="banner-container">
3      <ul class="images" :style="{
4        width:sliderArray.length*100+'%',
5        marginLeft:-index*100+'%'
6      }">
7        <li v-for="(item,i) of sliderArray" :key="i" @mouseleave="autoStart" @mouseenter="autoStop">
8          <a href="javascript:void(0)"><img :src=item alt=""></a>
9        </li>
10      </ul>
11      <ul class="dots">
12        <li v-for="(item,i) of sliderArray" :class="{
13          active:i===index
14        }" :key="i" @click="index=i"></li>
15      </ul>
16    </div>
17</template>
18
19<script>
20    export default {
21        name: "Slider",
22      props:{
23          sliderArray:{
24            require:true,
25            type:Array,
26          }
27      },
28      data(){
29          return{
30            index:0,
31            timer:null
32          }
33      },
34      mounted(){
35        this.autoStart()
36      },
37      destroyed(){
38          this.autoStop()
39      },
40      methods:{
41          autoStart(){
42            if(this.timer){
43              return
44            }
45            this.timer=setInterval(()=>{
46              this.index=(this.index+1)%this.sliderArray.length;
47            },2000)
48          },
49          autoStop(){
50            clearInterval(this.timer);
51            this.timer=null;
52          }
53      }
54    }
55</script>
56
57<style scoped>
58  /* 樣式 */
59  .banner-container {
60    height: 350px;
61    position: relative;
62    overflow: hidden;
63  }
64  .banner-container li {
65    display: block;
66    width: 1080px;
67    height: 100%;
68    float: left;
69  }
70  .images {
71    height: 100%;
72    transition: 0.5s;
73  }
74  .banner-container img {
75    width: 1080px;
76    height: 100%;
77  }
78  .dots {
79    position: absolute;
80    bottom: 10px;
81    right: 10px;
82    display: flex;
83  }
84  .dots li {
85    width: 10px;
86    cursor: pointer;
87    height: 10px;
88    margin: 0 3px;
89    border-radius: 50%;
90    border: 1px solid;
91    color: #fff;
92  }
93  .dots li.active {
94    background: #fff;
95  }
96</style>

簡單的輪播效果就已經實現了,整體難度不難,但是涉及的知識點比較多,從一個小的輪播效果就涉及那麼多的知識點,所以說基礎很重要,楊戩的基礎也不是很好,但是楊戩是一個喜歡學習的暖男(我信你個鬼),好了,看到這裡,本編部落格的內容就要結束了,我們下篇文章見。

結尾

如果覺得本篇文章對您有用的話,可以麻煩您幫忙點亮那個點贊按鈕嗎?

對於楊戩這個暖男來說:真的真的非常有用,您的支援將是我繼續寫文章前進的動力,我們下篇文章見。

【原創】|二郎神楊戩

二郎神楊戩,一個在互聯網前端苟且偷生的划水程式設計師,專註於前端開發,善於技術分享。
如需轉載,請聯繫作者或者保留原文鏈接,微信公眾號搜索二郎神楊戩或者掃描下方的二維碼更加方便。

一起來見證二郎神楊戩的成長吧!更多好文、技術分享盡在下方這個公眾號。歡迎關注。