孔乙己显出极高兴的样子,将两个指头的长指甲敲着柜台,点头说,“对呀对呀!……回字有四样写法,你知道么?”我愈不耐烦了,努着嘴走远。孔乙己刚用指甲蘸了酒,想在柜上写字,见
我绝不热心,便又叹一口气,显出极可惜的样子。
《“茴”字写法》系列文章主要总结常见的代码操做,给出多种实现方式,就像茴香豆的“茴”字有多种写法同样。
本文连接: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的特性实现,更好的保障用户的数据安全,实乃团队协做之利器。欢迎你们使用~