美文网首页
render 函数封装element-ui表格 form表单

render 函数封装element-ui表格 form表单

作者: 如果俞天阳会飞 | 来源:发表于2022-04-02 10:43 被阅读0次

    用法

    <template>
      <div>
        <base-search :params="listQuery" :items="queryItems" @search="handleFilter">
          <template slot="mobile">
            <el-input v-model="listQuery.mobile" placeholder="请输入手机号"/>
          </template>
        </base-search>
        <base-table
          :loading="listLoading"
          :data="list"
          :columns="columns"
          :stripe="true"
          border
          @row-click="rowClick">
          <template slot="importance" slot-scope="{row}">
            <svg-icon v-for="n in +row.importance" :key="n" icon-class="star" class="meta-item__icon"/>
          </template>
          <template slot="pageviews" slot-scope="{row}">
            <span v-if="row.pageviews" class="link-type" @click="handleFetchPv(row.pageviews)">{{ row.pageviews }}</span>
            <span v-else>0</span>
          </template>
          <template slot="status" slot-scope="{row}">
            <el-tag :type="row.status | statusFilter">{{ row.status }}</el-tag>
          </template>
          <template slot="operation" slot-scope="scope">
            <el-button
              type="primary"
              size="mini"
              @click="handleUpdate(scope.row)">{{ $t('table.edit') }}</el-button>
            <el-button
              v-if="scope.row.status!='published'"
              size="mini"
              type="success"
              @click="handleModifyStatus(scope.row,'published')">{{ $t('table.publish') }}
            </el-button>
            <el-button
              v-if="scope.row.status!='draft'"
              size="mini"
              @click="handleModifyStatus(scope.row,'draft')">{{ $t('table.draft') }}
            </el-button>
            <el-button
              v-if="scope.row.status!='deleted'"
              size="mini"
              type="danger"
              @click="handleModifyStatus(scope.row,'deleted')">{{ $t('table.delete') }}
            </el-button>
          </template>
        </base-table>
        <pagination
          v-show="total>0"
          :total="total"
          :page.sync="listQuery.page"
          :limit.sync="listQuery.limit"
          @pagination="getList" />
        <base-dialog
          :visible.sync="dialogPvVisible"
          :loading="loading"
          title="Reading statistics"
          @cancel="handleCancel"
          @ok="handleOk">
          <base-form ref="baseForm" :params="formParams" :items="formItems"/>
        </base-dialog>
      </div>
    </template>
    
    <script>
    import BaseTable from './components/baseTable'
    
    import { fetchList, fetchPv } from '@/api/article'
    import { parseTime } from '@/utils'
    import BaseSearch from './components/baseSearch'
    import Pagination from '../../components/Pagination'
    import BaseDialog from './components/baseDialog'
    import BaseForm from './components/baseForm'
    const columns = [
      { prop: 'id', label: 'id' },
      { prop: 'date', label: 'date', render: (h, { row }) => {
        const value = parseTime(row.timestamp, '{y}-{m}-{d} {h}:{i}')
        return <span>{ value }</span>
      } },
      {
        prop: 'title', label: 'title',
        render: (h, { index, row }) => {
          return <span>{row.title}</span>
        }
      },
      {
        prop: 'author', label: 'author'
      },
      {
        prop: 'importance', label: 'importance'
      },
      {
        prop: 'pageviews', label: 'pageviews'
      },
      {
        prop: 'status', label: 'status'
      },
      {
        prop: 'operation', width: '220', label: '操作'
      }
    ]
    const queryItems = [
      { label: 'ID', prop: 'id', type: 'input',
        config: {
          props: {},
          attrs: { placeholder: '请输入ID' },
          on: {}
        }
      },
      { label: '作者', prop: 'author', type: 'input' },
      { label: '手机号', prop: 'mobile', type: 'input' },
      {
        label: '状态', prop: 'status', type: 'select',
        config: {
          props: {},
          attrs: { placeholder: '请选择文章标签' },
          on: {}
        },
        option: [
          { label: '成功', value: 1 },
          { label: '失败', value: 0 }
        ]
      },
      {
        label: '日期范围', prop: 'datetimerange', type: 'datePicker',
        config: {
          props: {
            type: 'datetimerange',
            format: 'yyyy-MM-dd',
            valueFormat: 'yyyy-MM-dd'
          },
          attrs: {},
          on: {}
        }
      },
      {
        label: '日期', prop: 'timer', type: 'datePicker',
        config: {
          props: {
            // type: 'datetime',
            // format: 'yyyy-MM-dd HH:mm:ss',
            // valueFormat: 'yyyy-MM-dd HH:mm:ss'
          },
          attrs: {},
          on: {}
        }
      }
    ]
    const formItems = [
      { label: 'ID', prop: 'id', type: 'input',
        rules: [{ required: true, message: '请输入ID' }],
        input: {
          props: {},
          attrs: { placeholder: '请输入ID' },
          on: {}
        }
      },
      { label: '作者', prop: 'author', type: 'input' },
      { label: '手机号', prop: 'mobile', type: 'input' },
      {
        label: '状态', prop: 'status', type: 'select',
        config: {
          props: {},
          attrs: { placeholder: '请选择文章标签' },
          on: {}
        },
        option: [
          { label: '成功', value: 1 },
          { label: '失败', value: 0 }
        ]
      },
      {
        label: '日期范围', prop: 'datetimerange', type: 'datePicker',
        config: {
          props: {
            type: 'datetimerange',
            format: 'yyyy-MM-dd',
            valueFormat: 'yyyy-MM-dd'
          },
          attrs: {},
          on: {}
        }
      },
      {
        label: '日期', prop: 'timer', type: 'datePicker',
        config: {
          props: {
            // type: 'datetime',
            // format: 'yyyy-MM-dd HH:mm:ss',
            // valueFormat: 'yyyy-MM-dd HH:mm:ss'
          },
          attrs: {},
          on: {}
        }
      },
      {
        label: '资源', prop: 'resource', type: 'radio',
        config: {},
        option: [{ label: '1', text: '线上品牌商赞助' }, { label: '2', text: '线下场地免费' }]
      },
      {
        label: '资源2', prop: 'resource2', type: 'checkbox',
        config: {},
        option: [{ label: '1', text: '线上品牌商赞助' }, { label: '2', text: '线下场地免费' }]
      }
    ]
    export default {
      name: 'TestTable',
      components: { BaseForm, BaseDialog, Pagination, BaseSearch, BaseTable },
      filters: {
        statusFilter(status) {
          const statusMap = {
            published: 'success',
            draft: 'info',
            deleted: 'danger'
          }
          return statusMap[status]
        }
      },
      data() {
        return {
          listQuery: {
            page: 1,
            limit: 20,
            author: '111',
            status: null,
            timer: null,
            datetimerange: [],
            mobile: '',
            importance: undefined,
            title: undefined,
            type: undefined,
            id: ''
          },
          formParams: {
            page: 1,
            limit: 20,
            author: '111',
            status: null,
            timer: null,
            datetimerange: [],
            mobile: '',
            importance: undefined,
            title: undefined,
            type: undefined,
            resource: undefined,
            resource2: [],
            id: ''
          },
          total: 0,
          list: null,
          listLoading: false,
          columns,
          queryItems,
          formItems,
          pvData: [],
          dialogPvVisible: false,
          loading: false
        }
      },
      created() {
        this.getList()
      },
      methods: {
        rowClick() {
          console.log('rowClick')
        },
        handleFilter() {
          this.listQuery.page = 1
          this.getList()
        },
        getList() {
          this.listLoading = true
          fetchList(this.listQuery).then(response => {
            this.list = response.data.items
            this.total = response.data.total
            setTimeout(() => {
              this.listLoading = false
            }, 1.5 * 1000)
          })
        },
        handleFetchPv(pv) {
          fetchPv(pv).then(response => {
            this.pvData = response.data.pvData
            this.dialogPvVisible = true
          })
        },
        handleModifyStatus(row, status) {
          this.$message({
            message: '操作成功',
            type: 'success'
          })
          row.status = status
        },
        handleOk() {
          this.$refs.baseForm.validate((valid) => {
            if (valid) {
              this.loading = true
              setTimeout(() => {
                this.loading = false
              }, 1000)
            } else {
              console.log('error submit!!')
              return false
            }
          })
        },
        handleCancel() {
          this.dialogPvVisible = false
        }
      }
    }
    </script>
    
    <style scoped>
    
    </style>
    
    

    表格

    // baseTable.vue
    
    
    <script>
    export default {
      name: 'BaseTable',
      props: {
        data: {
          type: Array,
          default() {
            return []
          }
        },
        columns: {
          type: Array,
          default() {
            return []
          }
        }
      },
      render(h) {
        const { data, columns, $attrs, $listeners, $scopedSlots } = this
        const { loading } = $attrs
        const tableAttrs = {
          props: { ...$attrs },
          on: { ...$listeners }
        }
        const table = <el-table
          v-loading={loading}
          {...tableAttrs}
          data={data}>
          {
            columns.map((col) => {
              const colAttrs = {
                props: { ...col },
                scopedSlots: {
                  default: scope => {
                    const hasRender = col.hasOwnProperty('render')
                    if (hasRender) {
                      return col.render(h, scope)
                    }
                    const customRender = $scopedSlots[col.prop]
                    return customRender ? customRender(scope) : scope.row[col.prop]
                  }
                }
              }
              return <el-table-column {...colAttrs}/>
            })
          }
        </el-table>
        return <div>
          {table}
        </div>
      }
    }
    </script>
    
    

    form 表单

    // createForm.js
    export default {
      methods: {
        renderType(row) {
          const { params } = this
          const { config = {}} = row
          const defaultAttrs = {
            props: {
              value: params[row.prop],
              ...config.props
            },
            attrs: {
              ...config.attrs
            },
            on: {
              input(value) {
                params[row.prop] = value
              },
              ...config.on
            }
          }
          const types = {
            input: () => {
              const { props, attrs } = defaultAttrs
              const { clearable } = props
              const { placeholder } = attrs
              props.clearable = clearable === undefined ? true : clearable
              attrs.placeholder = placeholder === undefined ? '请输入' : placeholder
              return <el-input {...defaultAttrs}/>
            },
            select: () => {
              const { attrs, on } = defaultAttrs
              const { placeholder } = attrs
              attrs.placeholder = placeholder === undefined ? '请选择' : placeholder
              if (!on.change) {
                on.change = function(value) {
                  params[row.prop] = value
                }
              }
              return <el-select {...defaultAttrs}>
                {row.option && row.option.map((item, index) => {
                  const obj = {
                    props: { ...item },
                    on: { ...item }
                  }
                  return <el-option key={index} {...obj}></el-option>
                })}
              </el-select>
            },
            datePicker: () => {
              /*
              * type 类型 year/month/date/week/ datetime/datetimerange/daterange
              * 默认 date
              * 日期格式 yyyy-MM-dd HH:mm:ss
              * */
              const { attrs } = defaultAttrs
              const { startPlaceholder, endPlaceholder } = attrs
              attrs.startPlaceholder = startPlaceholder === undefined ? '开始日期' : startPlaceholder
              attrs.endPlaceholder = endPlaceholder === undefined ? '结束日期' : endPlaceholder
              return <el-date-picker {...defaultAttrs}/>
            },
            radio: () => {
              return <el-radio-group {...defaultAttrs}>
                {row.option && row.option.map((item, index) => {
                  return <el-radio key={index} {...{ props: { ...item }, attrs: { ...item }, on: { ...item }}}>
                    {item.text}
                  </el-radio>
                })}
              </el-radio-group>
            },
            checkbox: () => {
              return <el-checkbox-group {...defaultAttrs}>
                {row.option && row.option.map((item, index) => {
                  return <el-checkbox key={item.label} {...{ props: { ...item }, attrs: { ...item }, on: { ...item }}}>
                    {item.text}
                  </el-checkbox >
                })}
              </el-checkbox-group>
            }
          }
          return types[row.type]()
        },
        form(h) {
          const { items, params,
            $listeners, $attrs, $slots } = this
          const attrs = {
            props: {
              model: params,
              ...$attrs
            },
            ref: 'form',
            on: { ...$listeners }
          }
          return <el-form {...attrs}>
            {
              items.map((item, index) => {
                const obj = {
                  props: {
                    ...item
                  },
                  scopedSlots: {
                    default: scope => {
                      const hasRender = item.hasOwnProperty('render')
                      if (hasRender) {
                        return item.render(h, scope)
                      }
                      const customRender = $slots[item.prop]
                      return customRender || this.renderType(item)
                    }
                  }
                }
                return <el-form-item key={index} {...obj}/>
              })
            }
          </el-form>
        }
      }
    }
    
    
    

    baseForm.vue

    
    <script>
    import createForm from './createForm'
    
    export default {
      name: 'BaseForm',
      mixins: [createForm],
      props: {
        params: {
          type: Object,
          default() {
            return {}
          }
        },
        items: {
          type: Array,
          default() {
            return []
          }
        }
      },
      methods: {
        validate(callback) {
          this.$refs.form.validate(callback)
        }
      },
      render(h) {
        const { form } = this
        const { labelWidth, labelPosition } = this.$attrs
        this.$attrs.labelWidth = labelWidth || '100px'
        this.$attrs.labelPosition = labelPosition || 'left'
        return <div class={'form-container'}>
          {form(h)}
        </div>
      }
    }
    </script>
    <style scoped>
    .form-container{
      max-width: 460px;
    }
    </style>
    
    

    baseSearch.vue

    
    <script>
    import createForm from './createForm'
    export default {
      name: 'BaseSearch',
      mixins: [createForm],
      props: {
        params: {
          type: Object,
          default() {
            return {}
          }
        },
        items: {
          type: Array,
          default() {
            return []
          }
        }
      },
      data() {
        return {
          defaultParams: {}
        }
      },
      mounted() {
        this.defaultParams = JSON.parse(JSON.stringify(this.params))
      },
      methods: {
        handleReset() {
          for (const key in this.defaultParams) {
            this.params[key] = this.defaultParams[key]
          }
          this.$listeners.search()
        }
      },
      render(h) {
        const { form, $listeners } = this
        this.$attrs.inline = true
        return <el-card class={['filter-container']}>
          <el-row type='flex' justify='space-between' { ...{ style: { marginBottom: '10px' }} }>
            <el-col>
              <i class={['el-icon-search']}/>
              <span>筛选搜索</span>
            </el-col>
            <el-col {...{ style: { textAlign: 'right' }}}>
              <el-button {...{
                props: { type: 'primary', size: 'small' },
                on: { click: $listeners.search }
              }}>
              查询搜索
              </el-button>
              <el-button {...{
                props: { size: 'small' },
                on: { click: this.handleReset }
              }}>
                重置
              </el-button>
            </el-col>
          </el-row>
          {form(h)}
        </el-card>
      }
    }
    </script>
    
    <style scoped>
    .filter-container{
      margin-bottom: 10px;
    }
    </style>
    
    

    baseDialog.vue

    
    <script>
    export default {
      name: 'BaseDialog',
      data() {
        return {
          loading: false
        }
      },
      render(h) {
        const { $attrs, $listeners, $slots } = this
        const attrs = {
          props: { ...$attrs },
          on: { ...$listeners },
          scopedSlots: {
            default: scope => {
              return $slots.default
            },
            title: scope => {
              return $slots.title
            },
            footer: scope => {
              const defaultFooter = (<span slot='footer' className={'dialog-footer'}>
                <el-button {...{ on: { click: $listeners.cancel }}}>取消</el-button>
                <el-button type='primary' {...{ props: { loading: $attrs.loading }, on: { click: $listeners.ok }}}>
              确定
                </el-button>
              </span>)
              return $slots.footer || defaultFooter
            }
          }
        }
    
        return <el-dialog {...attrs}>
          <div slot='footer'/>
        </el-dialog>
      }
    }
    </script>
    
    <style scoped>
    
    </style>
    
    

    相关文章

      网友评论

          本文标题:render 函数封装element-ui表格 form表单

          本文链接:https://www.haomeiwen.com/subject/wzqtsrtx.html