2/5 Vue.js 简单轮播组件

  以前刚接触Vue的时候手撸了一个 轮播图 效果还是不错的

  但是在学习过程中,越发发现组件的用处

  所以在书上源码的加持下 添油加醋 写了一个轮播组件

  注释很清晰 供有缘人查看

  1 <template>
  2   <div class="swiper-container">
  3     <!-- 用动态样式换图片 -->
  4     <!-- 通过div的方式展示图片可以减轻浏览器负担 -->
  5 
  6     <!-- 进行过渡 -->
  7     <transition-group name="images" tag="div" class="swiper-images">
  8       <!-- 通过v-for来实现多个盒子的注入 -->
  9       <div
 10         v-for="(slide, index) in slides"
 11         :key="slides.indexOf(slide)"
 12         :style="{ backgroundImage: 'url(' + slide + ')' }"
 13         class="swiper-image"
 14         v-show="index === value"
 15         @mouseover="toggleIndex(index)"
 16         @mouseout="initTimer"
 17       ></div>
 18     </transition-group>
 19 
 20     <!-- 切换按钮 -->
 21     <div class="swiper-paginator">
 22       <!-- slides 是父组件传入的参数 -->
 23 
 24       <span
 25         v-for="(slide, index) in slides"
 26         :key="index"
 27         class="paginator-item"
 28         :class="{ 'paginator-current': index === value }"
 29         @mouseover="toggleIndex(index)"
 30         @mouseout="initTimer"
 31       ></span>
 32     </div>
 33 
 34     <div
 35       class="arrow arrow_left"
 36       @click="onLeft"
 37       @mouseover="toggleIndex()"
 38       @mouseout="initTimer"
 39     >
 40       <div></div>
 41     </div>
 42     <div
 43       class="arrow arrow_right"
 44       @click="onRight"
 45       @mouseover="toggleIndex()"
 46       @mouseout="initTimer"
 47     >
 48       <div></div>
 49     </div>
 50   </div>
 51 </template>
 52  
 53 <script>
 54 // 制造组件的第一部分 其实就是想清楚 变量
 55 // 要得到相应的 变量 ; 要从上级组件得到的 参数
 56 // 这里 因为是 轮播图 所以
 57 //  1 存放图片路径的图片数组 slides
 58 //  2 当前的图片标志 (页码) value
 59 //  3 自动轮播的时间间隔 interval
 60 // 这些我们都可以从上级的组件里面得到
 61 
 62 export default {
 63   name: "Swiper",
 64   props: {
 65     slides: {
 66       type: Array,
 67       validator(value) {
 68         //  判断是否每一个元素 都是 满足String 的条件
 69         return value.every(
 70           (item) => Object.prototype.toString.call(item) === "[object String]"
 71         );
 72       },
 73     },
 74     value: {
 75       //  Value 标志当前的图片 默认是从 0 开始 ( props 里面的 value 属性默认接受父组件的v-model值 )
 76       type: Number,
 77       default: 0,
 78     },
 79     interval: {
 80       //  间隔也是一个 数字类型的变量 默认从 4 开始
 81       type: Number,
 82       default: 4,
 83     },
 84   },
 85   data() {
 86     return {
 87       //  在 data 里面设置一个 计时器 还未被初始化
 88       timer: null,
 89     };
 90   },
 91 
 92   mounted() {
 93     // 每次挂载好了 就开启计时器
 94     this.initTimer();
 95   },
 96   methods: {
 97     //  初始化计时器
 98     initTimer() {
 99       this.timer = setInterval(() => {
100         //  父组件的 input 的参数
101         this.$emit("input", (this.value + 1) % this.slides.length);
102       }, this.interval * 1000);
103     },
104     //  每当 hover 和 点击到了 按钮 就开始 执行下面的操作
105     toggleIndex(index) {
106       // 父组件的index 为当前的的index 如果 没有参数 则就是原来的数值 注意0也是没得
107       this.$emit("input", index >= 0 ? index : this.value);
108       clearInterval(this.timer); // 清除计时器
109     },
110     // 箭头点击
111     // 左箭头
112     onLeft() {
113       // 自己做一下数学运算
114       this.$emit(
115         "input",
116         this.value - 1 >= 0
117           ? (this.value - 1) % this.slides.length
118           : (this.slides.length - Math.abs(this.value - 1)) % this.slides.length
119       );
120       clearInterval(this.timer); // 清除计时器
121     },
122     // 右箭头
123     onRight() {
124       this.$emit("input", (this.value + 1) % this.slides.length);
125       clearInterval(this.timer); // 清除计时器
126     },
127   },
128 };
129 </script>
130  
131 <style scoped>
132 /* scoped 表明该 css 仅仅只适用于 本组件 */
133 .swiper-container {
134   /* 容纳的大盒子 子绝 父相 */
135   position: relative;
136   width: 100%;
137   height: 100%;
138 }
139 .swiper-images {
140   height: 100%;
141   width: 100%;
142 }
143 .swiper-image {
144   height: 100%;
145   width: 100%;
146   background-size: cover;
147   background-repeat: no-repeat;
148   /* 让几个 image 盒子重叠 */
149   position: absolute;
150 }
151 .swiper-paginator {
152   margin-top: -30px;
153   padding-right: 5px;
154   text-align: right;
155   list-style: none;
156 }
157 .paginator-item {
158   cursor: pointer;
159   display: inline-block;
160   width: 16px;
161   height: 16px;
162   margin-left: 5px;
163   border-radius: 50%;
164   background-color: #000;
165   opacity: 0.3;
166 }
167 .paginator-current {
168   background-color: #fff; /* 当前激活的幻灯片切换按钮样式 */
169   opacity: 0.6;
170 }
171 
172 /* 箭头 */
173 .arrow {
174   display: block;
175   width: 45px;
176   height: 108px;
177   position: absolute;
178   top: 35%;
179   cursor: pointer;
180   right: -20%;
181   background: linear-gradient(
182     to left,
183     rgba(0, 0, 0, 0.3) 5%,
184     rgba(0, 0, 0, 0) 95%
185   );
186   transition: all 0.5s;
187 }
188 .arrow_left {
189   /*//左边距离父盒子边框*/
190   left: -45px;
191   background: linear-gradient(
192     to right,
193     rgba(0, 0, 0, 0.3) 5%,
194     rgba(0, 0, 0, 0) 95%
195   );
196 }
197 .arrow_right {
198   /*//右边距离父盒子边框*/
199   right: -45px;
200   background: linear-gradient(
201     to left,
202     rgba(0, 0, 0, 0.3) 5%,
203     rgba(0, 0, 0, 0) 95%
204   );
205 }
206 .arrow:hover {
207   background: linear-gradient(
208     to left,
209     rgba(171, 218, 244, 0.3) 5%,
210     rgba(171, 218, 244, 0) 95%
211   );
212 }
213 
214 .arrow div {
215   display: block;
216   /* 箭头图片的路径 */
217   background-image: url(/static/images/arrow.png);
218   background-repeat: no-repeat;
219   height: 36px;
220   width: 23px;
221   margin: 36px auto;
222 }
223 
224 .arrow_left div {
225   background-position: -23px 0px;
226 }
227 .arrow_right div {
228   background-position: 0px 0px;
229 }
230 
231 /* 过渡效果 */
232 .images-enter,
233 .images-leave-to {
234   opacity: 0;
235   /* transform:translateX(30px) */
236 }
237 .images-enter-active,
238 .images-leave-active {
239   transition-property: all;
240   /* transition-delay: 100ms; */
241   transition-duration: 500ms;
242   transition-timing-function: linear;
243 }
244 .images-leave,
245 .images-enter-to {
246   /* transform:translateX(0px); */
247   opacity: 1;
248 }
249 </style>

  当然这个组件应该怎么用呢,

  如下图

  

 

 


  接着是我写这个组件的时候遇到的问题

  1.trasnsition-group 没有只套用在 v-for 的一个标签上

    当时是这样的,v-for那个div 外层还有一个 大div , 我给套在大盒子上了,结果就出错了

  2.js 表示假值的一般来说 就是没得的东西 0 也是假值

    加了注释的地方就是我出错的地方

    

 

     当时没有想到这个,原来的代码是 框起来的那个部分

    

       如果 传入 0 的时候,如果参数 index 为 0 的话,就会发生意想不到的事情 

    表现在这个组件里面就是没办法点击到第一个小圆点,因为传到的参数是 0 

    3.还有一个错误,就是

      

    transition-group提示key值没有弄对,其实这里直接 这样就能解决 或者 :key ="slide"

      

    最后呢

    对比原来写的一个代码,我发现现在这个组件的代码更加美观,原来那个太小孩子了 感觉

      原来写的 https://www.cnblogs.com/WaterMealone/articles/14332704.html

    注:

      可能有朋友在用的时候会发现,小圆点有点奇怪,这个我也不知道怎么去处理,因为 span 的规定范围太小了,导致了快速滑动的时候 判定老是更新

      所以 会有一种反应不过来的 现象

      然后这个是箭头的图片

      

      这个是整个项目的图片

      

 

   总结

    每天进步一点点

    今天再撸一下代码

    

posted @ 2021-02-05 19:54  WaterMealone  阅读(150)  评论(0编辑  收藏  举报