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