這周的主要的工做就是搭建新工程的架子,項目基於vue-cli構建。基本的功能在腳手架裏都已經具有,可是仍是須要針對具體的業務場景來作一些定製。css
以如今先後端分離的開發模式來說,一個正常的開發流程大概是這樣:
前端
這樣前端能夠不用等後端接口徹底寫完才能夠開發,先後端並行開發,提升團隊效率。vue
而腳手架提供的功能只有一個proxy,不能知足咱們的需求。因此須要咱們本身寫一個mock-middleware
。大概是這樣的一個功能,就不貼mock-middleware
的代碼了:webpack
module.exports = () => {
const argv = Array.prototype.slice.call(process.argv, 2);
const proxyAddress = argv[0];
if (!argv.length || proxyAddress === 'mock') {
return mockMiddleware;
} else {
return proxyMiddleware(proxyAddress);
}
}複製代碼
最終的效果就是運行 npm run dev mock
,會將api請求(注意:這裏只會代理api請求,而不代理靜態資源)轉發到mock數據。在先後端開發完成以後,能夠運行npm run dev {proxy_ip}
將api請求代理到某臺開發服務器進行聯調。git
固然這篇文章的重點不是這個,而是想總結下在SPA應用裏如何規範的寫CSS。github
故事的起點從組件庫的選擇提及,項目選擇了開源的element 做爲組件庫。而這套組件庫並不符合考拉前端組的視覺規範,而目前也沒有計劃fork一條分支來維護,因而就採起了比較簡單粗暴的作法,樣式覆蓋。先來看一段element中的樣式:web
@component-namespace el {
@b progress {
position: relative;
line-height: 1;
@e text {
font-size:14px;
display: inline-block;
vertical-align: middle;
margin-left: 10px;
line-height: 1;
}
@m circle {
display: inline-block;
}
}
}複製代碼
可能有同窗在剛看到這段樣式的時候會有點蒙,可是仔細看@b,@e,@m,不就是bem規範麼。
vue-cli
關於BEM規範,網上有不少文章介紹。知乎上也有一篇文章來討論其優劣,這裏不去討論BEM規範的好處和壞處,我以爲只要在一個工程里約定好一種規範並嚴格執行,這樣老是不會錯的。npm
一方面爲了和組件庫的CSS規範保持統一,另外一方面我我的以爲BEM的優勢仍是大於缺點,所以在項目裏也準備按照這個規範來寫。gulp
那麼問題來了,瀏覽器是不認識上面這些@b,@e,@m的語法的,這個時候就須要postcss來幫忙了。
postcss和gulp,webpack等工具同樣,他自己並非一種預處理器或者後處理器,而是經過各類插件來完成轉換(好比很流行的Autoprefixer就是它的一個插件)。
postcss-salad能夠認爲是一個postcss插件的集合,支持最新的css語法,一些sass嵌套的語法以及bem轉化。這時候先來一份配置文件postcss.config.js
:
module.exports = {
plugins: [
require('postcss-salad')({
browsers: ['ie > 9', 'last 2 versions'],
features: {
bem: {
shortcuts: {
component: 'b',
descendent: 'e',
modifier: 'm'
},
separators: {
descendent: '__',
modifier: '--'
}
}
}
})
]
}複製代碼
bem之間的鏈接符能夠自定義,這邊是爲了和element的組件保持一致。這時候咱們能夠先經過postcss-cli這個工具來看一下效果。咱們就用上述那段css來用postcss+postcss-salad進行轉換,獲得結果以下:
.el-progress {
position: relative;
line-height: 1
}
.el-progress__text {
font-size: 14px;
display: inline-block;
vertical-align: middle;
margin-left: 10px;
line-height: 1
}
.el-progress--circle {
display: inline-block
}複製代碼
已經達到了咱們預想的效果,那麼接下來要想在webpack中使用postcss確定會須要一個loader,也就是postcss-loader。
而後將剛纔的postcss.config.js做爲postcss-loader的配置文件導入。
{
loader: 'postcss-loader',
options: {
config: {
path: 'path/to/postcss.config.js'
}
}
}複製代碼
至此,就能夠在webpack項目中,用這種嵌套的bem語法來進行css的書寫了。
故事尚未結束,你們都知道在寫單頁面應用的時候,一個常見的需求是但願組件間的css做用域是互相隔離的。這時候第一反應想到就是Scoped CSS,vue-loader也是支持Scoped CSS的(實際上對CSS進行轉換的仍是postcss)。那麼Scoped CSS是如何來處理這個問題的呢:
<style scoped>
.example {
color: red;
}
</style>
=>
<style>
.example[_v-f3f3eg9] {
color: red;
}
</style>複製代碼
能夠看到Scoped CSS會在class後面加上一段hash,從而來實現CSS做用域的隔離,可是在實踐過程當中,會發現幾個問題:
這時候就須要CSS Modules出場了,CSS Modules是目前CSS模塊化方案中被接受度較高的一種方案,網上也有不少的文章去介紹它。一樣的,咱們須要先看下CSS Modules能作什麼事情呢?
剛纔講到,postcss有不少的插件,那麼確定也會有CSS Modules的插件了。咱們一樣經過以前的postcss-cli來進行測試,首先配置上這個插件:
require('postcss-modules')({
generateScopedName: '[local]--[hash:base64:5]'
})複製代碼
這裏的[local]表明類名,[hash:base64:5]按照給定規則生成的hash值,還能夠用的變量有[name]表明標籤名,[path]表明路徑等
CSS Modules 生成的class能夠自定義規則,所以也能夠用自定義的規則,而不用bem規範,能夠看項目的具體狀況來定
仍是一樣那段css代碼,看下轉換的結果:
.el-progress--3tuDF {
position: relative;
line-height: 1
}
.el-progress__text--1W8n3 {
font-size: 14px;
display: inline-block;
vertical-align: middle;
margin-left: 10px;
line-height: 1
}
.el-progress--circle--3OD0E {
display: inline-block
}複製代碼
跟咱們預設的樣式規則一致,這樣就能夠解決上述的第一個問題,作到每一個組件內的樣式是惟一的。
可是咱們發現CSS Modules一樣會改變class,那麼也一樣沒法在組件內覆蓋element組件的全局樣式,這時候能夠用CSS Modules的全局樣式寫法,:global{.class}
:
:global(.el-progress) {
position: relative;
line-height: 1;
}
=>
.el-progress {
position: relative;
line-height: 1;
}複製代碼
這樣就不會在class上加上hash後綴,從而能夠達到覆蓋全局樣式的目的。
首先在Vue-loader的配置文件中配置生成class規則:
cssModules: {
localIdentName: '[local]--[hash:base64:5]',
camelCase: true
}複製代碼
而後在組件內經過在style上添加module打開CSS Modules。
<style module>
</style>複製代碼
css-loader 會將一個 $style
對象注入到當前組件。因此在實際中使用大概是這個樣子:
<header :class="$style['titan-header']">
</header>複製代碼
有時候咱們會有這樣的用法:
<div :class="{ 'active': selectedIndex == index} ">
</div>複製代碼
這時候樣式就會做爲對象的屬性名,而咱們知道用了CSS Modules,就必須用$style.active
來替換'active'
,還好咱們有ES6!
ES6有一個特性是用雙括號支持用計算屬性做爲屬性名,也就是這樣:
<div :class="{ [$style.active]: selectedIndex == index} ">
</div>複製代碼
bem+CSS Modules在新項目的實踐已經有一週的時間,並無發現什麼問題,才寫下這篇文章來總結。以上只是我在本次工程搭建過程當中的一些總結,並不保證觀點徹底正確,供你們參考。