摘要:前言本文純屬個人平時實踐過程中的一些經驗總結,算是一點點小技巧吧,不是多么高明的技術,如果對你有幫助,那么不勝榮幸。由于涉嫌投機取巧,可能會帶來一些不符合規范的副作用,請根據項目要求酌情使用。
前言
本文純屬個人平時實踐過程中的一些經驗總結,算是一點點小技巧吧,不是多么高明的技術,如果對你有幫助,那么不勝榮幸。
本文不涉及罕見API使用方法等,大部分內容都是基于對vue的一些實踐而已。由于涉嫌投機取巧,可能會帶來一些不符合規范的副作用,請根據項目要求酌情使用。
多個頁面都使用的到方法,放在 vue.prototype 上會很方便
剛接觸 vue 的時候做過一件傻事,因為封裝了一個異步請求接口post,放在 post.js 文件里面,然后在每個需要使用異步請求的頁面引入
import port from "./xxxx/xxxx/post"
如果只是這樣,還沒什么,我們可以寫好一個頁面以后再復制,可以保證每個頁面都有上面的語句。但是如果每個文件所在的目錄層級不一樣呢?
// 假設正常是這樣 import port from "../xxxx/xxxx/post" // 目錄加深一級,就變成這樣 import port from "../../xxxx/xxxx/post" // 再加深一級的樣子 import port from "../../../xxxx/xxxx/post"
當然,這個時候,我們可以用 別名 @/xxxx/post,但是還是少不了要每個頁面引用。
那我們來看看,用vue.prototype 有多方便?
首先,你得在 vue 的入口文件( vue-cli 生成的項目的話,默認是 /src/main.js)里面做如下設置
import port from "./xxxx/xxxx/post" vue.prototype.$post = post
這樣,我們就可以在所有的 vue 組件(頁面)里面使用 this.post() 方法了,就像 vue 的親兒子一樣
tip: 把方法掛在到 prototype 上的時候,最好加一個 $ 前綴,避免跟其他變量沖突til again: 不要掛載太多方法到 prototype 上,只掛載一些使用頻率非常高的
需要響應的數據,在獲取到接口數據的時候,先設置
大家有沒有很經常碰到這樣都一種情況,在循環列表的時候,我們需要給列表項一個控制顯示的屬性,如 是否可刪除,是否已選中等等,而后端接口一般不會返回這種字段,因為這屬于純前端展示的,跟后端沒啥關系,比如后端給的數據如下
[ {name: "abc", age: 18}, {name: "def", age: 20}, {name: "ghi", age: 22}, ]
我們不妨假設以上數據為學生列表
然后我們需要渲染這個列表,在每一項后面顯示一個勾選按鈕,如果用戶打勾,則這個按鈕是綠色,默認這個按鈕是灰色,這個時候,上表是沒有滿足這個渲染條件的數據,而如果我們在用戶打勾的時候,再去添加這個數據的話,正常的做法是無法及時響應的。
如果我們在獲取到數據的時候,先給數組的每一項都加一個是否打勾的標示,就可以解決這個問題,我們假設我們獲取到的數據是 res.list
res.list.map(item => { item.isTicked = false })
這么做的原理是 vue 無法對不存在的屬性作響應,所以我們在獲取到數據的時候,先把需要的屬性加上去,然后在賦值給 data , 這樣 data 接收到數據的時候,已經是存在這個屬性了,所以會響應。當然還有其他方法可以實現。不過對于一個強迫癥來說,我還是比較傾向于這種做法
封裝全局基于 promise 的異步請求方法
看過很多項目的源碼,發現大部分的異步請求都是直接使用 axios 之類的方法,如下
axios({ method: "post", url: "/user/12345", data: { firstName: "Fred", lastName: "Flintstone" } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
如果有跨域,或者需要設置 http 頭等,還需要加入更多的配置,而這些配置,對于同一個項目來說,基本都是一樣的,不一樣的只有 url 跟參數,既然這樣,那我嗎為什么不把它封裝成一個方法呢?
function post (url,param) { return axios({ method: "post", url: url, data: param ... axios 的其他配置 }) }
tip: 這里原來我多用了一層promise包起來,對簡單的需求來說是太多余了,感覺掘金用戶 @日月為易。 指出
再結合第一點,我們就可以再任意 vue 實例中這樣使用
let param = { firstName: "Fred", lastName: "Flintstone" } this.post("/user/12345",param) .then(...) .catch(...)
有沒有比原始的簡單很多呢?如果你的項目支持 async await,還可以這樣用
let param = { firstName: "Fred", lastName: "Flintstone" } let res = await this.post("/user/12345",param) console.log(res) // res 就是異步返回的數據
tip: await 關鍵字必須在 被 async 修飾的函數里面使用
如果你覺得有時候,你真的需要父子組件共享一個值,不如試試傳個引用類型過去
vue 的父子組件傳值,有好多種方法,這里就不一一列舉了,但是今天我們要了解的,是利用 javascript 的引用類型特性,還達到另一種傳值的目的
假設有這么一個需求,父組件需要傳 3 個值到子組件,然后再子組件里面改動后,需要立馬再父組件上作出響應,我們通常的做法上改完以后,通過 this.$emit 發射事件,然后再父組件監聽對應的事件,然而這么做應對一兩個數據還好,如果傳的數據多了,會累死人。
我們不妨把這些要傳遞的數據,包再一個對象/數組 里面,然后在傳給子組件
data () { return { subData: { filed1: "field1", filed2: "field2", filed3: "field3", filed4: "field4", filed5: "field5", } } }
這樣,我們在子組件里面改動 subData 的內容,父組件上就能直接作出響應,無需 this.$emit 或 vuex 而且如果有其他兄弟組件的話,只要兄弟組件也有綁定這個 subData ,那么兄弟組件里面的 subData 也能及時響應
tip: 首先,這么做我個人上感覺有點不符合規范的,如果沒有特別多的數據,還是乖乖用 this.$emit 吧,其次,這個數據需要有特定的條件才能構造的出來,并不是所有情況都適用。
異步請求的參數在 data 里面構造好,用一個對象包起來,會方便很多
有做過類似 ERP 類型的系統的同學,一定碰到過這樣的一個場景,一個列表,有 N 個過濾條件,這個時候通常我們這么綁定
....
data () { return { field1: "value1", field2: "value2", field3: "value3", ... fieldn:"valuen" } }
然后提交數據的時候這樣:
var param = { backend_field1: this.field1, backend_field2: this.field2, backend_field3: this.field3, ... backend_fieldn: this.fieldn } this.post(url,param)
如你看到的,每次提交接口,都要去構造參數,還很容易遺漏,我們不妨這樣:先去接口文檔里面看一下后端需要的字段名稱,然后
....
```javascript data () { return { queryParam:{ backend_field1: "value1" backend_field2: "value2" backend_field3: "value3" ... backend_fieldn: "valuen" } } } ``` 然后提交數據的時候這樣: ```javascript this.post(url,this.queryParam) ```
是的,這樣做也是有局限性的,比如你一個數據在 2 個地方共用,比如前端組件綁定的是一個數組,你需要提交給后端的是 2 個字符串(例:element ui 的時間控件),不過部分特殊問題稍微處理一下,也比重新構建一個參數簡單不是嗎?
data 里面的數據多的時候,給每個數據加一個備注,會讓你后期往回看的時候很清晰
續上一點,data 里面有很多數據的時候,可能你寫的時候是挺清晰的,畢竟都是你自己寫的東西,可是過了十天半個月,或者別人看你的代碼,相信我,不管是你自己,還是別人,都是一頭霧水(記憶力超出常人的除外),所以我們不妨給每個數據后面加一個備注
data () { return { field1: "value1", // 控制xxx顯示 field2: "value2", // 頁面加載狀態 field3: [], // 用戶列表 ... fieldn: "valuen" // XXXXXXXX } }
邏輯復雜的內容,盡量拆成組件
假設我們有一個這樣的場景:
<-- 當然,顯示中我們不會傻到不用 v-for,我們假設這種情況無法用v-for -->姓名:{{user1.name}}性別:{{user1.sex}}年齡:{{user1.age}}...此處省略999個字段...他隔壁鄰居的阿姨家小狗的名字:{{user1.petName}}姓名:{{user2.name}}性別:{{user2.sex}}年齡:{{user2.age}}...此處省略999個字段...他隔壁鄰居的阿姨家小狗的名字:{{user2.petName}}
這種情況,我們不妨把[用戶]的代碼,提取到一個組件里面:
假設如下代碼,在 comUserInfo.vue
姓名:{{user.name}}性別:{{user.sex}}年齡:{{user.age}}...此處省略999個字段...他隔壁鄰居的阿姨家小狗的名字:{{user.petName}}
然后原來的頁面可以改成這樣(省略掉導入和注冊組件,假設注冊的名字是 comUserInfo ):
這樣是不是清晰很多?不用看注釋,都能猜的出來,這是2個用戶信息模塊, 這樣做,還有一個好處就是出現錯誤的時候,你可以更容易的定位到錯誤的位置。
如果你只在子組件里面改變父組件的一個值,不妨試試 $emit("input") ,會直接改變 v-model
我們正常的父子組件通信是 父組件通過 props 傳給子組件,子組件通過 this.$emit("eventName",value) 通知父組件綁定在 @eventName 上的方法來做相應的處理。
但是這邊有個特例,vue 默認會監聽組件的 input 事件,而且會把子組件里面傳出來的值,賦給當前綁定到 v-model 上的值
正常用法 - 父組件
正常用法 - 子組件
利用默認 input 事件 - 父組件
利用默認 input 事件 - 子組件
這樣,我們就能省掉父組件上的一列席處理代碼,vue 會自動幫你處理好
tip: 這種方法只適用于改變單個值的情況,且子組件對父組件只需簡單的傳值,不需要其他附加操作(如更新列表)的情況。
補充一個 this.$emit("update:fidldName",value) 方法 (感謝掘金用戶 @日月為易。 指出)
具體用法如下:
父組件
子組件
該方法,個人認為比較適用于 要更新的數據不能綁定在 v-model 的情況下,或者要雙向通信的數據大于 1 個(1個也可以用,但我個人更推薦 input 的方式, 看個人喜好吧),但又不會很多的情況下.
conponents放在 Vue options 的最上面
不知道大家有沒有這樣的經歷: 導入組件,然后在也頁面中使用,好的,報錯了,為啥?忘記注冊組件了,為什么會經常忘記注冊組件呢?因為正常的一個 vue 實例的結構大概是這樣的:
import xxx form "xxx/xxx" export default { name: "component-name", data () { return { // ...根據業務邏輯的復雜程度,這里省略若干行 } }, computed: { // ...根據業務邏輯的復雜程度,這里省略若干行 }, created () { // ...根據業務邏輯的復雜程度,這里省略若干行 }, mounted () { // ...根據業務邏輯的復雜程度,這里省略若干行 }, methods () { // ...根據業務邏輯的復雜程度,這里省略若干行 }, }
我不知道大家正常是把 components 屬性放在哪個位置,反正我之前是放在最底下,結果就是導致經常犯上述錯誤。
后面我把 components 調到第一個去了
import xxx form "xxx/xxx" export default { components: { xxx }, // 省略其他代碼 }
從此以后,媽媽再也不用擔心我忘記注冊組件了,導入和注冊都在同一個位置,想忘記都難。
大部分情況下,生命周期里面,不要有太多行代碼,可以封裝成方法,再調用
看過很多代碼,包括我自己之前的,在生命周期里面洋洋灑灑的寫了一兩百行的代碼,如:把頁面加載的時候,該做的事,全部寫在 created 里面,導致整個代碼難以閱讀,完全不知道你在頁面加載的時候,做了些什么,
這個時候,我們不妨把那些邏輯封裝成方法,然后在生命周期里面直接調用:
created () { // 獲取用戶信息 this.getUserInfo() // 獲取系統信息 this.getSystemInfo() // 獲取配置 this.getConfigInfo() }, methods:{ // 獲取用戶信息 getUserInfo () {...}, // 獲取系統信息 getSystemInfo () {...}, // 獲取配置 getConfigInfo () {...}, }
這樣是不是一眼就能看的出,你在頁面加載的時候做了些什么?
tip: 這個應該算是一個約定俗成的規范吧,只是覺得看的比較多這樣寫的,加上我自己初學的時候,也這么做了,所以寫出來,希望新入坑的同學能避免這個問題
少用 watch,如果你覺得你好多地方都需要用到 watch,那十有八九是你對 vue 的 API 還不夠了解
vue 本身就是一個數據驅動的框架,數據的變動,能實時反饋到視圖上去,如果你想要根據數據來控制試圖,正常情況一下配合 computed 服用就能解決大部分問題了,而視圖上的變動,我們一般可以通過監聽 input change 等事件,達到實時監聽的目的,
所以很少有需求使用到 watch 的時候,至少我最近到的十來個項目里面,是沒有用過 watch 當然,并不是說 watch 是肯定沒用處, vue 提供這個api,肯定是有他的道理,也有部分需求是真的需要用到的,只是我覺得應該很少用到才對,如果你覺得到處都得用到的話,
那么我覺得 十有八九你應該多去熟悉一下 computed 和 vue 的其他 api 了
本文的github地址 歡迎隨意star,follow, 和 不隨意的 issue
另外,github上還有其他一些關于前端的教程和組件,
有興趣的童鞋可以看看,你們的支持就是我最大的動力。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108256.html
摘要:斯坦福宣布使用作為計算機課程的首選語言近日,某位有年教學經驗的斯坦福教授決定放棄,而使用作為計算機入門課程的教學語言。斯坦福官方站點將它們新的課程描述為是最流行的構建交互式的開發語言,本課程會用講解中的實例。 前端每周清單第 11 期:Angular 4.1支持TypeScript 2.3,Vue 2.3優化服務端渲染,優秀React界面框架合集 為InfoQ中文站特供稿件,首發地址為...
摘要:感謝王下邀月熊分享的前端每周清單,為方便大家閱讀,特整理一份索引。王下邀月熊大大也于年月日整理了自己的前端每周清單系列,并以年月為單位進行分類,具體內容看這里前端每周清單年度總結與盤點。 感謝 王下邀月熊_Chevalier 分享的前端每周清單,為方便大家閱讀,特整理一份索引。 王下邀月熊大大也于 2018 年 3 月 31 日整理了自己的前端每周清單系列,并以年/月為單位進行分類,具...
閱讀 2491·2021-09-28 09:36
閱讀 1486·2021-09-22 15:33
閱讀 3635·2019-08-30 15:44
閱讀 1743·2019-08-29 13:14
閱讀 3132·2019-08-29 11:17
閱讀 1441·2019-08-29 11:03
閱讀 2904·2019-08-26 17:10
閱讀 681·2019-08-26 12:13