• 怎么利用render函数对第三方UI组件进行二次封装


    上一篇文章介绍了《怎样高效地利用第三方UI组件》,以Input组件为例,介绍了一下怎么使用第三方的UI组件。

    实话实话,Input组件还是属于比较简单的组件,需要我们自己重写的东西还是比较少的。

    如果是Tabs组件呢?

    怎么二次封装Tabs组件

    我们先看一下element-ui组件的使用方式(官方示例):

    <template>
      <el-tabs v-model="activeName" @tab-click="handleClick">
        <el-tab-pane label="用户管理" name="first">用户管理</el-tab-pane>
        <el-tab-pane label="配置管理" name="second">配置管理</el-tab-pane>
        <el-tab-pane label="角色管理" name="third">角色管理</el-tab-pane>
        <el-tab-pane label="定时任务补偿" name="fourth">定时任务补偿</el-tab-pane>
      </el-tabs>
    </template>
    <script>
      export default {
        data() {
          return {
            activeName: 'second'
          };
        },
        methods: {
          handleClick(tab, event) {
            console.log(tab, event);
          }
        }
      };
    </script>
    

    是不是有点难受了?

    并不是我们简单的把参数传递过来,v-bind="$attrs"v-on="$listeners"就能解决的了。

    怎么办?

    诉求

    我们先看下,二次封装Tabs的诉求是什么?

    我肯定是不希望再写一堆el-tab-pane的,再配上label, name,那没啥意义,根本没有达到减少代码的目的。

    那就涉及到怎么把传递过来的$slots转换成el-tab-pane的内容的问题了。

    如果没有写过react,也不太了解render函数(确实基本上很少写render函数),那就有点困难了。

    怎么封装?

    事实上,我提供的方案,也是vue官方文档提供的,利用render函数写jsx。

    上代码吧!

    <script>
    let currentTab = null
    
    export default {
      name: "YvTabs",
      model: {
        prop: "value",
        event: "change"
      },
      props: {
        position: {
          type: String,
          default: "top",
          validator: val => ["top", "right", "bottom", "left"].includes(val)
        },
        value: {
          type: String,
          default: ""
        }
      },
      render(h) {
        return (
          <el-tabs
            tab-position={this.position}
            value={this.value}
            onTab-click={this.handleClick}
          >
            {this.$slots.default.map(tab => {
              const {
                data: {
                  key,
                  attrs: { name, type = null }
                }
              } = tab
              return (
                <el-tab-pane key={key} name={name} lazy>
                  {type ? (
                    <template slot="label">
                      {type === "icon" ? (
                        <i class={"el-icon-" + key} />
                      ) : (
                        <icon icon={key} />
                      )}
                      &nbsp;{name}
                    </template>
                  ) : <template slot="label">{name}</template> }
                  {tab}
                </el-tab-pane>
              )
            })}
          </el-tabs>
        )
      },
      methods: {
        handleClick(vm) {
          const { name = "" } = vm
          if (name !== currentTab) {
            currentTab = name
            this.$emit("change", name)
          }
        }
      }
    }
    </script>
    

    需要注意的是,在render函数内,是没有办法利用vue自定义的各种指令的,譬如v-model,不过,别难受,不能写就不写,v-model仅仅是语法糖,真没啥。

    还有一个就是el-tabs提供的事件tab-click,刚开始我很天真的以为:在jsx内要改成驼峰式的事件名称,就使用了onTabClick,我想很多人都可能跟我踩一样的坑的,然而,并不是,这里并不能用onTabClick,而是需要写成onTab-click,意不意外,惊不惊喜?

    剩下的就是对$slots的内容有点约束了,譬如每个DOM节点,需要传入key、 name、 type等字段,这个可以依据各自需求进行各种自定义。我这里key和name是对应el-tab-pane的属性label、name使用的,而type属性,纯粹是为了定义icon的,可以使用el-icon,也可以自定义各种图标字体,仅此而已。

    当习惯了render函数进行二次封装,也知道了v-bind="$attrs", v-on="$listeners",还有什么我们不可以进行封装的呢?

    下面就是各种愉快的玩耍了。

    只要在项目开始初期,按照设计图,自定义一遍各种组件的样式,剩下的就是各组件相互组合的问题了。

  • 相关阅读:
    MFC 错误异常,用vs添加资源并为资源定义类后报错:error C2065 : 未声明的标识符
    概率统计:数学期望、方差、协方差、相关系数、矩
    图像处理中的一些基本概念
    OpenCV中对Mat里面depth,dims,channels,step,data,elemSize和数据地址计算的理解
    C++语言运算符的功能、优先级和结合性
    标准C++中的string类的用法总结
    linux性能系列--块设备
    linux性能系列--网络
    linux性能系列--内存
    linux性能系列--cpu
  • 原文地址:https://www.cnblogs.com/zhuhuoxingguang/p/13048798.html
Copyright © 2020-2023  润新知