本文是本身vue項目實踐中的一些總結,針對Vue2及相關技術棧,實踐中版本爲2.3.3。javascript
在開發前,咱們要至少通讀一遍vue官方文檔和API(看官方文檔是最重要的,賽過看五10、一百篇博客),英文閱讀能力還行的建議閱讀英文文檔,中文文檔內容會稍落後,還要通讀相關的vue-router、axios、vuex等。css
通常來講咱們都是先利用vue-cli來搭建項目基本架構。html
vue-cli官方temaplte地址,咱們選擇webpack版本,建議看看其文檔vue-webpack-boilerplate瞭解基本用法和項目配置等。前端
深刻地瞭解vue-cli的webpack配置請查看vue-cli#2.0 webpack 配置分析vue
vue-cli雖然強大,可是它有不少個步驟要咱們去選擇配置,而實際上公司業務不少配置是固定的,好比咱們公司規定了要安裝vue-router、要使用Standard風格Eslint等,還規定了必須使用sass,這樣在vue-cli配置完成後還必需要npm install node-sass和sass-loader,還有axios等也是必定要安裝的。因此不該該每次新建一個項目都去一步步選擇vue-cli的那些配置而後還要去安裝sass等,應該在vue-cli基礎上根據公司自身的狀況打造團隊的腳手架,只需運行腳手架,就能夠初始化整個項目。java
建議在src/目錄增長views或pages目錄來存放對應路由的組件,添加api目錄,根據項目狀況增長filters、vuex等目錄。components目錄存放公共組件或者全局組件。每一個組件目錄能夠將圖片等資源放在一塊兒。組件的子組件目錄建議命名爲children放在父組件目錄下。如home組件目錄爲home/home.vue,子組件banner路徑爲home/chldren/banner/banner.vue。node
vue-webpack-boilerplate文檔中有靜態資源處理的詳細說明,但發現還有不少人都不知道,所以在這裏稍微提一下。webpack
vue-webpack-boilerplate的項目結構中,咱們有靜態資源兩個目錄:src/assets和static/ios
assets目錄中的文件會被webpack處理,只支持相對路徑形式,assets/logo.png會被編譯爲./assets/logo.png,不支持/assets/logo.pnggit
在js中,咱們能夠這樣獲取文件資源路徑
require('./assets/logo.png')
如下帶~前綴相似require效果
<img src="~assets/logo.png">
static目錄中的靜態資源不會被webpack處理,這裏適合放一些外部不須要webpack處理的資源,build後的靜態資源都會被放進這個目錄。
關於vue組件化,360奇舞團前端工程師鍾恆的pptVue.js實踐 如何使用Vue2.0開發富交互式WEB應用寫得很是好,本節內容也是出自其中。ppt中提到組件化帶來的新問題:通訊、複用、耦合,以及如何解決。
1)props和events:props down,events up
2)函數調用:this.refs
3)組件樹: $parent.$parent
4)共享state
5)eventbus
6)vue技術棧以外的如localstorage等
1)冗餘:if、else if、else判斷執行不一樣的代碼
if(this.type === 'editing') { // some editing code } else if(this.type === 'preview') { // some preview code } else if(this.type === 'present') { // some present code } else { // some base code }
2)包裝:slots
// plugin-page.vue <div> <slot name="page"> i am a page </slot> </div> // present-plugin-page.vue <div class="PresetPluginPage"> <plugin-page ref="page"> <h1 slot="page"> i am a present page </h1> </plugin-page> </div> //output <div class="PresetPluginPage"> <div> <h1> i am a present page </h1> </div> </div>
3)繼承:mixins
// define a mixin object var myMixin = { created: function () { this.hello() }, methods: { hello: function () { console.log('hello from mixin!') } } } // define a component that uses this mixin var Component = Vue.extend({ mixins: [myMixin] }) var component = new Component() // -> "hello from mixin!"
1)組件耦合帶來的問題:
2)解耦
解耦的本質就是將變化分離
1、組件功能單一
// wrong <control-input type="number"></control-input> // right <control-number></control-number>
2、採用穩定的接口
// wrong this.$parent.$parent.$refs['resource-image'].open() // right bus.$emit('open-resource-image')
3、處理好共享的部分
bindEvents (remove) { let method = remove ? 'removeEventListener' : 'addEventListener' window[method]('resize', this.handleResize) }
3)與服務端解耦
this.$http.get('/user/detail') .then(({body}) => { this.user = JSON.parse(body).data }, err => { console.error(err) }) user.detail().then(detail => this.detail = detail)
服務端與前端體系不一
同步異步轉換
多服務端/跨域的代碼
統一的錯誤處理代碼
1)不要濫用vuex
使用Vuex並不意味着你須要將全部的狀態放入Vuex。雖然將全部的狀態放到Vuex會使狀態變化更顯式和易調試,但也會使代碼變得冗長和不直觀。若是有些狀態嚴格屬於單個組件,最好仍是做爲組件的局部狀態。你應該根據你的應用開發須要進行權衡和肯定。
2)最好在根實例中註冊store選項,該store實例會注入到根組件下的全部子組件中,子組件能夠經過this.$store訪問,當狀態較多時使用建議mapState輔助函數。
3)polyfill
本次項目中使用了vuex,所以爲兼容IE9等低版本,須引入promise的polyfill--es6-promise。npm install後在main.js:
import 'es6-promise/auto'
爲了和後端進行數據交互,咱們通常引入axios庫。在main.js中以下將其加入vue的原型中,這樣能夠在組件中經過this.$http來獲取axios:
Object.defineProperty(Vue.prototype, '$http', { value: axios }) // 或者 Object.defineProperty(Vue.prototype, '$axios', { value: axios })
此次實踐中未採用這種作法,而是建立了一個getData.js進行了統一管理:
import axios from 'axios' const getSomething = (param1,param2) => axios.get(url,{ params: { param1: param1, param2: param2 } }) export { getSomething }
在單文件組件中import getSomething方法再進行調用便可。
直接在main.js中import你下載的iconfont.css便可
常見的需求是開發環境須console,而線上環境不能夠console。默認環境有'development'、'production'、'testing'三種。
if (process.env.NODE_ENV !== 'production') { console.log(data) }
數據模擬請求利用了mock.js,配置文檔,不過這個只是簡單的數據模擬,沒有生成文檔的功,更全面的文檔、Mock.js、可視化、Rest、接口過渡、文檔修改提醒、支持本地部署等功能可使用阿里RAP。
npm install mockjs安裝後,可在/src/api目錄下新建data.js,引入mockjs,後可在程序入口或api入口根據開發環境來引入data.js,下面是幾個示例:
import Mock from 'mockjs' let data = Mock.mock({ 'list|1-10': [{ 'id|+1': 1 }] }) // mock一個數據 console.log(JSON.stringify(data, null, 4)) import Mock from 'mockjs' Mock.setup({ timeout: '300‐500' }) Mock.mock(/\/login/, { code: 0 }) // 攔截login請求,返回對象{ code: 0 } import Mock from 'mockjs' Mock.setup({ timeout: '300‐500' }) Mock.mock(sitemap.cms.banners, { results: [] }) // 攔截sitemap中cms.banners請求,返回對象{ results: [] }
可使用服務端渲染或者預渲染,預渲染webpack插件github地址。
實際項目中仍是不可避免地要修改webpack配置,若是不知道怎麼改的話就去查看webpack的配置分析去進行修改。
要設置全局變量能夠在build中的webpack.base.conf.js中配置externals,與module同級:
externals: { sitemap: 'sitemap' }
而後在eslinttrc.js的module.exports添加這樣一個配置:
globals: { 'sitemap': false }
在這個項目中要根據環境(開發環境、測試環境、生產環境)的不一樣加載不一樣的sitemap.js,這個sitemap.js會暴露出一個全局的sitemap變量,sitemap變量是個由api地址構成的json對象。利用HtmlWebpackPlugin插件的option選項來實現。
在index.html中這樣寫:
<script src="<%= htmlWebpackPlugin.options.src %>"></script>
而後在build中的各自conf.js的HtmlWebpackPlugin設置不一樣的src,如在開發環境中添加src那一行:
new HtmlWebpackPlugin({ filename: 'index.html', template: 'index.html', src: '//dev.example.com/api/sitemap.js', inject: true })
在webpack.base.conf.js,vue-cli已經默認配置好了src目錄的別名爲@,建議配置src下一級目錄的別名,這樣能減小重複書寫也更美觀,以下添加src、pages、components別名:
resolve: { extensions: ['.js', '.vue', '.json'], alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src'), 'src': resolve('src'), 'pages': resolve('src/pages'), 'components': resolve('src/components') } }
可使用webpack插件image-webpack-loader來壓縮處理圖片。
實際就是添加多個入口js而後再修改相應配置,網上資料不少,一搜就知道了。
咱們有時候須要關閉某些代碼檢查,具體配置參見Configuring ESLint - ESLint中文,下面是常見的兩個:
1)關閉eslint
/* eslint-disable */ alert('foo') /* eslint-enable */
2)關閉禁止new
/* eslint-disable no-new */
1)因爲vue的追蹤對象變化原理基於使用Object.defineProperty,在處理大量數據而且不須要追蹤對象變化時,可經過Object.freeze(data)凍結對象達到優化數據渲染處理
2)vue-router路由懶加載。當打包構建應用時,javascript包會變得很是大,影響頁面加載。若是咱們能把不一樣路由對應的組件分割成不一樣的代碼塊,而後當路由被訪問的時候才加載對應組件,這樣就更加高效了。
1)使用表驅動法來註冊全局filter、指令等,如在src下新建filters目錄,index.js中import全部全局過濾器:
import milliFormat from './milliFormat' import reverse from './reverse' export default { milliFormat, reverse }
而後在main.js中註冊
import commonFiltes from './filters/index' Object.keys(commonFiltes).forEach(key => Vue.filter(key, commonFiltes[key]))
2)對於一些強耦合的組件如collapse和collapse-item,可使用$parent和$children來進行通訊,不必像elementUI同樣本身實現組件的broadcast和dispatch,我還發現有UI庫居然是使用bus來通訊的,這樣致使同一個頁面要是有兩個collapse,就會互相影響。
3)在根組件上註冊公共過濾器後,除了在「Mustache」語法中使用,還可在組件中經過this.$root.$options.filters.datetime(data)獲取datetime過濾器。
npm run build --report進行打包大小分析,可視化地看到有什麼地方須要優化。
build成功後有個tip提示你build後的文件須要部署在http服務器上,不能經過file協議打開。
咱們能夠經過node-static來啓動服務。能夠寫一個js配置文件經過node來啓動,或者CLI中輸入static dist(先安裝node-static):
$ static dist serving "dist" at http://127.0.0.1:8080
更多如設置端口等請點擊上面的連接查看文檔。
本文最重要的是文章中給出的一些連接,尤爲是開發前須知章節中的連接,最好點進去通讀一下。