作者 混元霹靂手-ziksang
前兩天一個同學問我想叫我寫了一個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.js
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(Object.prototype.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,感謝大家!!!
渣渣前端開發工程師,喜歡鑽研,熱愛分享和講解教學, 微信 zzx1994428 QQ494755899
支援我繼續創作和感到有收穫的話,請向我打賞點吧
如果轉載請標註出自@混元霹靂手ziksang