Vue 如何代码复用

我下面这段代码,在好几个页面都用到,而且一模一样的,请问一下怎么复用呢。我看vue官方文档,可以使用mixin来复用逻辑,但是好像没法满足我的要求

    <el-table
      ref="multipleTable"
      v-loading="listLoading"
      v-el-height-adaptive-table="{ bottomOffset: 50 }"
      :data="instanceList.results"
      style="width: 100%; margin-top: 10px; font-size: 15px"
      highlight-current-row
      row-key="id"
      height="100"
      stripe
      border
      default-expand-all
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      @selection-change="handleSelectionChange"
    >

封装组件不可以吗?个人觉得封装组件比mixin合适

可以写成组件,然后复用组件。
js部分可以写成 hook。
也可以用class。

1 Like
用el-table原本是这样 写的嘛
<el-table
      ref="multipleTable"
      v-loading="listLoading"
      v-el-height-adaptive-table="{ bottomOffset: 50 }"
      :data="instanceList.results"
      style="width: 100%; margin-top: 10px; font-size: 15px"
      highlight-current-row
      row-key="id"
      height="100"
      stripe
      border
      default-expand-all
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      @selection-change="handleSelectionChange"
    >
我想封装一个组件MyTable,他能完全继承el-table,但是某些属性有了我设定的默认值,使得下面的代码跟上面的代码效果能一模一样,这样MyTable要如何实现呢,相当于我配置了一套el-table的样式模板一样
<my-table
      ref="multipleTable"
      v-loading="listLoading"
      :data="instanceList.results"
      @selection-change="handleSelectionChange"
    >
用el-table原本是这样 写的嘛
<el-table
      ref="multipleTable"
      v-loading="listLoading"
      v-el-height-adaptive-table="{ bottomOffset: 50 }"
      :data="instanceList.results"
      style="width: 100%; margin-top: 10px; font-size: 15px"
      highlight-current-row
      row-key="id"
      height="100"
      stripe
      border
      default-expand-all
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      @selection-change="handleSelectionChange"
    >
我想封装一个组件MyTable,他能完全继承el-table,但是某些属性有了我设定的默认值,使得下面的代码跟上面的代码效果能一模一样,这样MyTable要如何实现呢,相当于我配置了一套el-table的样式模板
<my-table
      ref="multipleTable"
      v-loading="listLoading"
      :data="instanceList.results"
      @selection-change="handleSelectionChange"
    >

把你的el-table直接放到my-table组件里就行了呀

<my-table
      ref="multipleTable"
      v-loading="listLoading"
      :data="instanceList.results"
      @selection-change="handleSelectionChange"
    >

这里的属性在props里面接受,再给到el-table;
事件就在el-table的事件里用$emit将事件名和参数传递出来。this.$emit(‘selection-change’, 参数)
v-loading应该是el-table里的自定义指令,你可以用一个变量替代。

el-table这个组件我都没法import出来好像,下面这两种方式都不行,好像设计的就是不让人改写一样

import ElTable from 'element-ui/packages/table/src/table.vue'
import { ElTable } from 'element-ui/types/table'

我是想用下面的这种方式来给ElTable设置 默认值,这样能完全不影响原本的逻辑,但是ElTable这个组件好像导出不了

import { ElTable } from 'element-ui/types/table'

export default {
  name: 'MyTable',
  mixins: [ElTable],
  props: {
    cellStyle: {
      type: [Object, Function],
      default: {
        padding: '1px'
      }
    },
    rowStyle: {
      type: [Object, Function],
      default: { height: 0 }
    }

  }
}

你跟个element官方的[快速上手]部分走,应该不会出问题,按需引入有前提的

谢谢,我在官方的按需引入里找到了导入方式
import { Table } from 'element-ui'

export default {
  name: 'MyTable',
  mixins: [Table],
  props: {
    cellStyle: {
      type: [Object, Function],
      default: {
        padding: '1px'
      }
    },
    rowStyle: {
      type: [Object, Function],
      default: { height: 0 }
    }
  }
}

<template>
  <el-table
    ref="gridDom"
    size="mini"
    style="width: 100%"
    :data="dataList"
    :height="height"
    :stripe="stripe"
    :border="border"
    :fit="fit"
    :highlight-current-row="highlightCurrentRow"
    :current-row-key="idName"
    :row-key="idName"
    @selection-change="selectionChange"
    @current-change="currentChange"
  >
    <!--显示选择框-->
    <el-table-column
      type="selection"
      width="55">
    </el-table-column>
    <!--显示字段列表-->
    <el-table-column
      v-for="(id, index) in colOrder"
      :key="'grid_list_' + index + '_' + id"
      :colId="id"
      :column-key="'col_' + id"
      :fixed="id < fixedIndex"
      v-bind="itemMeta[id]"
      :prop="itemMeta[id].colName"
      :min-width="50"
    >
    </el-table-column>
    <!--右面的操作列-->
  </el-table>
</template>

<script>
  import { onMounted, ref } from 'vue'
  import { ElTable, ElTableColumn } from 'element-plus'
  // 表单控件的属性 
  import { gridProps } from '../mapController.js'

/**
 * 列表的单选和多选的事件
 */
const choiceManage = (props, gridDom) => {
  // 是否单选触发
  let isCurrenting = false
  // 是否多选触发
  let isMoring = false

  // 单选
  const currentChange = (row) => {
    if (isMoring) return // 多选代码触发
    if (row === null) return // 清空

    if (gridDom.value) {
      isCurrenting = true
      gridDom.value.clearSelection() // 清空多选
      gridDom.value.toggleRowSelection(row) // 设置复选框
      gridDom.value.setCurrentRow(row) // 设置单选
      // 记录
      props.selection.dataId = row[props.idName]
      props.selection.dataIds[0] = row[props.idName]
      props.selection.row = row
      props.selection.rows = row

      isCurrenting = false
    }
  }

  // 多选
  const selectionChange = (rows) => {
    if (isCurrenting) return
    // 记录
    if (typeof props.selection.dataIds === 'undefined') {
      props.selection.dataIds = []
    }
    props.selection.dataIds.length = 0 // 清空
    // 设置多选
    rows.forEach((item) => {
      if (typeof item !== 'undefined' && item !== null) {
        props.selection.dataIds.push(item[props.idName])
      }
    })
    props.selection.rows = rows
    // 设置单选
    switch (rows.length) {
      case 0:
        // 清掉单选
        gridDom.value.setCurrentRow()
        props.selection.dataId = ''
        props.selection.row = {}
        break
      case 1:
        isMoring = true
        // 设置新单选
        gridDom.value.setCurrentRow(rows[0])
        isMoring = false
        props.selection.row = rows[0]
        props.selection.dataId = rows[0][props.idName]
        break
      default:
        // 清掉单选
        gridDom.value.setCurrentRow()
        props.selection.row = rows[rows.length - 1]
        props.selection.dataId = props.selection.row[props.idName]
    }
  }

  return {
    currentChange, // 单选
    selectionChange // 多选
  }
}

/**
 * * height: 250, // 高度
 * * colOrder: [101], // 显示顺序
 * * fixedIndex: 0 // 锁定的列数
 * * itemMeta: {
 * * --101: {
 * * ----id: 101,
 * * ----label: '编号11',
 * * ----prop: 'code',
 * * ----width: 120
 * * --}
 */
export default {
  name: 'nf-el-grid-list',
  inheritAttrs: false,
  components: {
    ElTable, ElTableColumn
  },
  props: {
    ...gridProps
  },
  setup (props, ctx) {
    // console.log('\ngrid---props', props) //

    // 获取 table 的 dom 和其他,
    const gridDom = ref(null)
    onMounted(() => {
    })

    // 列表选项的事件
    const {
      currentChange, // 单选
      selectionChange // 多选
    } = choiceManage(props, gridDom)

    // 格式化
    const myformatter = (row, column, cellValue, index) => {
      // console.log('\nrow:', row, 'col:', column) //
      // console.log('cellValue:', cellValue, 'index:', index) //
      if (Array.isArray(cellValue)) {
        return cellValue.join(',')
      }
      if (typeof cellValue === 'boolean') {
        return cellValue.toString()
      }
      return row[column.property] // realWidth
    }

    return {
      selectionChange, // 多选
      currentChange, // 单选
      gridDom, // table 的 dom
      myformatter // 格式化
    }
  }
}
</script>

可以封装成组件呀,比如这样,这是我封装的。

组件里面使用

  <nf-grid
    v-grid-drag="gridMeta"
    :dataList="dataList"
    v-bind="gridMeta"
    :selection="selection"
  >
  </nf-grid>

具体代码

谢谢,我看你的代码学习一下

写成module,用components当子组件来调用?