天天看点

Vue elementUI 组件二次封装

一、Vue组件的功能

  1. 能够把页面抽象成多个相对独立的模块
  2. 实现代码重用,提高开发效率和代码质量,使得代码易于维护

二、Vue组件封装过程

  1. 建立组件的模板,定义通用样式,考虑组件的基本逻辑。
  2. 准备组件的数据输入。即分析好逻辑,定好 props 里面的数据、类型。
  3. 准备组件的数据输出。即根据组件逻辑,做好要暴露出来的方法。
  4. 封装完毕,在父组件中直接调用即可。

三、Vue组件封装要点

做好父组件与子组件的数据传输,保证数据的实时性传递。父组件一般通过props向子组件进行数据传输。子组件通过events向父组件发送消息。由于vue中数据为单向传输的特性,所以不可直接在子组件中修改父组件的值。通信原理图如下

::: hljs-center

Vue elementUI 组件二次封装

:::

四、Vue组件命名规则与全局注册

4.1 命名规则

规定将所有公用组件放于. \src\components\baseComponents文件夹下,系统文件会根据正则表达式进行公共组件扫描并进行全局注册。扫描注册采用PascalCase 命名法则,所以要求封装组件以ElXxxx.vue规则进行命名。引用规则为。

例如:

Select组件命名为TdSelect.vue。

在页面进行使用时,引用规则为</ el-select>

4.2. 全局注册

对baseComponents文件夹下进行扫面完成后,会对匹配到的组件进行全局注册发布。所以对于已经引用importResources.js的模块来说,可以直接按照上面的方法进行组件调用。

注:importResources.js属于公共引用文件所有模块都需要引用

五、具体示例封装过程展示

由于table表格在实际使用中应用比较广泛,依照Element官网进行table表格使用时代码篇幅较大且重复性的代码较多,所以结合官网特性以及实际使用情况进行封装使用。在封装完成后,只需要将封装完成的部件引入,将需要的表头数据传输到组件,即可创建完成。将后台查询数据传输到组件即可完成数据填充。

Table通常由如下几个部分组成:

• 表头

• 表格内容

• 操作栏事件

• 分页控件

下面将通过数据传输、属性控制、自定义事件三个方面详细讲述。

5.1数据传输

首先,我们应该在baseComponents文件夹下建立对应的.vue文件,按照Element官网的标准模式将用到的组件引入文件。将其属性值定义为v-bind的模式,采用组件默认值或者父组件定义的该属性的取值。如:height=“tableHeight”。hight为表格高度属性,tableHeight为属性值。

<!-- border 显示表格线 -->
<!-- v-loading.iTable 是否显示加载动画 -->
<!-- header-cell-style 表头样式设置 -->
<!-- tableHeight 表格高度设置 只接受number  -->
<el-table
    v-if="activeTable === true"
    :ref="tablesRef"
    border
    :stripe="stripe"
    :data="formatData"
    v-loading.iTable="hasLoading"
    :height="tableHeight"
>
    <!--region 选择框-->
    <el-table-column 
        v-if="hasMutiSelect" 
        type="selection" 
        width="40" 
        :selectable="selectable">
    </el-table-column>
    <!-- region 序号 -->
    <!--序号-->
    <el-table-column 
        v-if="hasIndex && !hasTreeTable" 
        align="center" 
        type="index" 
        width="55" 
        :label="vm.$t('common.SERIAL_NUMBER')">
    </el-table-column>
    <slot></slot>
    <!--主体部分-->
    <!-- 对于width属性不设置默认均分各列,可对某些进行宽度设置,其余各列均分,支持number -->
    <el-table-column
        v-for="(column, index) in showColumns"
        :prop="column.prop"
        :key="index"
        :label="vm.$t(column.label)"
        :align="column.align"
        :width="column.tableWidth"
        :type="column.type"
    >
        <!-- 操作栏相关按钮处理 -->
        <template slot-scope="scope">
            <my-render 
                v-if="column.render" 
                :row="scope.row" 
                :render="column.render" 
                :index="index">
            </my-render>
            <!-- 表格列是否可编辑 -->
            <template v-else-if="column.inputable">
                <td-input 
                    :width="column.tableWidth" 
                    v-model="scope.row[column.prop]"
                ></td-input>
            </template>
            <template v-else>
                {{ scope.row[column.prop] }}
            </template>
        </template>
    </el-table-column>
    <slot name="behind"></slot>
    <template name="append">
        <slot name="append"></slot>
    </template>
</el-table>
           
5.1.1父组件向子组件数据传输

组件实例的作用域是孤立的。这意味着不能 在子组件的模板内直接引用父组件的数据。父组件的数据需要通过 prop 才能下发到子组件中。也就是props是子组件访问父组件数据的唯一接口。

所以我们定义了props方法,用来接受父组件的参数。例如tableHeight属性在prop中进行定义。需要注意的是我们需要定义参数的参数类型,如,Object、String等,进行数据的一些校验工作。type定义类型。Default定义默认值。

/*  接收父组件参数 */
props: {
	tableHeight: {
		type: Number,
		default() { return window.screen.height * 0.65 }
	}
}
           

在父组件中的子组件标签进行属性值传递。

我们还需要了解一个vue的生命周期方法created,该方法与mounted作用相似只是渲染时间不同。created是在html渲染完成之前执行,在此正好可以解决我们对于一些属性值初始化的工作。

由于vue的特性,若父组件向子组件传递了某个对象,子组件中的对象就被覆盖掉,所以对于某个对象中包含多个属性的情况,可以再created方法中进行初始化化。当然对于某些不常用的值或者使用特别频繁的属性值建议单个属性值进行传递,方便操作。

5.1.2子组件向父组件的数据传输

在methods中,我们定义了currentChange方法,当当前页发生变化后触发该方法,然后通过this. this.$emit(‘currentChange’,val)通知父组件。'currentChange’为父组件方法名,val为参数。在父组件引用的子组件的标签上定义同名方法就可接到该信息传递,从而实现子组件向父组件的数据传输。

methods: {
	currentChange (val) {
		this.$emit('currentChange', val)
	}
}
           

我们可以在子组件中实现某些原声方法,比如焦点事件等。在焦点事件触发时可以调用父组件的订阅方法。实现子组件的中一些对外方法。

另外,对于需要实时更新的数据可以通过 :input(v-model) 和 :update(.sync) 进行实时跟新

5.2属性控制

在我们的实际开发过程中,有些属性值使用时不一样的,比如table中的序号、全选以及分页控件。做公共组件开发时就需要把这些属性值做成可配置的,以满足绝大多数的使用情况。

以分页组件举例,有的table比较简单占用空间也比较小所以此时正常的分页空间对象显示是无法满足使用的,所以出正常分页以为我们引入了简单分页,只包含最简单的功能。

所以在进行组件加载时会根据父组件的属性值展现组件信息。在vue中有v-if和v-else做布尔类型类型的判断。更多是根据属性值的数据进行加载。

5.3自定义事件

Table表格中的操作栏是根据不用的需求进行自定义操作的地方。需要使用者根据者自我定义。是否使用按钮,或者根据不同的表格数据展示不同的内容。

在父组件中引入了渲染函数render。该方法在2.0版本以后被限制为只可传输vNode节点。不过也正好可以满足我们的使用需求。render函数包括的三个参数,我们只用到了前两个。第一个参数可以用于创建一个节点数据,第二个参数则为本行数据信息。可以在porps定义基本信息在on中定义相应事件。不同的展示内容可以根据param进行数据判断。如图所示。我们定义了exit事件,参数为本行数据。在父组件的mothods中实现exit方法,则可进行表格的编辑操作,其他与此事件类似

// 组件封装
components: {
    MyRender: {
         functional: true,
         props: {
            row: Object,
            render: Function
         },
         render: (h, ctx) => {
            const params = {
                row: ctx.props.row,
                index: ctx.props.index
            };
            if (ctx.props.column) params.column = ctx.props.column;
                return ctx.props.render(h, params);
            }
        }
    }
}
           
// 父组件中使用
{
	label: '',
	key: '',
	width: '',
	render: (createElement, params) => {
		return createElement('div', [
			createElement('el-button', {
				props: {
					type: 'text',
					size: 'small'
				},
				on: {
					click: () => {
						// exit methods中的方法
						this.exit(params.row);
					}
				}
			}, '编辑')
		])
	}
}