当前位置: 代码迷 >> 综合 >> Vue2.0进阶组件篇2 解析饿了么(spinner组件)
  详细解决方案

Vue2.0进阶组件篇2 解析饿了么(spinner组件)

热度:83   发布时间:2023-10-22 09:01:14.0

https://juejin.im/post/58e3bebcac502e49579fc1bd前两天一个同学问我想叫我写了一个spinner组件,那OK我就是那么能满足大家的口味,如果写一个spinner组件,别看一个小小的组件如何去写,很多人问我vuex,vue-router怎么玩,这东西有什么好玩的,看看api文档就可以去玩了,然后我就看看了饿了么spinner组件的写法,他是如何去组织自己的代码结构的
因为饿了么的spinner组件本质上是基于px来写的,我经常会遇到一个问题,我用的是rem怎么办,px毕竟还是不适配,那只有拿出我的开山釜自己打造一个rem版本的,如果有饿了么开发人员看到我这文章,虽然小弟我没办法和你们肩并肩一起打造组件,那我就借鉴一下,人在江湖走那有不被抄。


接下来还是按着我们约定的来
关于组件篇我就直接拿demo再进行细化分析给大家讲一些细节的知识点,我相信会更有意思一点,为什么我要把基础给大家讲的那么详细呢,因为基础打的好组件才写的好
1.本文分享 解析饿了么(spinner组件)

2.代码运行vue-cli 2.1版本

3.组件代码都在components文件夹里

4.主代码逻辑都在 App.vue文件夹里

我什么都不要我只要

饿了么向外爆露出三个接口
color : 颜色 size : 大小 type : 样式类型

首先index.html,先用rem布局,原理略知一二,就不多说了,反正就是移动端给你做适配

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>y</title><meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"><script>(function(doc, win) {var docEl = doc.documentElement,resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',recalc = function() {var clientWidth = docEl.clientWidth;if (!clientWidth) return;if (clientWidth >= 640) {docEl.style.fontSize = '100px';} else {docEl.style.fontSize = 100 * (clientWidth / 640) + 'px';}};if (!doc.addEventListener) return;win.addEventListener(resizeEvt, recalc, false);doc.addEventListener('DOMContentLoaded', recalc, false);})(document, window);</script>
</head><body><div id="app"></div><!-- built files will be auto injected -->
</body></html>

接下来我们在components写spinner组件,这里我就写两个组件一个是snake,和double-bounce

首先我们在components先写一个snake,我们先创建一个spinner文件夹,就单个type形式的如何写,既然教大家了,就一步一步来写,写的麻烦点就麻烦点。

我的文件目录是在components里创了一个=》zk-spinner文件夹=》又创建了一个src文件夹=>又创建了一个snake.vue文件
components/zk-spinner/src/snake.vue

<template><div class='snake' :style="{'border-top-color' : spinnerColor,'border-left-color' : spinnerColor,'border-bottom-color' : spinnerColor,'height' : spinnerSize,'width' : spinnerSize}"></div>
</template>
<script>
export default {name : 'snake',computed : {spinnerColor () {return this.color || this.$parent.color || 'red'},spinnerSize () {return (this.size || this.$parent.size || .44)+'rem'}},props : {color : String,size :  Number}
}
</script>
<style>
.snake {animation : ziksang-spinner-rotate 0.8s infinite linear;border : 4px solid transparent;border-radius : 50%;
}
@keyframes  ziksang-spinner-rotate {0% {transform : rotate(0deg);transform : rotate(360deg)}
}</style>

App.vue

<template><snake></snake>
</template><script>
import snake from './components/zk-spinner/src/snake.vue'
export default {components : {snake}
}
</script><style>
</style>

你会发现一个小蛇就在来回的转啊转,很漂亮,这里只用到了向外暴露的两处一个是color,一个是颜色,这里用的是compunted来计算返回给template模板里,这时好处是什么呢,可以用默认样式,还可以用自己定样式
this.color || this.$parent.color || 'red'
(this.size || this.$parent.size || .44)+'rem'
这里代表如果自己没有设定样式则用父元素的样式,父元素没有样式,则用默认样式,你后续会发现 this.color 和 this.size和默认就是根本没有任何用的东西,这里设计的就是一个并句,回头看到后面我再给大家分析

我们再来写一个double-bounce样式
components/zk-spinner/src/double-bounce.vue

<template><div class="double-bounce" :style='{width:spinnerSize,height:spinnerSize}'><div class="double-bounce1" :style='{backgroundColor : spinnerColor}'></div><div class="double-bounce2" :style='{backgroundColor : spinnerColor}'></div></div>
</template><script>
export default {name : 'double-bounce',computed : {spinnerColor () {return this.color || this.$parent.color || 'red'},spinnerSize () {return (this.size || this.$parent.size || .44)+'rem'}},props : {color : String,size :  Number}
}
</script><style>
.double-bounce {position: relative;
}.double-bounce1, .double-bounce2 {width: 100%;height: 100%;border-radius: 50%;background-color: #67CF22;opacity: 0.6;position: absolute;top: 0;left: 0;-webkit-animation: bounce 2.0s infinite ease-in-out;animation: bounce 2.0s infinite ease-in-out;
}.double-bounce2 {-webkit-animation-delay: -1.0s;animation-delay: -1.0s;
}@-webkit-keyframes bounce {0%, 100% { -webkit-transform: scale(0.0) }50% { -webkit-transform: scale(1.0) }
}@keyframes bounce {0%, 100% { transform: scale(0.0);-webkit-transform: scale(0.0);} 50% { transform: scale(1.0);-webkit-transform: scale(1.0);}
}
</style>

App.vue

<template><div><snake></snake><double-bounce></double-bounce></div>
</template><script>
import snake from './components/zk-spinner/src/snake.vue'
import doubleBounce from './components/zk-spinner/src/double-bounce.vue'
export default {components : {snake,doubleBounce}
}
</script><style>
</style>

此时你会发现一个东西,其实本质上,做再多样spinner样式,只要去基于CSS3写一些东西,就可以了,我们可以借鉴前两天掘进里有一个人发的什么7种loading样式,我的收藏夹里有,你们可以去找一下,按照里面的样式,你可以做更多spinner
里面很多东西都是换汤不要药,从两个spinner里可以发现computed和props里面共用的都是同样的,那现在我有只有两个spinner,如果我现在有十个spinner可提供给大家用的,那启不是要写十下,基于编程思想,我要还是要抽取出来,我们提取到common.vue里

components/zk-spinner/src/common.vue

export default {computed: {spinnerColor() {return this.color || this.$parent.color || 'red'},spinnerSize() {return (this.size || this.$parent.size || .6) + 'rem'}},props: {color: String,size: Number}
}

现在问题来了,我们现在有两个组件,一个是snack,和 double-bounce,我们要更完善一点,再把他们两个挂到一个组件上,那就用到了动态组件,is来进行改造

<template><component :is="spinner"></component>
</template><script>const SPINNERS= ['snake',         //第一段'double-bounce']const parseSpinner = function(index){if({}.toString.call(index) == '[object Number]'){if(index >= SPINNERS.length){console.warn(`'${index}' spinner not found, use the default spinner.`);index = 0   //第二段}return SPINNERS[index]}if(SPINNERS.indexOf(index) === -1){console.warn(`'${index}' spinner not found, use the default spinner.`);index = SPINNERS[0]  //第三段}return index}export default {name : 'zk-spinner',computed : {spinner () {return `spinner-${parseSpinner(this.type)}`}    //第四段},components: {   //第五段SpinnerSnake: require('./src/snake.vue'),SpinnerDoubleBounce : require('./src/double-bounce.vue')},props: {type: {default: 0    //第六段},size: {type: Number,default: .6},color: {type: String,default: 'red'}}}
</script>

App.vue

<template><div><zk-spinner :type='1' color='#000' ></zk-spinner><zk-spinner :type='0' color='#000' ></zk-spinner> </div> </template><script> import zkSpinner from './components/zk-spinner/zk-spinner.vue' export default {components : {zkSpinner} } </script><style> </style>

我对这里进行详细的解释一下,以上我分了六段,我觉得按着顺序讲不一定是好事,我们按着我所学习的想法和你们说,
1.我先从props里的将要从父组件接收的数据,我在common.js里把this.color,this.size 和默认的都删除了,因为无论snake还是double-bounce他们的父组件是谁,是这个动态组件,本质上这个动态组件也就是他们一个挂载的地点,没有必要再进行数据传递,我们只要进行继承父组件接收的数据即可。所以this.color和this.size都没有没有用的,因为我们根本不传递数据,默认数据我们也在动态组件里进行设了default
2.我们再看看components里面,我们进行两个组件引入
3.我们再看看computed,我们通过计算属性,通过不同的计算返回不同的组件
4.我们再看看SPINNERS变量里,我们对组件名进行了定议
5.在第二段里当我们在type里传入的是一个数字的话,如果数字大于PINNERS变量的总长度,我们则默认给第一个样式,我们再给出提醒
6.在第三段里另一种传法,传入一个字符传,先对看SPINNERS变量进行一个匹配,如果匹配到则用这个,没有的话还是默认用snake这个样式,再给出warn提示

最后我们都明白了这三个用法了,type是如何封装出来的,size和color又是如何封装出来的,其实如果你真的能把组件系统搞明白了,对你的逻辑思维和封装一些js的能力也是一种提升,大型项目又有几个能做,所以vuex这东西大家只要没事看看api文档自己手动试试就没有什么问题了,如果有空的话,如果我够精通的话,我会给大家进行分享的,支持混元霹雳手ziksang,感谢大家!!!

  相关解决方案