最近在做的一個幾月vue的移動端小demo,其中有一塊是實現各個頁面的統一換膚功能的。本文主要介紹了基於vue的換膚功能的範例程式碼,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧。
一先看一下實現效果吧
#設定主題顏色
講道理這麼一個功能,我覺得這麼幾點可以說下,逐步實現:
1. 色值的選取
2. scss 的一些小眾用法(多變數CSS值的批次設定)
3. 全域事件巴士的應用
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;
4 設定並儲存一個全域顏色
介面的小事:我在首頁直接實現這個功能,專案中我引入了mint-ui 框架(餓了麼團隊的行動裝置框架,稍微遺憾使用感覺沒有element.ui 的舒服), 設定的互動就用彈層mt-popup 的形式好了,然後直接點擊色塊便設定對應顏色值<!-- 設置顏色 --> <mt-popup v-model="changColor" position="bottom" class="color-panel"> <p 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> </p> </mt-popup>接著就是色塊p的呈現,從上面程式碼發現,我會很容易出現類似這樣的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) ,将选取的颜色设置到全局,我的代码结构是这样的
子组件
68d8f6da816bfab17f7bba8f32b5bcb7 是 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 }) }
详细的实现请参照项目代码,这里我只挑一些比较清奇的点出来讨论,项目和代码的一些规范和习惯还是挺重要的,希望有好的实践能互相借鉴进步~
相关推荐:
jQuery结合jQuery.cookie.js插件实现换肤功能示例
Javascript结合css实现网页换肤功能_javascript技巧
以上是vue換膚功能實例教程的詳細內容。更多資訊請關注PHP中文網其他相關文章!