孔乙己顯出極高興的樣子,將兩個指頭的長指甲敲着櫃檯,點頭說,「對呀對呀!……回字有四樣寫法,你知道麼?」我愈不耐煩了,努着嘴走遠。孔乙己剛用指甲蘸了酒,想在櫃上寫字,見
我絕不熱心,便又嘆一口氣,顯出極可惜的樣子。
《「茴」字寫法》系列文章主要總結常見的代碼操做,給出多種實現方式,就像茴香豆的「茴」字有多種寫法同樣。
本文連接:https://www.taskhub.work/arti... javascript
規則千萬條,簡潔第一條vue
正文開始 java
Vue 組件有不少中寫法,在3.0以後會更好的支持typescript,ts用過都知道,真香,不管是代碼提示仍是代碼重構都很是方便,本人以前寫過一個UI庫大概4~5萬行規模,全用ts,期間發現不少不合理的地方,對UI庫進行重構,只花了2天時間。下面經過對比不一樣寫法。ios
UI 庫 | 實現方式 |
---|---|
muse-ui | 徹底不寫 <template> 只使用 render 函數 |
iview | 使用 .vue 文件,樣式單獨寫 |
element | 使用 .vue 文件,樣式單獨寫 |
vant | 使用 .vue 文件,樣式單獨寫 |
ant-design-vue | 使用 .jsx 文件,樣式單獨寫 |
vux | 使用帶 <style> 的 .vue 文件,但在使用時必須用 vux-loader |
cube-ui | 使用帶 <style> 的 .vue 文件,但有一些配置 |
在實際開發中用不用 *.vue 這樣的單文件組件來開發呢?
網上有不少網友吐槽Vue的單文件組件模式寫法,認爲Vue的模板語法很雞肋,各類不方便,不如所有jsx。決定這個問題的關鍵是解耦,包括功能解耦、模塊解耦、甚至框架解耦。*.vue文件組織方式雖然多少和Vue相關,可是實際操做時發現要解耦重構也不是很大的問題,因此還OK。git
import Vue, { PropOptions } from 'vue' interface User { firstName: string lastName: number } export default Vue.extend({ name: 'YourComponent', props: { user: { type: Object, required: true } as PropOptions<User> }, data () { return { message: 'This is a message' } }, computed: { fullName (): string { return `${this.user.firstName} ${this.user.lastName}` } } })
import { Vue, Component, Prop } from 'vue-property-decorator' interface User { firstName: string lastName: number } @Component export default class YourComponent extends Vue { @Prop({ type: Object, required: true }) readonly user!: User message: string = 'This is a message' get fullName (): string { return `${this.user.firstName} ${this.user.lastName}` } }
import Vue from 'vue' import { computed, value } from 'vue-function-api' interface User { firstName: string lastName: number } interface YourProps { user?: User } export default Vue.extend({ name: 'YourComponent', setup ({ user }: YourProps) { const fullName = computed(() => `${user.firstName} ${user.lastName}`) const message = value('This is a message') return { fullName, message } } })
寫法 | 優勢 | 缺點 |
---|---|---|
Object API | Vue 官方寫法,方便Vue直接處理組件 | 1. 代碼長、縮進多,組件複雜時難以理清邏輯,很差進行分割 2. 混入較多Vue的概念,新手學習成本高 |
Class API | 相關概念能夠用class的思路理解,能夠更好地描述Vue的混入、data、computed,生命週期鉤子等概念。Vue 3.0 將原生支持class寫法 | 用到了修飾器語法特性,目前還在實驗階段(typescript可使用helper函數解決兼容問題,問題不大) |
Function API | 無狀態,更好的單元測試、並行化 | 函數式寫法很容易寫出回調地獄,致使代碼可讀性、可維護性差,目前純粹function api 寫法較少見 |
完成一樣一件事,ts的class寫法簡潔得多,在工程較大時減小1/3左右的代碼,可維護性大大提升。github
使用class寫法會發現部分Vue的鉤子函數沒法使用問題,能夠經過註冊鉤子函數解決,以下:vue-router
import Component from 'vue-class-component' // Register the router hooks with their names Component.registerHooks([ 'beforeRouteEnter', 'beforeRouteLeave', 'beforeRouteUpdate' // for vue-router 2.2+ ])
使用vuex-class 解決,如state映射vuex
import { Vue, Component } from 'vue-property-decorator'; import { User } from '@/api/account'; import { State } from 'vuex-class'; @Component export default class TestPage extends Vue { @State(state => state.user, { namespace: 'account' }) user!: User; }
代碼常常須要各類錯誤,包括用戶輸入錯誤、安全檢測、後臺錯誤、網絡故障等。若是所有錯誤處理代碼放進組件中,代碼臃腫,閱讀性差,能夠將常見的錯誤處理邏輯提取出來,經過混入的方式插入組件中。class寫法推薦使用vue-property-decorator 的 Mixins,參考附錄typescript
附上模板代碼,解決大多數Vue typescript 組件問題
Vue class 組件axios
import { Vue, Component, Prop, Watch, Model, Mixins } from 'vue-property-decorator'; import { State, Getter, Action, Mutation } from 'vuex-class'; import axios, { AxiosError } from 'axios'; interface Person { userId: string; nickname: string; } @Component class CommonHandler extends Vue { onNetworkError(e: AxiosError) { console.log('on error'); } } @Component export default class Test extends Mixins(CommonHandler) { @Prop(Number) readonly propA: number | undefined @Prop({ default: 'default value' }) readonly propB!: string @Prop([String, Boolean]) readonly propC: string | boolean | undefined @Model('change', { type: Boolean }) readonly checked!: boolean message: string = 'hello world'; get propBLen(): number { return this.propB.length; } @Watch('child') onChildChanged(val: string, oldVal: string) {} @Watch('person', { immediate: true, deep: true }) onPersonChanged1(val: Person, oldVal: Person) {} @Watch('person') onPersonChanged2(val: Person, oldVal: Person) {} change() { console.log('on change'); } created() { // 調用混入中的錯誤處理函數,簡化代碼 axios.get('hello').catch(this.onNetworkError); } mounted() { console.log('mounted'); } }
Vue 官方寫法
import axios from 'axios'; const CommonHandler = { methods: { onNetworkError(e) { console.log('on error'); } }, } export default { mixins: [CommonHandler], props: { propA: { type: Number }, propB: { default: 'default value' }, propC: { type: [String, Boolean] } }, model: { prop: 'checked', event: 'change' }, data() { return { message: 'hello world', } }, computed: { propBLen() { return this.propB.length; }, }, watch: { child: [ { handler: 'onChildChanged', immediate: false, deep: false } ], person: [ { handler: 'onPersonChanged1', immediate: true, deep: true }, { handler: 'onPersonChanged2', immediate: false, deep: false } ] }, methods: { change() { console.log('on change'); }, onChildChanged(val, oldVal) {}, onPersonChanged1(val, oldVal) {}, onPersonChanged2(val, oldVal) {} }, // vue lifecycle hooks created() { // 調用混入中的錯誤處理函數,簡化代碼 axios.get('hello').catch(this.onNetworkError); }, mounted() { console.log('mounted'); } }
52行對比84行,一樣功能減小38%的代碼
最後打個廣告~
TaskHub 是咱們團隊開發的一個 Markdown 加密網盤,支持常見的任務管理功能還有Markdown 文件編輯,全部功能與平臺解耦,只使用Markdown的特性實現,更好的保障用戶的數據安全,實乃團隊協做之利器。歡迎你們使用~