element-ui 表格hook 及相关组件

2020-04-16 19:13:37 浏览数 (1)

使用例子
代码语言:javascript复制
<template>
  <div>
    <Searchbar :searchBarConf='searchBarConf'/>
    <Table :tableConf='tableConf'>
         <div slot="btns" slot-scope="slotProps" v-bind="slotProps.itemProps">
          <el-button type='text' @click="onEditor(slotProps)" > 编辑 </el-button>
        </div>
    </Table>
    <Pagination />
  </div>
</template>

<script>
import { reactive, computed, toRefs, provide } from '@vue/composition-api'
import {
  tableConf,
  searchBarConf,
  confHook
} from './model'
import { delPop, reqSuccessTip, reqFailTip, asyncVessel } from '@/utils/tool'
import * as api from './api'
import {
  tableHook,
  injectMark,
  Pagination,
  Searchbar,
  Table
} from '@/components/manage-table/index.js'

    
 const tableConf = {
    props: {

    },
    columns: [
        { label: '用户id', prop: 'id', align: 'center', sortable: true },
        { label: '用户昵称', prop: 'realName', align: 'center' },
        { label: '参团数', prop: 'joinGroupNum', align: 'center', sortable: true },
        { label: '订货数', prop: 'buyProductNum', align: 'center', sortable: true },
        { label: '操作', prop: 'btns', align: 'center', width: 80, slot: 'btns' }
    ]
  }
 
const searchBarConf = [

    {
      col: 6,
      cmp: 'el-input',
      cmpProps:{
          size:'small',
          placeholder: '请输入完整的手机号码'
      },
      formItemProp: {
        label: '手机号码',
        prop: 'phone'
      },
    },

  ]
 
export default {
  components:{
    Pagination,
    Searchbar,
    Table
  },

  setup(){
      
    // 创建state
    const tableState = tableHook( api.tableList )
    
    // 注入组件依赖
    provide(injectMark, tableState)
    
    // 表格更新
    const updateTable = tableState.onSearchNoQuery
    const onEditor = (row) => {
        console.log(row);
        updateTable()
    }
    
    return {

      tableConf,
      searchBarConf,
     
    }
  }

 
}
</script>
tableHook实现
代码语言:javascript复制
/**
  * author: huhaiguo
  * date: 2019-51-26 10:12
  * summary: 表格功能逻辑
  */
import { reactive, computed, toRefs, ref, watch } from '@vue/composition-api'
import cloneDeep from 'lodash/cloneDeep'


import { 
  asyncVessel
} from '@/utils/tool'

export const injectMark = 'MANAGE_TABLE' 

/**
 * 
 * @param { Function } update 表格数据请求接口 
 * @param { Object } initQuery 搜素条初始参数
 * @param { Object } options 设置项 
 */
export default function tableHook( update, initQuery={}, options={}){

  // 默认配置
  const defOptions = {
    pageSize: 10,
    totalCount: 0,
    currentPage: 1,
    tableList: [],
  }

  const state = reactive(Object.assign({}, defOptions, options))
  
  // 表格对象,用于获取对象上的方法
  const tableEle = ref(null)

  // 设置搜索条参数
  const setQuery = (initQuery) => reactive({
    pageSize: computed(() => state.pageSize),
    pageNo: computed(() => state.currentPage),
    ...cloneDeep(initQuery),
  })
  
  
  // 重置搜索条参数
  let query = ref(setQuery(initQuery))
   

  // 向外开放查询参数
  watch(() => query.value, () => state.localCopyQuery&&state.localCopyQuery(query.value))
  
  // 搜索条重置
  const resetQuery = () => query.value = setQuery(initQuery)

  // 请求表格数据
  async function onSearch(params=query.value){
    
    const [ res, err ] = await asyncVessel(update(params)) 

    if(err){
      console.error('TABLE_ERROR: ', err)
      return
    }
    
    const { result, totalCount } = res
    state.tableList = result
    state.totalCount = totalCount
    
  }

  // 分页选择
  const onCurrentChange = num => {
    state.currentPage = num
    onSearch()
  }
  
  // 重置表格数据
  const restTable = () => {
    resetQuery()
    onCurrentChange(1)
  }


  // 初始请求
  restTable()

  return {
    query,
    tableEle,
    restTable,
    resetQuery,
    onSearch,
    onSearchNoQuery: () => onSearch(),
    onCurrentChange,
    ...toRefs(state)
    
  }
  
}
搜索条
代码语言:javascript复制
<template>
<div style="margin-bottom: 40px">
    <el-card shadow="hover" body-style="padding: 0">
        <DefTableTopbar @search='onSearchHandler' @reset='onResetHandler' />
        <div style="padding: 20px; padding-bottom: 2px">
            <Form :itemsConf='searchBarConf' :model='query' />
        </div>
    </el-card>
</div>
</template>

<script>
import DefTableTopbar from './searchbar-btns'
import Form from '../form-container/index.vue'
import { toRefs, inject } from '@vue/composition-api'
import { injectMark } from './table-hook'

export default {

    components: {
        DefTableTopbar,
        Form
    },
    
    props: {

        searchBarConf:{
            default(){return {}}
        },
        
    },
    
    setup(){
        const allState = inject(injectMark)
    
        const onSearchHandler = () => {
            allState.currentPage = 1
            allState.onSearch()
        }

        const onResetHandler = () =>{
            allState.restTable()
        }
        
        return {
            onSearchHandler,
            onResetHandler,
            ...toRefs(allState)
        }
    }

}
</script>
分页
代码语言:javascript复制
<template>
  <div style='margin-top: 20px'>
   <el-card bodyStyle="padding: 10px 20px" shadow='hover'>
        <Pagination
        @current-change='onCurrentChange'
        :total='totalCount' 
        :pageSize='pageSize' 
        :currentPage='currentPage' >
        </Pagination>
    </el-card>
  </div>
</template>

<script>
import { toRefs, inject } from '@vue/composition-api'
import { injectMark } from './table-hook'

const Pagination = ctx => {

  const _defaultConf = {

    ['layout']: ['total', 'prev', 'pager', 'next',  'jumper'].join(','),
    ['current-page']: '',
    ['page-sizes']: [10],
    ['page-size']: 10,
    ['total']: 0,
    ['currentPage']: 1,
    
  }

  if(ctx.props){
    ctx.props = Object.assign({}, _defaultConf, ctx.props)  
  }

  return (
    <el-pagination style={{padding:0, marginTop:0}} { ...ctx } on={ ctx.listeners } ></el-pagination>
  )
   
} 

export default {

    components: {
      Pagination
    },

    setup(){
        const allState = inject(injectMark)
        return toRefs(allState)
    }

}

</script>
表格
代码语言:javascript复制
import CadTopBar from '@/components/card-top-bar'
import { inject } from '@vue/composition-api'
import { injectMark } from './table-hook'

const Table = {

    props:{
        tableConf:{
            default(){return {}}
        },
       
    },

    setup(props){
        const allState = inject(injectMark)
        
        return {
            tableList: allState.tableList 
        }
    },

    render(){

        const { tableList, tableConf } = this
        
        // 表格列
        const tableColumns = tableConf.columns.map((item, index) =>{

            // child 插槽
            if(item.child){

                const Cmp = item.child
                const scopedSlots = {
                    default: slotprops => [
                        <Cmp slotprops={slotprops} on={ item.on } attrs={ item } ></Cmp>
                    ]
                }
                
                return <el-table-column  key={index} props={item} scopedSlots={scopedSlots} ></el-table-column>
            }

            // slot 插槽
            if(item.slot){

                const Cmp = this.$scopedSlots[ typeof item.slot === 'string' ? item.slot : item.prop]
                
                if(!Cmp) return 
                
                const scopedSlots ={
                    default: slotprops => [
                        Cmp(slotprops),
                    ]
                }

                return <el-table-column key={index} props={item} scopedSlots={scopedSlots} ></el-table-column>
                
            }
            
            // 默认column
            return <el-table-column key={index} props={item} ></el-table-column>
            
        })

        // topbar 插槽
        let Topbar = this.$slots['table-top-bar']

        return (

            <el-card body-style='padding: 0' shadow='hover' >

                <CadTopBar title='数据列表'>
                    { Topbar }
                </CadTopBar>
            
                <el-table ref='tableEle' data={ tableList } listeners={ tableConf.on } attrs={ tableConf.props }  >
                    { tableColumns }
                </el-table>
    
            </el-card>
            
        )
        
    }
    
}


export default Table
  • left-vue-hooks vue的hooks工具包

0 人点赞