editor.vue 4.17 KB
<script>
import { get, set, cloneDeep } from '../utils';
import { renderContext } from '../utils/vnode';

// 标题渲染
function headerRender(h, context, item) {
  const headerSlot = context.scopedSlots[`header-${item.prop}`];
  return function(scope) {
    // 自定义具名插槽
    if (headerSlot) {
      return headerSlot(scope);
    }
    // 自定义渲染函数
    if (item.header) {
      return item.header(item, h, scope);
    }
    // 默认取值
    return item.label;
  };
}

// 单元格渲染
function cellRender(h, context, item) {
  const cellSlot = context.scopedSlots[`cell-${item.prop}`];
  return function(scope) {
    const value = get(scope.row, item.prop);
    // 自定义具名插槽
    if (cellSlot) {
      return cellSlot({ item, value, index: scope.$index, ...scope });
    }
    // 自定义渲染函数
    if (item.render) {
      return item.render(value, scope.row, h, scope.$index);
    }
    // 默认取值
    return get(scope.row, item.prop);
  };
}

// 编辑器渲染
function editorRender(h, context, item) {
  const editorSlot = context.scopedSlots[`editor-${item.prop}`];
  const contentProps = context.props || {};
  return function(scope) {
    const value = get(scope.row, item.prop);
    // 自定义具名插槽
    if (editorSlot) {
      return editorSlot({ item, value, index: scope.$index, ...scope });
    }
    // 默认
    const vnode = h(item.is, {
      attrs: item.attrs,
      props: { ...(item.props || {}), value },
      on: {
        input(val) {
          if (get(contentProps, 'editor.deep') === true) {
            if (item.prop.indexOf('.') > -1 || item.prop.indexOf('[') > -1) {
              let separator = '';
              if (item.prop.indexOf('.') > -1) {
                separator = '.';
              } else if (item.prop.indexOf('[') > -1) {
                separator = '[';
              }
              const path = item.prop.split(separator);
              const bindProp = path[0];
              const propValue = cloneDeep(scope.row);
              set(propValue, item.prop, val);
              vnode.componentInstance.$set(scope.row, bindProp, propValue[bindProp]);
            } else {
              // set(scope.row, item.prop, val);
              scope.row[item.prop] = val;
            }
          } else {
            scope.row[item.prop] = val;
            // set(contentProps.data, `[${[scope.$index]}]${item.prop}`, val);
          }
          if (item.on && item.on.input) {
            item.on.input(val);
          }
        },
      },
    });
    return vnode;
  };
}

// 跟进columns生成列
function createElTableColumns(h, context, columns) {
  const props = context.props || {};
  const editorConfig = props.editor || {};
  return columns.map((item, index) => {
    const { attrs, on, ...props } = item;
    const editorMatch = editorConfig.inputs.find(i => i.prop === item.prop);
    // 处理插槽
    const scopedSlots = {
      header: headerRender(h, context, item),
      default: editorMatch ? editorRender(h, context, editorMatch) : cellRender(h, context, item),
    };
    return h('el-table-column', { key: index, attrs, props, on, scopedSlots });
  });
}

export default {
  name: 'TableEditor',
  functional: true,
  render(h, context) {
    console.log(context);
    const props = context.props || {};
    let scopedSlots = context.scopedSlots || {};
    // 如有默认插槽则相当于直接写el-table
    if (scopedSlots.default) {
      return h('el-table', context);
    }
    const columns = props.columns || [];
    // 通过columns快速生成el-table-column
    const elTableColumns = createElTableColumns(h, context, columns);
    // 前置插槽
    const prependSlot = scopedSlots.prepend ? scopedSlots.prepend() : '';
    // 左侧插槽
    const leftSlot = scopedSlots.left ? scopedSlots.left() : '';
    // 右侧插槽
    const rightSlot = scopedSlots.right ? scopedSlots.right() : '';
    // 后置插槽
    const appendSlot = scopedSlots.append ? scopedSlots.append() : '';
    // 渲染组件时移除当前组件特有的props,避免透传不必要的参数
    delete context.columns;
    return h('el-table', renderContext(context), [prependSlot, leftSlot, ...elTableColumns, rightSlot, appendSlot]);
  },
};
</script>