VueJS 开发常见问题集锦
VueJS 開發(fā)常見問題集錦
框架瀏覽數(shù):416
2017-8-3
 由于公司的前端開始轉(zhuǎn)向 VueJS,最近開始使用這個框架進(jìn)行開發(fā),遇到一些問題記錄下來,以備后用。
 主要寫一些 官方手冊 上沒有寫,但是實(shí)際開發(fā)中會遇到的問題,需要一定知識基礎(chǔ)。
涉及技術(shù)棧
- CLI: Vue-CLI
- UI: Element
- HTML: Pug(Jade)
- CSS: Less
- JavaScript: ES6
polyfill 與 transform-runtime
 首先,vue-cli 為我們自動添加了 babel-plugin-transform-runtime 這個插件,該插件多數(shù)情況下都運(yùn)作正常,可以轉(zhuǎn)換大部分 ES6 語法。
 但是,存在如下兩個問題:
 1、異步加載組件時,會產(chǎn)生 polyfill 代碼冗余
 2、不支持對全局函數(shù)與實(shí)例方法的 polyfill
 兩個問題的原因均歸因于 babel-plugin-transform-runtime 采用了沙箱機(jī)制來編譯我們的代碼(即:不修改宿主環(huán)境的內(nèi)置對象)。
   由于異步組件最終會被編譯為一個單獨(dú)的文件,所以即使多個組件中使用了同一個新特性(例如:Object.keys()),那么在每個編譯后的文件中都會有一份該新特性的 polyfill 拷貝。如果項(xiàng)目較小可以考慮不使用異步加載,但是首屏的壓力會比較大。
   不支持全局函數(shù)(如:Promise、Set、Map),Set 跟 Map 這兩種數(shù)據(jù)結(jié)構(gòu)應(yīng)該大家用的也不多,影響較小。但是 Promise 影響可能就比較大了。
   不支持實(shí)例方法(如:’abc’.include(‘b’)、[‘1’, ‘2’, ‘3’].find((n) => n < 2) 等等),這個限制幾乎廢掉了大部分字符串和一半左右數(shù)組的新特性。
 替換 babel-polyfill
 首先,從項(xiàng)目中移除 babel-plugin-transform-runtime
   卸載該依賴:
| npm un babel-plugin-transform-runtime -D | 
修改 babel 配置文件
| // .babelrc { ??//... ??"plugins": [ ????// - "transform-runtime" ??] ??//... } | 
然后,安裝 babel-polyfill 依賴:
| npm i babel-polyfill -D | 
最后,在入口文件中導(dǎo)入
| // src/main.js import 'babel-polyfill' | 
ES6 import 引用問題
   在 ES6 中,模塊系統(tǒng)的導(dǎo)入與導(dǎo)出采用的是引用導(dǎo)出與導(dǎo)入(非簡單數(shù)據(jù)類型),也就是說,如果在一個模塊中定義了一個對象并導(dǎo)出,在其他模塊中導(dǎo)入使用時,導(dǎo)入的其實(shí)是一個變量引用(指針),如果修改了對象中的屬性,會影響到其他模塊的使用。
   通常情況下,系統(tǒng)體量不大時,我們可以使用 JSON.parse(JSON.stringify(str)) 簡單粗暴地來生成一個全新的深度拷貝的 數(shù)據(jù)對象。不過當(dāng)組件較多、數(shù)據(jù)對象復(fù)用程度較高時,很明顯會產(chǎn)生性能問題,這時我們可以考慮使用?Immutable.js。
 鑒于這個原因,進(jìn)行復(fù)雜數(shù)據(jù)類型的導(dǎo)出時,需要注意多個組件導(dǎo)入同一個數(shù)據(jù)對象時修改數(shù)據(jù)后可能產(chǎn)生的問題。
 此外,模塊定義變量或函數(shù)時即便使用 let 而不是 const,在導(dǎo)入使用時都會變成只讀,不能重新賦值,效果等同于用 const 聲明。
在 Vue 中使用 Pug 與 Less
安裝依賴
Vue 中使用 vue-loader 根據(jù) lang 屬性自動判斷所需要的 loader,所以不用額外配置 Loader,但是需要手動安裝相關(guān)依賴:
| npm i pug -D npm i less-loader -D | 
還是相當(dāng)方便的,不用手動修改 webpack 的配置文件添加 loader 就可以使用了
 使用 pug 還是 pug-loader?sass 兩種語法的 loader 如何設(shè)置?
 — 請參考?預(yù)處理器 · vue-loader
使用
| <!-- xxx.vue --> <style lang="less"> ??.action { ????color: #ddd; ??????ul { ????????overflow: hidden; ????????li { ??????????float: left; ????????} ??????} ??} </style> <template lang="pug"> ??.action(v-if='hasRight') ????ul ??????li 編輯 ??????li 刪除 </template> <script> ??export default { ????data () { ??????return { ????????hasRight: true ??????} ????} ??} </script> | 
定義全局函數(shù)或變量
許多時候我們需要定義一些全局函數(shù)或變量,來處理一些頻繁的操作(這里拿 AJAX 的異常處理舉例說明)。但是在 Vue 中,每一個單文件組件都有一個獨(dú)立的上下文(this)。通常在異常處理中,需要在視圖上有所體現(xiàn),這個時候我們就需要訪問 this 對象,但是全局函數(shù)的上下文通常是 window,這時候就需要一些特殊處理了。
簡單粗暴型
   最簡單的方法就是直接在 window 對象上定義一個全局方法,在組件內(nèi)使用的時候用 bind、call 或 apply 來改變上下文。
   定義一個全局異常處理方法:
| // errHandler.js window.errHandler = function () { // 不能使用箭頭函數(shù) ??if (err.code && err.code !== 200) { ????this.$store.commit('err', true) ??} else { ????// ... ??} } | 
在入口文件中導(dǎo)入:
| // src/main.js import 'errHandler.js' 在組件中使用: // xxx.vue export default { ??created () { ????this.errHandler = window.errHandler.bind(this) ??}, ??method: { ????getXXX () { ??????this.$http.get('xxx/xx').then(({ body: result }) => { ????????if (result.code === 200) { ??????????// ... ????????} else { ??????????this.errHandler(result) ????????} ??????}).catch(this.errHandler) ????} ??} } | 
優(yōu)雅安全型
   在大型多人協(xié)作的項(xiàng)目中,污染 window 對象還是不太妥當(dāng)?shù)摹L貏e是一些比較有個人特色的全局方法(可能在你寫的組件中幾乎處處用到,但是對于其他人來說可能并不需要)。這時候推薦寫一個模塊,更優(yōu)雅安全,也比較自然,唯一不足之處就是每個需要使用該函數(shù)或方法的組件都需要進(jìn)行導(dǎo)入。
   使用方法與前一種大同小異,就不多作介紹了。 ̄
自定義路徑別名
可能有些人注意到了,在 vue-cli 生成的模板中在導(dǎo)入組件時使用了這樣的語法:
| import Index from '@/components/Index' | 
   這個 @ 是什么東西?后來改配置文件的時候發(fā)現(xiàn)這個是 webpack 的配置選項(xiàng)之一:路徑別名。
   我們也可以在基礎(chǔ)配置文件中添加自己的路徑別名,比如下面這個就把 ~ 設(shè)置為路徑 src/components 的別名:
| // build/webpack.base.js { ??resolve: { ????extensions: ['.js', '.vue', '.json'], ????alias: { ??????'vue$': 'vue/dist/vue.esm.js', ??????'@': resolve('src'), ??????'~': resolve('src/components') ????} ??} } | 
然后我們導(dǎo)入組件的時候就可以這樣寫:
| // import YourComponent from 'YourComponent' // import YourComponent from './YourComponent' // import YourComponent from '../YourComponent' // import YourComponent from '/src/components/YourComponent' import YourComponent from '~/YourComponent' | 
既解決了路徑過長的麻煩,又解決了相對路徑的煩惱,方便很多吧!
CSS 作用域與模塊
組件內(nèi)樣式
   通常,組件中
 
標(biāo)簽里的樣式是全局的,在使用第三方 UI 庫(如:Element)時,全局樣式很可能影響 UI 庫的樣式。我們可以通過添加 scoped 屬性來使 style 中的樣式只作用于當(dāng)前組件:
| <style lang="less" scoped=""> ??@import 'other.less'; ??.title { ????font-size: 1.2rem; ??} </style> | 
 在有 scoped 屬性的 style 標(biāo)簽內(nèi)導(dǎo)入其他樣式,同樣會受限于作用域,變?yōu)榻M件內(nèi)樣式。復(fù)用程度較高的樣式不建議這樣使用。
 另,在組件內(nèi)樣式中應(yīng)避免使用元素選擇器,原因在于元素選擇器與屬性選擇器組合時,性能會大大降低。
 — 兩種組合選擇器的測試:classes selector,elements selector
導(dǎo)入樣式
相對于 style 使用 scoped 屬性時的組件內(nèi)樣式,有時候我們也需要添加一些全局樣式。當(dāng)然我們可以用沒有 scoped 屬性的 style 來寫全局樣式。但是相比較,更推薦下面這種寫法:
| /* 單獨(dú)的全局樣式文件 */ /* style-global.less */ body { ??font-size: 10px; } .title { ??font-size: 1.4rem; ??font-weight: bolder; } | 
然后在入口文件中導(dǎo)入全局樣式:
| // src/main.js import 'style-global.less' | 
獲取表單控件值
通常我們可以直接使用 v-model 將表單控件與數(shù)據(jù)進(jìn)行綁定,但是有時候我們也會需要在用戶輸入的時候獲取當(dāng)前值(比如:實(shí)時驗(yàn)證當(dāng)前輸入控件內(nèi)容的有效性)。
這時我們可以使用 @input 或 @change 事件綁定我們自己的處理函數(shù),并傳入 $event 對象以獲取當(dāng)前控件的輸入值:
| <input type="text" @change="change($event)"> | 
| change (e) { ??let curVal = e.target.value ??if (/^\d+$/.test(curVal)) { ????this.num = +curVal ??} else { ????console.error('%s is not a number!', curVal) ??} } | 
當(dāng)然,如果 UI 框架采用 Element 會更簡單,它的事件回調(diào)會直接傳入當(dāng)前值。
v-for 的使用 tips
v-for 指令很強(qiáng)大,它不僅可以用來遍歷數(shù)組、對象,甚至可以遍歷一個數(shù)字或字符串。
基本語法就不講了,這里講個小 tips:
索引值
在使用 v-for 根據(jù)對象或數(shù)組生成 DOM 時,有時候需要知道當(dāng)前的索引。我們可以這樣:
| <ul> ??<li v-for="(item, key) in items" :key="key"> {{ key }} - {{ item }} </li></ul> | 
但是,在遍歷數(shù)字的時候需要注意,數(shù)字的 value 是從 1 開始,而 key 是從 0 開始:
| <ul> ??<li v-for="(v, k) in 3" :key="k"> {{ k }}-{{ v }} ??<!-- output to be 0-1, 1-2, 2-3 --> </li></ul> | 
2.2.0+ 的版本里,當(dāng)在組件中使用 v-for 時,key 現(xiàn)在是必須的。
模板的唯一根節(jié)點(diǎn)
與 JSX 相同,組件中的模板只能有一個根節(jié)點(diǎn),即下面這種寫法是 錯誤 的:
| <template> ??<h1>Title</h1> ??<article>Balabala...</article> </template> | 
我們需要用一個塊級元素把他包裹起來:
| <template> ??<div> ????<h1>Title</h1> ????<article>Balabala...</article> ??</div> </template> | 
原因參考:React-小記:組件開發(fā)注意事項(xiàng)#唯一根節(jié)點(diǎn)
項(xiàng)目路徑配置
由于 vue-cli 配置的項(xiàng)目提供了一個內(nèi)置的靜態(tài)服務(wù)器,在開發(fā)階段基本不會有什么問題。但是,當(dāng)我們把代碼放到服務(wù)器上時,經(jīng)常會遇到靜態(tài)資源引用錯誤,導(dǎo)致界面一片空白的問題。
這是由于 vue-cli 默認(rèn)配置的 webpack 是以站點(diǎn)根目錄引用的文件,然而有時候我們可能需要把項(xiàng)目部署到子目錄中。
我們可以通過 config/index.js 來修改文件引用的相對路徑:
| build.assetsSubDirectory: 'static' build.assetsPublicPath: '/' dev.assetsSubDirectory: 'static' dev.assetsPublicPath: '/' | 
我們可以看到導(dǎo)出對象中 build 與 dev 均有 assetsSubDirectory、assetsPublicPath 這兩個屬性。
其中 assetsSubDirectory 指靜態(tài)資源文件夾,也就是打包后的 js、css、圖片等文件所放置的文件夾,這個默認(rèn)一般不會有問題。
assetsPublicPath 指靜態(tài)資源的引用路徑,默認(rèn)配置為 /,即網(wǎng)站根目錄,與 assetsSubDirectory 組合起來就是完整的靜態(tài)資源引用路徑 /static。
寫到這里解決方法已經(jīng)很明顯了,只要把根目錄改為相對目錄就好了:
| build.assetsSubDirectory: 'static' build.assetsPublicPath: './' | 
沒錯!就是一個 . 的問題
 文章還在完善中,歡迎大家一起討論 Vue.JS 開發(fā)中遇到的一些問題哈 /
 話說收藏好多,你確定收藏了會記得看嗎_
 讀一讀開發(fā)的時候至少會有個印象,點(diǎn)個贊打卡啦~
 原文:VueJS 開發(fā)常見問題集錦
 https://blog.beard.ink/JavaScript/VueJS-開發(fā)常見問題集錦/
總結(jié)
以上是生活随笔為你收集整理的VueJS 开发常见问题集锦的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 抖音最近很火的梗有哪些是什么意思
- 下一篇: Web学习之跨域问题及解决方案
