您好,登錄后才能下訂單哦!
這篇文章給大家介紹vue中怎么實現一個換膚功能,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
1 色值的選取和原則
推薦大家看下螞蟻金服的設計指引,里面對常見的交互和界面設計有一套不錯的指引和建議,喜歡看書的也可以看看《寫給大家看的設計書》。
對于界面中的色彩元素,我們一般要保持視覺的連續性,即同一套色彩,盡量采取同一個色環上的色值
同一個圓環上的色值作為一套顏色會顯得更協調
所以這里采取ant design 的建議,取某一列色值作為我們的系列主題顏色(具體色值參照它的官網吧~)
而在某些特殊場合,需要表現出顏色的差異,如拋硬幣頁面的兩個顏色,
2 將格式色值轉換成十六進制顏色值
這里我們通過設置主題顏色的透明度來實現區分不同顏色, 然后我們是通過存儲一個諸如 #123456 的16進制顏色全局變量作為我們主題,這里就需要我們把這樣一個格式的色值轉化成 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;
一個很直接的思路,我們需要在各個view頁面里面,去定義我們需要設置主題的元素的顏色,比如文字和icon的color, 以及頭部的background 等。 于是我們在app 里面定義一個color變量,派發到各個view組件里面去,通過這個全局的變量來控制所有路由頁面的顏色,以實現不同的主題效果。
派發的實現在下一個部分說,這里我們先來完成我們的第一步,我們可以容易提取出我們的需求:
4 設置并保存一個全局顏色
界面的小事:
我在首頁直接實現這個功能,項目中我引入了mint-ui 框架(餓了么團隊的移動端框架,稍微遺憾使用感覺沒有element.ui 的舒服), 設置的交互就用彈層 mt-popup 的形式好了,然后直接點擊色塊便設置對應顏色值
<!-- 設置顏色 --> <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的呈現,從上面代碼發現,我會很容易出現類似這樣的css樣式表
.bg-color1 {background: #f04134} .bg-color2 {background: #f04134} .bg-color3 {background: #f04134} .bg-color4 {background: #f04134} ···
寫代碼時候如果我們一般發現,一件類似的東西重復出現了,就總隱隱覺得可以開始表演了,然后可預見的是,這樣的情況意味著在項目增長后,還可能出現許多單一設置字體顏色或border顏色的樣式表,諸如color1, borderColor1···,這樣每種形式的表現我們都需要根據我們主題顏色的數組去逐條書寫,修改成本也會變高 。于是我的書寫風格是這樣的,
// 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 除了常用的類名嵌套書寫外,還有許多···低調奢華的語法, 對于這類需要重復書寫的樣式類型,我的約定是添加一個scss變量在mixin 文件中, 在需要書寫重復循環樣式時候作為變量引入,并在書寫樣式時候,利用sass的循環,引用其中對應的值,這樣無論設置顏色的樣式怎么拓展和變化,變成顏色背景邊框都好,我都只需要維護一份mixin的的文件里的色值就行了, 同樣的實踐也可以應用于項目里面字體大小和間距值的統一之類,總之我們多嘗試體驗下吧
5 邏輯的小事
這個項目里面localstorage 基本被當成數據庫使用了,所以點擊色塊設置主題時候,我們假裝發出請求,在localstorage存儲我們改變的顏色就好了( ./static/api.json 是一個返回helloword 的json, 為了寫實在這里這么用,$bus 事件巴士下面說, 作用就是設置全局的主題顏色變量,localStorage 模擬我們把設置存儲到后臺,每次重新打開頁面就去獲取這些設置值), 目前為止,我們的設置頁面就大致完成了
// 假裝調用接口設置顏色 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 事件巴士的運用
在上一步最后我們有個關鍵的東西沒完成, this.$bus.$emit('set-theme', color) ,將選取的顏色設置到全局,我的代碼結構是這樣的
子組件
<setColor> 是 home 頁面 的一個子組件,而在一開始我們已經說了,我們想在我們在app.vue (home.vue和其他view的父組件) 里面定義一個color變量,派發到各個view組件里面去。 于是這其實就是個,從 setColor 觸發 app.vue 的設置顏色事件, 子組件向父組件通信的問題。
我們可以很直接地用綁定事件配合 emit() 的做法,在 app.vue 定義一個 setglobalColor 方法, 并綁定到router-view(包含了home.vue),接著在home組件繼續定義一個 setglobalColor 方法, 實現的功能就是 emit('setglobalColor') 去觸發app.vue的方法, 并把 home.vue 的這個 setglobalColor 繼續綁定到組件, 組件里面點選顏色時候,直接emit這個方法就行了。
為什么我想用事件巴士.vue 的事件巴士和 vuex, 在一些有追求的程序員手里總是小心翼翼的,我也一樣,因為作為涉及全局的東西,一般覺得能不用就不用,代碼能精簡就精簡,我們經常用一個詞,不提倡。
可是有朝一日我經常在想,代碼的可讀性可維護性,和性能以及“風險”相對比,到底哪個更重要。對于事件巴士和vuex 這類全局性質的方案的主要擔憂大部分在于, 他們是全局的,可能因為一個事件名變量名一致就造成沖突,在小型項目還會造成冗余和額外開銷。 但事實上,事件和變量的命名我們都可以通過約定去規范,而在表現上,使用了事件巴士和vuex的項目,在性能上和直接 props 傳遞數據,emit 回調事件的項目相比,其實并沒有太大區別,反而是無止境的 props 和 emit ,給人一種麻煩難以維護的感覺。 像上述的 setglobalColor , 僅僅是跨越了兩層組件, 過程就顯得繁瑣了。所以我建議在出現兩級以上組件層次,數據流稍微多的項目中都可以這么去做,定義一個全局的事件巴士
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) } } }
將事件巴士綁定到當前vue對象,使用時候只需要:
this.$bus.$on('set-theme', (color) => {··· }) this.$bus.$emit('set-theme', '#000000')
在這個demo中,我在app.vue 綁定了
this.$bus.$on('set-theme', (color) => { this.loadingColor = color this.userinfo.color = color })
而在 setColor.vue 則在點擊顏色塊時候觸發 this.$bus.$emit('set-theme', color), 則能實現我們設置全局顏色的效果。這樣的好處在于,對于跨了多個層次,或者兄弟組件的通信,我們不再需要太繁瑣的props,比如我在header.vue 也綁定了 this.$bus.$on('set-theme', (color) => { }) ,在 this.$bus.$emit 發生時候,header 的背景顏色就能直接改變,而不需要等待app.vue 將 全局的color值props傳遞到header.vue里面(僅做示例,這里 header.vue 只是 app.vue 的下一層級,通過props數據流會更清晰)
而對于其他路由頁面組件,和 app.vue 都是直接上下級關系,我們依然采用props保持一個清晰的數據流向下傳遞, demo 里我是將 color 存在userinfo(以后還有其他數據), userinfo傳到每個子路由, 最后,每個頁面在創建時候,通過拿到這個全局的顏色,再用dom去更改對應的樣式就好啦,例如
mounted () { this.$nextTick(() => { // 綁定設置主題的事件,一旦觸發修改主題,則將當前字體顏色改為對應顏色 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 }) }
關于vue中怎么實現一個換膚功能就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。