吐血整理的前端代码规范系列 -- Vue组件设计规范

1,657 阅读3分钟

设计原则

一致性

  • **与现实生活一致:**与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;
  • **在界面中一致:**所有的元素和结构需保持一致,比如:设计样式、图标和文本、元素的位置等。

效率 

  • **简化流程:**设计简洁直观的操作流程;
  • **清晰明确:**明确输入输出

易扩展

  • 不掺杂明确的业务属性
  • 提供合理的插槽自定义

辅助代码分离

一个有效的原则就是将辅助代码分离出来放在特定的地方,这样你在处理组件时就不必考虑这些。以下列举一些方面:

  1. 配置代码
  2. 假数据
  3. 大量非技术说明文档

组件模板中使用简短的表达式

  • 复杂的行内表达式可读性比较差
  • 行内表达式不能在其他地方复用,会导致代码冗余
  • IDE不支持行内式表达式的语法校验
  • 将复杂的语法移动到methods或者计算属性中

扁平的化props

  • **组件的props根据实际情况进行合理拆解:**props只传递简单类型数据和函数,让组件的api看起来更像原生html的属性,并且让代码维护者和协作开发者明白传什么参数,不然的话如果props传递复杂数据类型,让你的组件很难重构,也会造成代码冗余。

假如我们现在一个对象数据源form,这个对象里面拥有的属性是一个零散的集合,里面有哪些属性自己并不尽知,并且组件只需要使用这个对象其中一部分的属性,这时我们应该对prop进行拆解。

/* bad */
<list-item :form="form"/>

/* good */
<list-item :phone="form.phone" :name="form.name" />
  • **组件的props定义规范化:**属性设置默认值;属性设置数据类型校验;使用组件之前检查props是否存在。
/* good */
 	 props: {
		modelData: {
            type: Array,
            default: () => []
        },
        roleData: {
            type: Object,
            default: () => ({})
        },
        isSelect: {
            type: Boolean,
            default: false
        },
        selectTitle: {
            type: String,
            default: ''
        }	
	}

更加纯粹的状态变化

对状态的更改通常应该响应某种事件,例如用户单击按钮或 API 的响应。此外它们不应该因为别的状态的变化而做出响应,因为状态之间这种关联可能会导致难以理解和维护的组件行为,状态变化应该没有副作用。

/* good */
watch: {
  pagination() {
    this.getDataFromApi()
  },
	searchText: {
  	handler() {
      // 重置页码
      if(this.pagination.page > 1) {
          this.pagination.page = 1
          return;
      }
      
    	this.getDataFromApi()
  	}
	}
},

当分页改变时,应用首先会通过 pagination 的处理函数重新获取数据。因此,如果我们改变了分页,我们并不需要去关注数据更新这段逻辑。

与实际业务代码松耦合

组件内代码只涉及到组件内部逻辑的实现,如果涉及到具体业务,因通过一些方式抽离出来,以此来增强组件的可复用性。大致的方式有以下两种:

  • 涉及到布局和样式的代码通过插槽分离到父组件去,以此来实现组件可以再各种布局场景下进行更好的复用
 // delete-modal组件里定义插槽
<isc-dialog :visible="dialogVisible" :before-close="handleClose">
   <slot name="content"></slot> 
</isc-dialog>

 // 父组件中,可自定义组件内容
 <delete-modal :dialogVisible.sync="dialogVisible" :title="'物模型'" @deleteClick="handleDelete">
   <template v-slot:content>
	 <p>确认删除"{{ deleteData.name }}"物模型吗?</p>
   </template>
 </delete-modal>
  • 涉及到接口调用,使用emit定义事件降低代码耦合性
//category-selec组件

<select @change="selectedChange"></select>

methods: {
    selectedChange(value) {
      this.$emit('change', value);
  }
}
// 父组件触发传来的api请求事件
<category-select @change="getData" />
  
methods: {
    getData(value) {
       const res = await service.get('/api/data', {
        id:value
   		 });
    }
}