基于VueJS的render渲染函数结合自定义组件打造一款非常强大的IView 的Table

1、render渲染函数的介绍

字符串模板的代替方案,允许你发挥 JavaScript 最大的编程能力。该渲染函数接收一个 createElement 方法作为第一个参数用来创建 VNode。

如果组件是一个函数组件,渲染函数还会接收一个额外的 context 参数,为没有实例的函数组件提供上下文信息。

2、如何使用render函数?

下面是vue官网的例子

var getChildrenTextContent = function (children) {
  return children.map(function (node) {
    return node.children
      ? getChildrenTextContent(node.children)
      : node.text
  }).join('')
}

Vue.component('anchored-heading', {
  render: function (createElement) {
    // 创建 kebabCase 风格的ID
    var headingId = getChildrenTextContent(this.$slots.default)
      .toLowerCase()
      .replace(/\W+/g, '-')
      .replace(/(^\-|\-$)/g, '')

    return createElement(
      'h' + this.level,
      [
        createElement('a', {
          attrs: {
            name: headingId,
            href: '#' + headingId
          }
        }, this.$slots.default)
      ]
    )
  },
  props: {
    level: {
      type: Number,
      required: true
    }
  }
})

3、iview table组件介绍

主要用于展示大量结构化数据。
支持排序、筛选、分页、自定义操作、导出 csv 等复杂功能。

4、iview table组件的使用

<template>
    <Table :columns="columns1" :data="data1"></Table>
</template>
<script>
    export default {
        data () {
            return {
                columns1: [
                    {
                        title: 'Name',
                        key: 'name'
                    },
                    {
                        title: 'Age',
                        key: 'age'
                    },
                    {
                        title: 'Address',
                        key: 'address'
                    }
                ],
                data1: [
                    {
                        name: 'John Brown',
                        age: 18,
                        address: 'New York No. 1 Lake Park',
                        date: '2016-10-03'
                    },
                    {
                        name: 'Jim Green',
                        age: 24,
                        address: 'London No. 1 Lake Park',
                        date: '2016-10-01'
                    },
                    {
                        name: 'Joe Black',
                        age: 30,
                        address: 'Sydney No. 1 Lake Park',
                        date: '2016-10-02'
                    },
                    {
                        name: 'Jon Snow',
                        age: 26,
                        address: 'Ottawa No. 2 Lake Park',
                        date: '2016-10-04'
                    }
                ]
            }
        }
    }
</script>

渲染成如下表格:
clipboard.png

5、iview table render函数和renderHeader介绍

render:

自定义渲染列,使用 Vue 的 Render 函数。传入两个参数,第一个是 h,第二个为对象,包含 row、column 和 index,分别指当前行数据,当前列数据,当前行索引,详见示例。 学习 Render 函数的内容

renderHeader:

自定义列头显示内容,使用 Vue 的 Render 函数。传入两个参数,第一个是 h,第二个为对象,包含 column 和 index,分别为当前列数据和当前列索引。

6、iview table render函数的使用

<template>
    <Table border :columns="columns7" :data="data6"></Table>
</template>
<script>
    export default {
        data () {
            return {
                columns7: [
                    {
                        title: 'Name',
                        key: 'name',
                        render: (h, params) => {
                            return h('div', [
                                h('Icon', {
                                    props: {
                                        type: 'person'
                                    }
                                }),
                                h('strong', params.row.name)
                            ]);
                        }
                    },
                    {
                        title: 'Age',
                        key: 'age'
                    },
                    {
                        title: 'Address',
                        key: 'address'
                    },
                    {
                        title: 'Action',
                        key: 'action',
                        width: 150,
                        align: 'center',
                        render: (h, params) => {
                            return h('div', [
                                h('Button', {
                                    props: {
                                        type: 'primary',
                                        size: 'small'
                                    },
                                    style: {
                                        marginRight: '5px'
                                    },
                                    on: {
                                        click: () => {
                                            this.show(params.index)
                                        }
                                    }
                                }, 'View'),
                                h('Button', {
                                    props: {
                                        type: 'error',
                                        size: 'small'
                                    },
                                    on: {
                                        click: () => {
                                            this.remove(params.index)
                                        }
                                    }
                                }, 'Delete')
                            ]);
                        }
                    }
                ],
                data6: [
                    {
                        name: 'John Brown',
                        age: 18,
                        address: 'New York No. 1 Lake Park'
                    },
                    {
                        name: 'Jim Green',
                        age: 24,
                        address: 'London No. 1 Lake Park'
                    },
                    {
                        name: 'Joe Black',
                        age: 30,
                        address: 'Sydney No. 1 Lake Park'
                    },
                    {
                        name: 'Jon Snow',
                        age: 26,
                        address: 'Ottawa No. 2 Lake Park'
                    }
                ]
            }
        },
        methods: {
            show (index) {
                this.$Modal.info({
                    title: 'User Info',
                    content: `Name:${this.data6[index].name}<br>Age:${this.data6[index].age}<br>Address:${this.data6[index].address}`
                })
            },
            remove (index) {
                this.data6.splice(index, 1);
            }
        }
    }
</script>

渲染成如下table

clipboard.png

7、iview render和renderHeader结合自定义组件,渲染table表格

QiDropdown.vue组件代码如下:

<style lang="postcss" scoped>
.dd{
    & .ivu-select-dropdown{
        max-height: 100% !important;
    }
    & .ivu-select-dropdown{
        max-height: 100% !important;
    }
    & >.ddm{
        text-align: left;
        font-weight:normal;
        & .active{
            color:#008cee
        }
    }    
}
</style>
<template>
<div class="dd">
    <Dropdown :placement="placement" @on-click="ddClick" transfer >
        <span v-if="content.length > 0" style="cursor:pointer">
            {{content}}            
            <Icon type="arrow-down-b" v-if="showArrow"/>
        </span>
        <Icon type="plus" v-else style="cursor:pointer"></Icon>
        <DropdownMenu slot="list" class="ddm">
            <DropdownItem v-for="(item, index) in data" :key="index" :name="item.value" 
                :style="{color:localChoosedItem == item.value ? activeColor:defaultColor}">{{item.name}}</DropdownItem>
            <slot name="diy"></slot>
        </DropdownMenu>
    </Dropdown>
</div>
</template>
<script>
export default {
    data(){
        return{
            activeColor:'#008cee',
            defaultColor:'#495060',
            localChoosedItem:''
        }
    },
    props:{
        placement:{
            type:String,
            default:'bottom-start'
        },
        showArrow:{
            type:Boolean,
            default:false
        },
        content:{
            type:String,
            default:''
        },
        data:{
            type:Array,
            default:()=>{
                return [];
            }
        },
        choosedItem:{
            type:String,
            default:''
        }
    },
    watch:{
        choosedItem:{
            immediate:true,
            handler(newv,oldv){
                this.localChoosedItem = newv;
            }
        }
    },
    created(){

    },
    methods:{
        ddClick(name){
            this.$emit('on-choosed',name);
            this.localChoosedItem = name;
        }
    }
}
</script>

8、父组件引入QiDropdown组件并应用到table 的render和renderHeader函数中

import QiDropdown from '@/components/QiDropdown'

export default {
    name: 'email-list',
    components:{
        QiDropdown
    },
...
columns: [
                {
                    title: '标注',
                    key: 'callout',
                    align:'center',
                    renderHeader:(h,params)=>{
                        return h(QiDropdown,{
                            props:{                                
                                placement:'bottom-start',
                                showArrow:true,
                                content:'标注',
                                data:this.flags
                            },
                            on:{
                                'on-choosed':(value)=>{        
                                    this.queryForm.callout = value;                            
                                    this.getResumeFromEmailBy();
                                }
                            }
                        });
                    },
                    render:(h,params)=>{
                        return h(QiDropdown,{
                                props:{
                                    content:params.row.callout||'',
                                    data:this.flags.slice(1)
                                },
                                on:{
                                    'on-choosed':(value)=>{
                                        this.choosedFlag(params.row.id,value);    
                                    }
                                }
                            },[ 
                                h('DropdownItem',
                                {
                                    slot: 'diy',
                                    style:{
                                        color:'#2d8cf0'
                                    },
                                    props:{
                                        name:'add',
                                        divided:true
                                    }
                                }, 
                                '添加并标注'),
                                h('DropdownItem',
                                {
                                    slot: 'diy',
                                    style:{
                                        color:'#2d8cf0'
                                    },
                                    props:{
                                        name:'clear'
                                    }
                                }, 
                                '清除该标注')
                            ]);
                        
                    }
                }, 
                ...

渲染成如下所示:
clipboard.png

clipboard.png

9、总结:

1)有了render函数加上自定义组件,那么你再也不怕iview table组件功能的单调了,一开始我也以为iview table功能太少,现在有了它,你可以实现你任何想实现的表格了,非常简单!

2)iview Dropdown组件上一定要加 transfer 属性,否则它不能正常显示出来

3)render函数可以使用slot,如我的QiDrowdown组件里面有一个slot name=diy,那它在render函数里面就是要写到QiDrowdownr 数组中,如:

h(QiDrowdown,
{//这里写QiDrowdown属性props、事件on、样式style等等},
[//这里可以写slot组件,也可以是其它组件,如果是slot你要这样写:
    h('DropdownItem',
                                {
                                    slot: 'diy',//记住这里要写上QiDrowdown组件slot的name
                                    style:{
                                        color:'#2d8cf0'
                                    },
                                    props:{
                                        name:'add',
                                        divided:true
                                    }
                                }, 
                                '添加并标注'),
                                
这样渲染就等于是这样写:
<QiDrowdown>
    <DropdownItem slot="diy" style="color:#2d8cf0" name="add" divided></DropdownItem>
</QiDrowdown>
])
h('组件名', {组件属性(包括vue相关的props)}, [子组件或者子节点或者文本])
{
  // 和`v-bind:class`一样的 API
  'class': {
    foo: true,
    bar: false
  },
  // 和`v-bind:style`一样的 API
  style: {
    color: 'red',
    fontSize: '14px'
  },
  // 正常的 HTML 特性
  attrs: {
    id: 'foo'
  },
  // 组件 props
  props: {
    myProp: 'bar'
  },
  // DOM 属性
  domProps: {
    innerHTML: 'baz'
  },
  // 事件监听器基于 `on`
  // 所以不再支持如 `v-on:keyup.enter` 修饰器
  // 需要手动匹配 keyCode。
  on: {
    click: this.clickHandler
  },
  // 仅对于组件,用于监听原生事件,而不是组件内部使用 `vm.$emit` 触发的事件。
  nativeOn: {
    click: this.nativeClickHandler
  },
  // 自定义指令。注意事项:不能对绑定的旧值设值
  // Vue 会为您持续追踪
  directives: [
    {
      name: 'my-custom-directive',
      value: '2',
      expression: '1 + 1',
      arg: 'foo',
      modifiers: {
        bar: true
      }
    }
  ],
  // Scoped slots in the form of
  // { name: props => VNode | Array<VNode> }
  scopedSlots: {
    default: props => createElement('span', props.text)
  },
  // 如果组件是其他组件的子组件,需为插槽指定名称
  slot: 'name-of-slot',
  // 其他特殊顶层属性
  key: 'myKey',
  ref: 'myRef'
}

注:如果你使用图片,src应该如下配置

render: (h, params)=>{
    return h('img', {
        style:{
            width: '100px'
        },
        domProps:{
            src: params.row.material_img,
        }
    })
}

10、引用

1)vue Render中slots的使用
2)渲染函数 & JSX
3)理解Vue中的Render渲染函数

阅读 14.9k

推荐阅读
全栈工程师进阶
用户专栏

日常学习总结与分享,包括:前端、后台与运维,讲解的知识点包括:javascript、vuejs、reactjs、springb...

79 人关注
44 篇文章
专栏主页