Vue 中props传入模字符串渲染

在vue中要想实现一个props,然后再渲染这个props不像react当中那么简单,react中这种jsx的语法,传递渲染函数和普通参数一样没什么区别,例如antd中的a-table -> column中的render:

const columns = [
  {
    title: 'Name',
    dataIndex: 'name',
    key: 'name',
    render: (text) => <a>{text}</a>,
  },
  {
    title: 'Action',
    key: 'action',
    render: (_, record) => (
      <Space size="middle">
        <a onClick={editHandler}>编辑</a>
        <a>删除</a>
      </Space>
    ),
  },
];

在react中实现这样的一个功能还是很容易的,但是在Vue中通常可能需要给column设置一个slot name,然后template中使用作用域插槽。

实现类似功能:
父组件:

<template>
	<my-table :columns="columns" :dataSource="dataSource"></my-table>
</template>
<script>
export default{
	data() {
        return {
            columns: [{
                label: '姓名',
                prop: 'name',
                width: 160
              }, {
                label: '年龄',
                prop: 'age',
                formatter: (value) => value * 2
              }, {
                label: '操作',
                prop: 'action',
                context: this,
                bindMethodKeys: ['remove'],
                customerRender(row){
                  return `<div><el-link type="primary" @click="remove(row, index)">删除</el-link></div>`
                }
              }],
        }
    },
    methods: {
        remove(row, index) {
          	console.log(row,index,column)
      		this.$message.success(`删除第${index+1}行成功!`)
        }
    }
}
</script>

子组件实现我这边用的是自己实现render函数,用模板应该也可以。

注意上面需要传入context上下文和bindMethodKeys这两个参数,否则拿不到父组件的上下文和绑定的函数。

<script>
export default{
    props: {
        columns: Array,
        dataSource: Array,
    }
    render(h){
        // ...
        return h(
            'el-table',
            {
                 props: {
                    border: true,
                    stripe: true,
                    data: this.dataSource,
                },
                style: { width: '100%' } 
            },
            [...createColumns(this.columns)]
        )
    }
}
</script>

实现一下createColumns的逻辑:


const columnRender = (column, props) => {
            if(!column.customerRender && !column.slot){
                let text = column.formatter ? column.formatter(props.row[column.prop], props.row, props.$index) : props.row[column.prop]
                return h('span', text)
            }
    		// 这边是处理作用域插槽的逻辑
            if(column.slot && this.$scopedSlots[column.slot]){
                return this.$scopedSlots[column.slot]({
                    $index: props.$index,
                    row: props.row,
                    column: props.column
                })
            }
			// 处理渲染字符串逻辑
            if(column.customerRender){
                const context = column.context || this
                const outterHtml = column.customerRender(props.row, column)
                const res = Vue.compile(outterHtml)
                const methods = column.bindMethodKeys.reduce((result, key) => {
                    result[key] = context[key]
                    return result
                }, {})
                const com = Vue.extend({
                    name: 'customerRenderCell',
                    render: res.render, // res.render.bind(context),
                    staticRenderFns: res.staticRenderFns,
                    methods: methods,
                    data() {
                        return { row: props.row, column: props.column, index: props.$index }
                    }
                })
                return h('span', {}, [h(com)])
                // 这样也可以实现
                /* const com = Vue.extend({
                    template: outterHtml, // 模板字符串
                    methods: methods,
                    data() {
                        return { row: props.row, column: props.column, index: props.$index }
                    }
                })
                return h('div', {  style: { textAlign: 'center' } }, [h(com)]) */
            }
        }

为了调用父组件的函数, 实现逻辑我一开始是想用res.render.bind(context)绑定到父组件传的context上下文,这样就可以调用父组件的方法了, 但是这样的话那些当前行和下标之类的就没办法传了, 所以改为了从context中直接把对应的函数拿过来再传给这个新创建的子组件,就可以实现调用父组件的函数了。

还有这个新创建的子组件,data中绑定了row和column和index下标,所以父组件那边函数的参数也可以接受的到了。

还有要注意一点的是,Vue分为runtime-only版本和runtime-with-compile版本,因为这个需要实时编译,所以需要使用带编译版本的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值