随着js编程进入工程化纪元,代码模块化,组件化,成为工程的具体落地方法。javascript
最近使用vue全家桶作了一个相似于iconfont的网站,在作的过程当中关于组件有了一些思考和总结,为了巩固,写个小结。css
根据我已知的组件的编写方式,有四种介绍给你们:html
最基本的组件由一个.vue文件构成,其中包含了基本的tempplate,script, style三大元素。前端
能够经过props接收参数,$emit事件bus向父传递参数。vue
比较懒得我通常会在dev阶段在components文件夹里放置一个Demo.vue。写好基本的元素以及组件注释。java
import后在组件的compontents中声明就能够在模板里标签调用了。git
<template>
<!-- 指南中推荐组件名应该始终为多个单词的,根组件App,<transition>、<component>之类除外 -->
<Header></Header>
<shop-cart></shop-cart>
</template>
components: { Header, ShopCart }复制代码
这里比较注意的是组件命名规范应该严格参考vue风格指南。让驼峰和短横线在该使用的地方使用。github
构造类组件主要是用在想要经过js动态调用组件的场景里,由一个该组件文件夹好比notice,中包含Notice.vue, index.js两个文件组成。vuex
vue文件就是编写基本的vue文件编程
index.js中
/** 项目添加模态框 */
import Vue from 'vue'
import proModal from './ProModal.vue'
import store from '@/store/index'
import router from '@/router/index'
let proModalInstance
export default {
open (modalType, packageInfoDatail) {
if (!proModalInstance) {
proModalInstance = new ProModalCreater({
el: document.createElement('div'),
store: store,
router: router
})
document.body.appendChild(proModalInstance.$el)
}
proModalInstance.$data.modalType = modalType
proModalInstance.$data.options4 = []
proModalInstance.visible = true
modalType === 'modify'
? (() => {
proModalInstance.$data.packageInfoDetailTemp = packageInfoDatail
proModalInstance.$data.headerName = '修改项目'
proModalInstance.$data.value9 = []
packageInfoDatail.coUsers.map((item) => {
proModalInstance.$data.value9.push(item)
proModalInstance.$data.options4.push(item)
})
})()
: proModalInstance.init()
if (modalType === 'create' && packageInfoDatail) {
proModalInstance.fromPath = packageInfoDatail
}
// proModalInstance.$data.callback = callback
}
}复制代码
调用:
Vue.prototype._message = obj => {
obj.duration = messageDurationTime
ElementUI.Message(obj)
}
this._message.info('why so serious?')复制代码
import ProModal from '@/components/common/proModal'
methods: {
createPro () {
// 打开模态框
ProModal.open('create')
},
}复制代码
全局组件主要是用在一些通用组件想要在各处组件里使用标签调用的场景,组成与构建组件相同。
vue文件就是编写基本的vue文件(该注意的点仍是多注意下,全局对通用,颗粒的要求更高一些
index.js中
import NoContentComponent from './NoContent.vue'
// 添加install方法 (插件方法)
const NoContent = {
install: function (Vue) {
Vue.component('NoContent', NoContentComponent)
}
}
// 导出Buttonexport
default NoContent复制代码
在全局main.js中引入组件对象使用Vue.use()注册该组件
Vue.use(NoContent)复制代码
在各个组件中经过标签直接调用
<no-content v-if="!Array.isArray(iconLibNowDetail.icons)">
<template slot="default"> <span>尚未上传图标哦</span> <upload-btn :toPath="'/upload?type=iconLib&id=' + libId"></upload-btn> </template> </no-content>复制代码
指令类主要是使用Vue.directive方法注册一个指令,在指令中bind的方法中去实例组件并添加到响应dom处。这里很少说,由于我没用到。(想看怎么用的去看参考Vue组件的三种调用方式)
其结构相似于全局组件,只是调用是经过在某个元素上的指令属性进行调用。
好了,知道怎么写一个基本的组件了,路程刚刚开始,那么如何写好一个组件呢。若是你写的组件是为了目的而写不考虑设计原则,相信很快就会被你本身所抛弃,而后重构组件。(小伙伴说我这一节写的步骤有些乱不太好,后面会改进)
先说下个人组件设计思路:
这一节起的有点节题党,这里只是分享一点点点总结,不敢谈设计,后续有好的总结会更新上来,大佬们轻拍哈哈
组件在一些场景中会变得复杂,其复杂性分为组件自己的复杂和被应用场景的复杂。
自己比较复杂的组件如dataTimerPicker,Form之类的拥有复杂的配置项属性以及methods,events,而且其中会包含子组件,子组件的slot,attributes,methods也会不少。
这里仅仅分享三个场景:
1. 我在作一个IconList,当时想要一次性在组件中所有作好,就不想再多抽出子组件,结果发现会写的很冗余。因而很快就抽出了icon组件,IconList接受icons数组数据,在v-for中将item对象再传入icon组件,icon中经过props拿到iconData,最终用来渲染出最终显示的icon。
固然还能够再对icon进行子组件抽取的,我目前仍是采用配置参数iconModalType方式+v-if来区分项目中和图标库内在不一样权限下,三种modal层的显示。后面能够继续使用mixIn(IconModal.vue中使用)+调用时<icon-modal :modalType="icon.modalType">方式来加载。
组合大于继承,不用一次性去写一个庞然大物,这样会在复用的时候束手束脚失去灵活性。
2. 我在作一个FilterGroup,肯定了其核心是InputSearch结果到了后面发现仍是会遇到核心不肯定场景。因而这个时候FilterGroup只为ui服务,子元素能够经过slot来加载,slot中经过name将子组件放置到对应位置。下面是个demo,我当时就将InputSearch和Sort只做为了FilterGroup中的元素来处理了,致使了后续须要经过很长的配置项在group上去肯定groupElement上的属性,使Group自己属性被混淆减弱了自身含义,增长了复用时理解难度。
<!-- group合理设计应该为使用slot插入须要的groupElement而不是直接去集成div,即便是很是固有化的元素,如其中的两个元素:排序和搜索元素 -->
<btn-group inputPlaceVal="请搜索图标" :useSort="true" @sort="proSort" :sortOptions="options" @search="searchIcon" >
<template slot="body">
<div class="radius-btn" v-if="_isProManager() >= 2" @click="createPro">
<img :src="iconAddLib" alt="">
</div>
</template>
</btn-group>复制代码
正确的是应该去考衡抽出的必要性,假如该元素不复杂不须要传递数据自身无复杂方法,固定为ui项,就能够经过配置属性来取决其是否显示,好比element的input的icon,使用prefix-icon
和 suffix-icon
属性在 input 组件首部和尾部增长显示图标,固然在句尾说清了:也能够经过 slot 来放置图标 。由于slot伴随着子组件的编写,也是有代价的,因此对于一些默认最小项,我的认为能够内置编写好,经过配置属性来显示。
固然,能够看到,slot对于一个组件是多么的重要,一个复杂的子组件,一定不是一次性在组件内写好的,而是通过提取优化思考获得的一个组合结果,而且经得起复用和灵活扩展。
3. 我在作一个BatchOperate,批量操做组件时发现本身须要经过得到兄弟组件iconlist中被批量选择的icon的id数据,而且将这些icon加入ShopCart,这个时候对于数据以及状态的考量就来了。
最后选用了vuex加LocalStorage方式来解决了这个数据通讯的问题。(有点晚了,先不细说...)
这几个场景事最想表达的是:
在模块化思想的今天,这种抽出组合的思惟是很灵活的,能够在写组件的时候多去思考下模块化,包括公共方法,公共样式,vue的mixIn,scss的mixIn,公共变量仓库store集中处理,组件最下化,让重复性代码模块化抽出,再经过配置灵活组合。这种作法可让代码在后续的维护中很是清爽,一键修改专制各类公共改动,不再用跑到各个地方去作一下下的修改,而且避免了耦合带来的深层代码缠绕,能够说真的很好用了。
今天先写到这,第三节总结的不是很好,只是先罗列出本身以前想到的一些问题和处理,具体的优化想法会和组内小伙伴讨论后再更新的。