zoukankan      html  css  js  c++  java
  • 【Vue】基于UI库二次组件封装——ant design table(包括支持slot插槽)

    vue现在使用非常广泛,对于一些公用的功能我们通常也会封装成组件,同时还有各类的UI组件库给我们开发提供了便利。

    为什么要封装成组件

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

    为什么要讲基于第三方UI库封装组件

    这段时间经手了几个项目,都是后台管理系统的,大家知道后台管理系统最多的就是table以及表单,几乎90%的页面都会包含这两个,但从中发现了好几个问题:

    第一,有些项目表格基本没有做封装,直接是使用的element-ui或者iview等UI库提供现成的copy过来的,然后很多页面可以看到的就是表格、表单的各种逻辑,而且每个页面基本代码都相似,不同的就是调用的接口,表单的配置。

    第二,虽然有些项目对表格或者表单进行了二次封装,但是维护起来却很不方便,参数都是通过一个一个传递过来,代码量大,并且slot也不支持,大大降低了灵活性。

    下面以antd-vue封装一个Table组件为例进行一个简单的封装实例。

    封装前考虑的问题?

    • 如何将自己定义的组件 可以支持库中当前组件所有接收参数和事件。

      如果通过参数一个个传 第一个参数太多,第二个 如果第三方库有更新增加了接受参数,自己库也需要进行更新。
    • 如何将所有传过来的值 挂载到UI库的组件上。
    • 如何支持插槽。

    如果能解决以上的三个问题,其实也就完成50%了,剩下的就是处理一些逻辑。

    我们先来解决第一个问题。

    一、如何将自己定义的组件 可以支持库中当前组件所有接收参数和事件。

    下面是antd官方的一个实例:

    <template>
      <a-table :columns="columns" :data-source="data">
        <a slot="name" slot-scope="text">{{ text }}</a>
      </a-table>
    </template>
    <script>
    const columns = [
      {
        title: 'Name',
        dataIndex: 'name',
        key: 'name',
        scopedSlots: { customRender: 'name' },
      },
      {
        title: 'Age',
        dataIndex: 'age',
        key: 'age',
         80,
      },
    ];
    
    const data = [
      {
        key: '1',
        name: 'John Brown',
        age: 32,
        address: 'New York No. 1 Lake Park, New York No. 1 Lake Park',
        tags: ['nice', 'developer'],
      },
      {
        key: '2',
        name: 'Jim Green',
        age: 42,
        address: 'London No. 2 Lake Park, London No. 2 Lake Park',
        tags: ['loser'],
      },
    ];
    
    export default {
      data() {
        return {
          data,
          columns,
        };
      },
    };
    </script>

    现在我要改成可以如下方式使用并且效果一样,tablePanel是我需要封装的组件。

    <template>
      <TablePanel :columns="columns" :data-source="data">
        <a slot="name" slot-scope="text">{{ text }}</a>
      </TablePanel>
    </template>
    <script>
    const columns = [
      // ...此处省略 同上
    ];
    
    const data = [
      // ...此处省略 同上
    ];
    
    export default {
      data() {
        return {
          data,
          columns,
        };
      },
    };
    </script>

    现在上方代码只传入了两个参数,官方文档是有15+个API参数可以配置的,如果我们一个个传进去,然后又通过props一个个接口这样特别繁琐,而且当UI库进行更新增加了参数时,组件又需要同步修改。

    其实每个组件都有一个props对象,我们只要把子组件的props赋给当前组件的props就可以继承子组件的所有属性了。

    TablePanel组件:

    <template>
        <a-table v-bind="$props" v-on="$listeners"/>//v-bind="$props"支持ant-design所有属性;v-on="$listeners"支持ant-design所有事件
    </template>
    
    <script>
    import {Table} from 'ant-design-vue'
    
    export default {
     props: {
        ...Table.props,
        ...myProps
      }     
    }
    </script>
    原文处理第二个和第三个问题的方法没有看懂,大家能看懂的告诉我一下哦,这里找到另一个方法解决第三个问题的:

    父组件:

             <body-table pageMethod="applyPage" :columns="columns">
                <span slot="status" slot-scope="row">
                    <a-icon v-show='row.status!=="0"' style="color:#bfbfbf" type="pause-circle" />
                    <a-icon v-show='row.status=="0"' class="ant-tag-green" type="check-circle" />
                </span>
                <span slot="type" slot-scope="scope">
                    <a-tag :color="row.type === 'private' ? 'orange' : 'green'">
                        {{ scope.record.type.toUpperCase() }}
                    </a-tag>
                </span> 
            </body-table>

    子组件:

                <a-table 
                size="small" bordered 
                @change="handleTableChange"
                :row-key="record => record.id" 
                :data-source="data" 
                :pagination="pagination"
                :rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange,columnWidth:39}" 
                :rowClassName="(record, index) => (index % 2 === 0 ? 'unOdd' : 'odd')"
                :scroll="{x: 1200, y: this.tableheight}"
                :columns="columns" 
                :loading="loading"  
                >
                    <template  v-for="column in columns"  :slot="column.scopedSlots?column.scopedSlots.customRender:''" slot-scope="text,record" >
                        <slot :name="column.scopedSlots?column.scopedSlots.customRender:''" v-bind:scope="record" ></slot>//绑定的scope可以在父组件中使用
                    </template>
                </a-table>

    参考:https://www.zhihu.com/question/339501753

    参考:https://segmentfault.com/a/1190000038483387

    v-on="$listeners"的用法详情见:https://www.cnblogs.com/vickylinj/p/13376391.html

  • 相关阅读:
    [NOI2008] [bzoj1061] 志愿者招募
    [bzoj1070] 修车
    [群内模拟4.8] 定点爆破 后宫着♂火 签到题
    初识费用流 模板(spfa+slf优化) 餐巾计划问题
    Chromium的无锁线程模型C++代码示例
    JavaScript的Date类的函数特殊处理导致的问题
    ssh免密码快速登录配置
    container-with-most-water(最大蓄水问题)
    死锁
    美团2018春招编程题第一题 字符串距离 O(n)解法
  • 原文地址:https://www.cnblogs.com/vickylinj/p/14629519.html
Copyright © 2011-2022 走看看