vue移動助手實踐(一)——用sass和事件巴士寫一個主題換膚

(By: Kath & kimmy)

最近在做的一個幾月vue的移動端小demo,其中有一塊是實現(xiàn)各個頁面的統(tǒng)一換膚功能的。想著寫一篇文章,來寫一寫實現(xiàn)過程中遇到的一些問題。

項目在線demo

項目在線演示demo(切換到移動端調(diào)試模式哦)

項目github地址

項目github地址

一 先看一下實現(xiàn)效果吧

設(shè)置主題顏色
講道理這么一個功能,我覺得這么幾點可以說下贿肩,分步實現(xiàn):
1. 色值的選取
2. scss 的一些小眾用法(多變量CSS值的批量設(shè)置)
3. 全局事件巴士的應(yīng)用

1 色值的選取和原則

推薦大家看下螞蟻金服的設(shè)計指引,里面對常見的交互和界面設(shè)計有一套不錯的指引和建議失仁,喜歡看書的也可以看看《寫給大家看的設(shè)計書》。
對于界面中的色彩元素们何,我們一般要保持視覺的連續(xù)性萄焦,即同一套色彩,盡量采取同一個色環(huán)上的色值

同一個圓環(huán)上的色值作為一套顏色會顯得更協(xié)調(diào)

所以這里采取ant design 的建議冤竹,取某一列色值作為我們的系列主題顏色(具體色值參照它的官網(wǎng)吧~)

而在某些特殊場合拂封,需要表現(xiàn)出顏色的差異,如拋硬幣頁面的兩個顏色鹦蠕,

2 將格式色值轉(zhuǎn)換成十六進(jìn)制顏色值

這里我們通過設(shè)置主題顏色的透明度來實現(xiàn)區(qū)分不同顏色冒签, 然后我們是通過存儲一個諸如#123456的16進(jìn)制顏色全局變量作為我們主題,這里就需要我們把這樣一個格式的色值轉(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;

一個很直接的思路,我們需要在各個view頁面里面肠阱,去定義我們需要設(shè)置主題的元素的顏色票唆,比如文字和icon的color, 以及頭部的background 等。 于是我們在app 里面定義一個color變量屹徘,派發(fā)到各個view組件里面去走趋,通過這個全局的變量來控制所有路由頁面的顏色,以實現(xiàn)不同的主題效果噪伊。
派發(fā)的實現(xiàn)在下一個部分說簿煌,這里我們先來完成我們的第一步氮唯,我們可以容易提取出我們的需求:
4 設(shè)置并保存一個全局顏色
界面的小事:
我在首頁直接實現(xiàn)這個功能,項目中我引入了mint-ui 框架(餓了么團(tuán)隊的移動端框架姨伟,稍微遺憾使用感覺沒有element.ui 的舒服)惩琉, 設(shè)置的交互就用彈層 mt-popup 的形式好了,然后直接點擊色塊便設(shè)置對應(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)琳水,我會很容易出現(xiàn)類似這樣的css樣式表

.bg-color1 {background: #f04134}
.bg-color2 {background: #f04134}
.bg-color3 {background: #f04134}
.bg-color4 {background: #f04134}
···

寫代碼時候如果我們一般發(fā)現(xiàn),一件類似的東西重復(fù)出現(xiàn)了般堆,就總隱隱覺得可以開始表演了在孝,然后可預(yù)見的是,這樣的情況意味著在項目增長后淮摔,還可能出現(xiàn)許多單一設(shè)置字體顏色或border顏色的樣式表私沮,諸如color1, borderColor1···,這樣每種形式的表現(xiàn)我們都需要根據(jù)我們主題顏色的數(shù)組去逐條書寫和橙,修改成本也會變高 仔燕。于是我的書寫風(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)奢華的語法晰搀, 對于這類需要重復(fù)書寫的樣式類型,我的約定是添加一個scss變量在mixin 文件中, 在需要書寫重復(fù)循環(huán)樣式時候作為變量引入办斑,并在書寫樣式時候外恕,利用sass的循環(huán),引用其中對應(yīng)的值乡翅,這樣無論設(shè)置顏色的樣式怎么拓展和變化鳞疲,變成顏色背景邊框都好,我都只需要維護(hù)一份mixin的的文件里的色值就行了蠕蚜, 同樣的實踐也可以應(yīng)用于項目里面字體大小和間距值的統(tǒng)一之類尚洽,總之我們多嘗試體驗下吧

5 邏輯的小事

這個項目里面localstorage 基本被當(dāng)成數(shù)據(jù)庫使用了,所以點擊色塊設(shè)置主題時候靶累,我們假裝發(fā)出請求腺毫,在localstorage存儲我們改變的顏色就好了( ./static/api.json 是一個返回helloword 的json, 為了寫實在這里這么用挣柬,$bus 事件巴士下面說拴曲, 作用就是設(shè)置全局的主題顏色變量,localStorage 模擬我們把設(shè)置存儲到后臺凛忿,每次重新打開頁面就去獲取這些設(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 事件巴士的運用

在上一步最后我們有個關(guān)鍵的東西沒完成, this.$bus.$emit('set-theme', color)叁熔,將選取的顏色設(shè)置到全局委乌,我的代碼結(jié)構(gòu)是這樣的

子組件

<setColor>home 頁面的一個子組件,而在一開始我們已經(jīng)說了荣回,我們想在我們在app.vue (home.vue和其他view的父組件) 里面定義一個color變量遭贸,派發(fā)到各個view組件里面去。 于是這其實就是個心软,從setColor 觸發(fā)app.vue的設(shè)置顏色事件壕吹, 子組件向父組件通信的問題。

我們可以很直接地用綁定事件配合emit()的做法删铃,在app.vue 定義一個setglobalColor方法耳贬, 并綁定到router-view(包含了home.vue),接著在home組件繼續(xù)定義一個setglobalColor方法猎唁, 實現(xiàn)的功能就是 emit('setglobalColor') 去觸發(fā)app.vue的方法咒劲, 并把home.vue的這個setglobalColor繼續(xù)綁定到<setColor>組件, 組件里面點選顏色時候诫隅,直接emit這個方法就行了腐魂。
為什么我想用事件巴士 .vue 的事件巴士和 vuex, 在一些有追求的程序員手里總是小心翼翼的逐纬,我也一樣蛔屹,因為作為涉及全局的東西,一般覺得能不用就不用豁生,代碼能精簡就精簡兔毒,我們經(jīng)常用一個詞,不提倡沛硅。
可是有朝一日我經(jīng)常在想眼刃,代碼的可讀性可維護(hù)性绕辖,和性能以及“風(fēng)險”相對比摇肌,到底哪個更重要。對于事件巴士和vuex 這類全局性質(zhì)的方案的主要擔(dān)憂大部分在于仪际, 他們是全局的围小,可能因為一個事件名變量名一致就造成沖突,在小型項目還會造成冗余和額外開銷树碱。 但事實上肯适,事件和變量的命名我們都可以通過約定去規(guī)范,而在表現(xiàn)上成榜,使用了事件巴士和vuex的項目框舔,在性能上和直接props傳遞數(shù)據(jù),emit 回調(diào)事件的項目相比,其實并沒有太大區(qū)別刘绣,反而是無止境的props 和 emit樱溉,給人一種麻煩難以維護(hù)的感覺。 像上述的setglobalColor, 僅僅是跨越了兩層組件纬凤, 過程就顯得繁瑣了福贞。所以我建議在出現(xiàn)兩級以上組件層次,數(shù)據(jù)流稍微多的項目中都可以這么去做停士,定義一個全局的事件巴士

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對象挖帘,使用時候只需要:

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則在點擊顏色塊時候觸發(fā) this.$bus.$emit('set-theme', color)恋技, 則能實現(xiàn)我們設(shè)置全局顏色的效果拇舀。這樣的好處在于,對于跨了多個層次猖任,或者兄弟組件的通信你稚,我們不再需要太繁瑣的props,比如我在header.vue 也綁定了this.$bus.$on('set-theme', (color) => { })朱躺,在 this.$bus.$emit發(fā)生時候刁赖,header 的背景顏色就能直接改變,而不需要等待app.vue 將 全局的color值props傳遞到header.vue里面(僅做示例长搀,這里header.vue只是app.vue的下一層級宇弛,通過props數(shù)據(jù)流會更清晰)
而對于其他路由頁面組件,和app.vue 都是直接上下級關(guān)系源请,我們依然采用props保持一個清晰的數(shù)據(jù)流向下傳遞枪芒,demo里我是將color存在userinfo(以后還有其他數(shù)據(jù)), userinfo傳到每個子路由谁尸, 最后舅踪,每個頁面在創(chuàng)建時候,通過拿到這個全局的顏色良蛮,再用dom去更改對應(yīng)的樣式就好啦抽碌,例如

mounted () {
    this.$nextTick(() => {
      // 綁定設(shè)置主題的事件,一旦觸發(fā)修改主題决瞳,則將當(dāng)前字體顏色改為對應(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ì)的實現(xiàn)請參照項目代碼货徙,這里我只挑一些比較清奇的點出來討論,項目和代碼的一些規(guī)范和習(xí)慣還是挺重要的皮胡,希望有好的實踐能互相借鑒進(jìn)步~

項目在線demo

項目在線演示demo(切換到移動端調(diào)試模式哦)

項目github地址

項目github地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末痴颊,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子屡贺,更是在濱河造成了極大的恐慌蠢棱,老刑警劉巖锌杀,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異泻仙,居然都是意外死亡抛丽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門饰豺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亿鲜,“玉大人,你說我怎么就攤上這事冤吨≥锪” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵漩蟆,是天一觀的道長垒探。 經(jīng)常有香客問我,道長怠李,這世上最難降的妖魔是什么圾叼? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮捺癞,結(jié)果婚禮上夷蚊,老公的妹妹穿的比我還像新娘。我一直安慰自己髓介,他們只是感情好惕鼓,可當(dāng)我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著唐础,像睡著了一般箱歧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上一膨,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天呀邢,我揣著相機(jī)與錄音,去河邊找鬼豹绪。 笑死价淌,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的森篷。 我是一名探鬼主播输钩,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼豺型,長吁一口氣:“原來是場噩夢啊……” “哼仲智!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起姻氨,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤钓辆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體前联,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡功戚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了似嗤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啸臀。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖烁落,靈堂內(nèi)的尸體忽然破棺而出乘粒,到底是詐尸還是另有隱情,我是刑警寧澤伤塌,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布灯萍,位于F島的核電站,受9級特大地震影響每聪,放射性物質(zhì)發(fā)生泄漏旦棉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一药薯、第九天 我趴在偏房一處隱蔽的房頂上張望绑洛。 院中可真熱鬧,春花似錦童本、人聲如沸诊笤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讨跟。三九已至,卻和暖如春鄙煤,著一層夾襖步出監(jiān)牢的瞬間晾匠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工梯刚, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留凉馆,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓亡资,卻偏偏與公主長得像澜共,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锥腻,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容