基于vue的換膚功能的示例代碼
最近在做的一個(gè)幾月vue的移動(dòng)端小demo,其中有一塊是實(shí)現(xiàn)各個(gè)頁面的統(tǒng)一換膚功能的。想著寫一篇文章,來寫一寫實(shí)現(xiàn)過程中遇到的一些問題。
項(xiàng)目github地址
一 先看一下實(shí)現(xiàn)效果吧
設(shè)置主題顏色
講道理這么一個(gè)功能,我覺得這么幾點(diǎn)可以說下,分步實(shí)現(xiàn):
1. 色值的選取
2. scss 的一些小眾用法(多變量CSS值的批量設(shè)置)
3. 全局事件巴士的應(yīng)用
1 色值的選取和原則
推薦大家看下螞蟻金服的設(shè)計(jì)指引,里面對(duì)常見的交互和界面設(shè)計(jì)有一套不錯(cuò)的指引和建議,喜歡看書的也可以看看《寫給大家看的設(shè)計(jì)書》。
對(duì)于界面中的色彩元素,我們一般要保持視覺的連續(xù)性,即同一套色彩,盡量采取同一個(gè)色環(huán)上的色值
同一個(gè)圓環(huán)上的色值作為一套顏色會(huì)顯得更協(xié)調(diào)
所以這里采取ant design 的建議,取某一列色值作為我們的系列主題顏色(具體色值參照它的官網(wǎng)吧~)
而在某些特殊場合,需要表現(xiàn)出顏色的差異,如拋硬幣頁面的兩個(gè)顏色,
2 將格式色值轉(zhuǎn)換成十六進(jìn)制顏色值
這里我們通過設(shè)置主題顏色的透明度來實(shí)現(xiàn)區(qū)分不同顏色, 然后我們是通過存儲(chǔ)一個(gè)諸如 #123456 的16進(jìn)制顏色全局變量作為我們主題,這里就需要我們把這樣一個(gè)格式的色值轉(zhuǎn)化成 rgba 表示的顏色值啦,代碼如下,備用
hexToRgba (hex, opacity = 0.3) {
let color = []
let rgb = []
hex = hex.replace(/#/, '')
for (let i = 0; i < 3; i++) {
color[i] = '0x' + hex.substr(i * 2, 2)
rgb.push(parseInt(Number(color[i])))
}
return `rgba(${rgb.join(',')},${opacity})`
}
3 scss 的一些小眾用法
我們最終拿到這么一串我們想要的主題顏色
$colors: #f04134, #00a854, #108ee9, #f5317f, #f56a00, #7265e6, #ffbf00, #00a2ae, #2e3238;
一個(gè)很直接的思路,我們需要在各個(gè)view頁面里面,去定義我們需要設(shè)置主題的元素的顏色,比如文字和icon的color, 以及頭部的background 等。 于是我們?cè)赼pp 里面定義一個(gè)color變量,派發(fā)到各個(gè)view組件里面去,通過這個(gè)全局的變量來控制所有路由頁面的顏色,以實(shí)現(xiàn)不同的主題效果。
派發(fā)的實(shí)現(xiàn)在下一個(gè)部分說,這里我們先來完成我們的第一步,我們可以容易提取出我們的需求:
4 設(shè)置并保存一個(gè)全局顏色
界面的小事:
我在首頁直接實(shí)現(xiàn)這個(gè)功能,項(xiàng)目中我引入了mint-ui 框架(餓了么團(tuán)隊(duì)的移動(dòng)端框架,稍微遺憾使用感覺沒有element.ui 的舒服), 設(shè)置的交互就用彈層 mt-popup 的形式好了,然后直接點(diǎn)擊色塊便設(shè)置對(duì)應(yīng)顏色值
<!-- 設(shè)置顏色 -->
<mt-popup v-model="changColor" position="bottom" class="color-panel">
<div class="color-items">
<span class="color-item" v-for="(item, $index) in colors" :key="$index" @click="chooseColor(item)">
<span class="color-cycle" :class="'bg-color' + ($index + 1)"></span>
</span>
</div>
</mt-popup>
接著就是色塊div的呈現(xiàn),從上面代碼發(fā)現(xiàn),我會(huì)很容易出現(xiàn)類似這樣的css樣式表
.bg-color1 {background: #f04134}
.bg-color2 {background: #f04134}
.bg-color3 {background: #f04134}
.bg-color4 {background: #f04134}
···
寫代碼時(shí)候如果我們一般發(fā)現(xiàn),一件類似的東西重復(fù)出現(xiàn)了,就總隱隱覺得可以開始表演了,然后可預(yù)見的是,這樣的情況意味著在項(xiàng)目增長后,還可能出現(xiàn)許多單一設(shè)置字體顏色或border顏色的樣式表,諸如color1, borderColor1···,這樣每種形式的表現(xiàn)我們都需要根據(jù)我們主題顏色的數(shù)組去逐條書寫,修改成本也會(huì)變高 。于是我的書寫風(fēng)格是這樣的,
// mixin.scss:
$colors: #f04134, #00a854, #108ee9, #f5317f, #f56a00, #7265e6, #ffbf00, #00a2ae, #2e3238;
// setColor.vue:
@import '~@/assets/mixin.scss';
···
@for $i from 1 to 10 {
.bg-color#{$i} {
background-color: nth($colors, $i)
}
}
scss 除了常用的類名嵌套書寫外,還有許多···低調(diào)奢華的語法, 對(duì)于這類需要重復(fù)書寫的樣式類型,我的約定是添加一個(gè)scss變量在mixin 文件中, 在需要書寫重復(fù)循環(huán)樣式時(shí)候作為變量引入,并在書寫樣式時(shí)候,利用sass的循環(huán),引用其中對(duì)應(yīng)的值,這樣無論設(shè)置顏色的樣式怎么拓展和變化,變成顏色背景邊框都好,我都只需要維護(hù)一份mixin的的文件里的色值就行了, 同樣的實(shí)踐也可以應(yīng)用于項(xiàng)目里面字體大小和間距值的統(tǒng)一之類,總之我們多嘗試體驗(yàn)下吧
5 邏輯的小事
這個(gè)項(xiàng)目里面localstorage 基本被當(dāng)成數(shù)據(jù)庫使用了,所以點(diǎn)擊色塊設(shè)置主題時(shí)候,我們假裝發(fā)出請(qǐng)求,在localstorage存儲(chǔ)我們改變的顏色就好了( ./static/api.json 是一個(gè)返回helloword 的json, 為了寫實(shí)在這里這么用,$bus 事件巴士下面說, 作用就是設(shè)置全局的主題顏色變量,localStorage 模擬我們把設(shè)置存儲(chǔ)到后臺(tái),每次重新打開頁面就去獲取這些設(shè)置值), 目前為止,我們的設(shè)置頁面就大致完成了
// 假裝調(diào)用接口設(shè)置顏色
chooseColor (color) {
this.$axios.get('./static/api.json')
.then((data) => {
this.$bus.$emit('set-theme', color)
this.changColor = false
localStorage.setItem('themeColor', color)
})
.catch((data) => {
console.log(data)
})
}
6 事件巴士的運(yùn)用
在上一步最后我們有個(gè)關(guān)鍵的東西沒完成, this.$bus.$emit('set-theme', color) ,將選取的顏色設(shè)置到全局,我的代碼結(jié)構(gòu)是這樣的
子組件
<setColor> 是 home 頁面 的一個(gè)子組件,而在一開始我們已經(jīng)說了,我們想在我們?cè)赼pp.vue (home.vue和其他view的父組件) 里面定義一個(gè)color變量,派發(fā)到各個(gè)view組件里面去。 于是這其實(shí)就是個(gè),從 setColor 觸發(fā) app.vue 的設(shè)置顏色事件, 子組件向父組件通信的問題。
我們可以很直接地用綁定事件配合 emit() 的做法,在 app.vue 定義一個(gè) setglobalColor 方法, 并綁定到router-view(包含了home.vue),接著在home組件繼續(xù)定義一個(gè) setglobalColor 方法, 實(shí)現(xiàn)的功能就是 emit('setglobalColor') 去觸發(fā)app.vue的方法, 并把 home.vue 的這個(gè) setglobalColor 繼續(xù)綁定到組件, 組件里面點(diǎn)選顏色時(shí)候,直接emit這個(gè)方法就行了。
為什么我想用事件巴士.vue 的事件巴士和 vuex, 在一些有追求的程序員手里總是小心翼翼的,我也一樣,因?yàn)樽鳛樯婕叭值臇|西,一般覺得能不用就不用,代碼能精簡就精簡,我們經(jīng)常用一個(gè)詞,不提倡。
可是有朝一日我經(jīng)常在想,代碼的可讀性可維護(hù)性,和性能以及“風(fēng)險(xiǎn)”相對(duì)比,到底哪個(gè)更重要。對(duì)于事件巴士和vuex 這類全局性質(zhì)的方案的主要擔(dān)憂大部分在于, 他們是全局的,可能因?yàn)橐粋€(gè)事件名變量名一致就造成沖突,在小型項(xiàng)目還會(huì)造成冗余和額外開銷。 但事實(shí)上,事件和變量的命名我們都可以通過約定去規(guī)范,而在表現(xiàn)上,使用了事件巴士和vuex的項(xiàng)目,在性能上和直接 props 傳遞數(shù)據(jù),emit 回調(diào)事件的項(xiàng)目相比,其實(shí)并沒有太大區(qū)別,反而是無止境的 props 和 emit ,給人一種麻煩難以維護(hù)的感覺。 像上述的 setglobalColor , 僅僅是跨越了兩層組件, 過程就顯得繁瑣了。所以我建議在出現(xiàn)兩級(jí)以上組件層次,數(shù)據(jù)流稍微多的項(xiàng)目中都可以這么去做,定義一個(gè)全局的事件巴士
export default (Vue) => {
let eventHub = new Vue()
Vue.prototype.$bus = {
$on (...arg) {
eventHub.$on(...arg)
},
$off (...arg) {
eventHub.$off(...arg)
},
$emit (...arg) {
eventHub.$emit(...arg)
}
}
}
將事件巴士綁定到當(dāng)前vue對(duì)象,使用時(shí)候只需要:
this.$bus.$on('set-theme', (color) => {··· })
this.$bus.$emit('set-theme', '#000000')
在這個(gè)demo中,我在app.vue 綁定了
this.$bus.$on('set-theme', (color) => {
this.loadingColor = color
this.userinfo.color = color
})
而在 setColor.vue 則在點(diǎn)擊顏色塊時(shí)候觸發(fā) this.$bus.$emit('set-theme', color), 則能實(shí)現(xiàn)我們?cè)O(shè)置全局顏色的效果。這樣的好處在于,對(duì)于跨了多個(gè)層次,或者兄弟組件的通信,我們不再需要太繁瑣的props,比如我在header.vue 也綁定了 this.$bus.$on('set-theme', (color) => { }) ,在 this.$bus.$emit 發(fā)生時(shí)候,header 的背景顏色就能直接改變,而不需要等待app.vue 將 全局的color值props傳遞到header.vue里面(僅做示例,這里 header.vue 只是 app.vue 的下一層級(jí),通過props數(shù)據(jù)流會(huì)更清晰)
而對(duì)于其他路由頁面組件,和 app.vue 都是直接上下級(jí)關(guān)系,我們依然采用props保持一個(gè)清晰的數(shù)據(jù)流向下傳遞, demo 里我是將 color 存在userinfo(以后還有其他數(shù)據(jù)), userinfo傳到每個(gè)子路由, 最后,每個(gè)頁面在創(chuàng)建時(shí)候,通過拿到這個(gè)全局的顏色,再用dom去更改對(duì)應(yīng)的樣式就好啦,例如
mounted () {
this.$nextTick(() => {
// 綁定設(shè)置主題的事件,一旦觸發(fā)修改主題,則將當(dāng)前字體顏色改為對(duì)應(yīng)顏色
this.$el.querySelector('.myTitle').style.color = this.userinfo.color
this.$el.querySelector('.weui-btn_primary').style.backgroundColor = this.userinfo.color
this.$el.querySelector('.add_icon').style.color = this.userinfo.color
})
}
詳細(xì)的實(shí)現(xiàn)請(qǐng)參照項(xiàng)目代碼,這里我只挑一些比較清奇的點(diǎn)出來討論,項(xiàng)目和代碼的一些規(guī)范和習(xí)慣還是挺重要的,希望有好的實(shí)踐能互相借鑒進(jìn)步~
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Vue + Scss 動(dòng)態(tài)切換主題顏色實(shí)現(xiàn)換膚的示例代碼
- Vue項(xiàng)目實(shí)現(xiàn)換膚功能的一種方案分析
- vue+iview+less 實(shí)現(xiàn)換膚功能
- 使用vue + less 實(shí)現(xiàn)簡單換膚功能的示例
- Vue中使用sass實(shí)現(xiàn)換膚功能
- Vue 換膚的示例實(shí)踐
- vue實(shí)現(xiàn)換膚功能
- 基于Vue結(jié)合ElementUI的換膚解決方案
- vue項(xiàng)目實(shí)現(xiàn)一鍵網(wǎng)站換膚效果實(shí)例(webpack-theme-color-replacer的使用)
相關(guān)文章
詳解在Vue.js編寫更好的v-for循環(huán)的6種技巧
這篇文章主要介紹了詳解在Vue.js編寫更好的v-for循環(huán)的6種技巧,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
詳解如何在 vue 項(xiàng)目里正確地引用 jquery 和 jquery-ui的插件
本篇文章主要介紹了詳解如何在 vue 項(xiàng)目里正確地引用 jquery 和 jquery-ui的插件,具有一定的參考價(jià)值,有興趣的可以了解一下2017-06-06
Vue?ELement?Table技巧表格業(yè)務(wù)需求實(shí)戰(zhàn)示例
這篇文章主要介紹了Vue?ELement?Table技巧表格業(yè)務(wù)需求實(shí)戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
Vue ElementUI this.$confirm async await封
這篇文章主要介紹了Vue ElementUI this.$confirm async await封裝方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09

