基于Vue封装hansontable及自定义编辑器

一、设计思路及背景

        项目地址:GitHub - JavonHuang/zqWeb2.0

        hansontable其官方也有提供Vue的版本,使用过的人应该知道,其实本质还是通过配置config的形式。对于列的动态配置,数据的绑定自定义渲染,还是很不方便。需要进行大量的jq的写法,使得代码不够简洁,维护不易,更不好和第三方UI组件融合。

        基于上述问题,借鉴element-ui的思路,对表格进行封装改造,使其编写风格与element-ui风格相似。让代码更加简介,使用方便易于维护及扩展。如图:

<template>
  <div>
    <el-button v-on:click="handelGetData()" size="small">获取数据</el-button>
    <pageVHandsontable
      ref="page"
      :url="'/gzList/getGzList'"
      :nestedHeaders="nestedHeaders"
      :manualColumnResize="true"
      :default-sort="{data:'CLOSE_PRICE',sort:'asc'}"
      :fixedRowsBottom="1"
      :countFixedRowsBottom="true"
      :fixedColumnsLeft="0"
      :columnsFooter="columnsFooter"
      v-on:selection-change="selectionChange"
      >
      <VhTableColumn type="selection"></VhTableColumn>
      <VhTableColumn type="text" data="SECURITY_NAME" :readOnly="false" title="代码名" width="200" :show-overflow-tooltip="true">
        <template slot="editors" slot-scope="slotProps">
          <myselect :slotProps="slotProps"></myselect>
        </template>
      </VhTableColumn>
      <VhTableColumn type="text" data="CLOSE_PRICE" :sortable="true" title="收价" width="200">
        <template slot="editors" slot-scope="slotProps">
          <vhInput :slotProps="slotProps"></vhInput>
        </template>
      </VhTableColumn>
      <VhTableColumn type="text" data="CHANGE_RATE" :sortable="true" :readOnly="true" title="波动" width="200"></VhTableColumn>
      <VhTableColumn type="text" data="TRADE_DATE" :sortable="true" width="200" title="日期">
        <template slot="editors" slot-scope="slotProps">
          <vhdate :slotProps="slotProps"></vhdate>
        </template>
        <template slot="header" slot-scope="slotProps">
          <div>
            <div>{{slotProps.columns.title}}</div>
          </div>
        </template>
        <template slot="headerTips" slot-scope="slotProps">
          <div>
            <el-tooltip class="item" effect="dark" :content="slotProps.columns.title" placement="top">
                <i class="el-icon-question"></i>
            </el-tooltip>
          </div>
        </template>
        <template slot-scope="slotProps">
          <div>
            <div>{{ dateF(slotProps.rowData.TRADE_DATE,slotProps)}}</div>
          </div>
        </template>
        
      </VhTableColumn>
      <VhTableColumn type="text" data="A_SHARES_RATIO" :readOnly="true" title="占比" width="180" :formatter="(rowData,prop,value,rowIndex)=>{return value +'%'}"></VhTableColumn>
      <VhTableColumn type="text" data="HOLD_SHARES" :readOnly="true" title="数量" width="180" :show-overflow-tooltip="true"></VhTableColumn>
      <VhTableColumn type="text" data="HOLD_MARKET_CAP" :readOnly="true" title="规模" width="180"></VhTableColumn>  
      <VhTableColumn title="操作" :width="1000">
        <template slot-scope="slotProps">
          <div>
            <el-button v-on:click="handelClick(slotProps)" type="text" size="small">查看</el-button>
          </div>
        </template>
      </VhTableColumn>
    </pageVHandsontable>
  </div>
</template>

<script>
import moment from 'moment'
import pageVHandsontable from './../components/handsontable/pageVHandsontable'
import VhTableColumn from './../components/handsontable/vh-table-column'
import myselect from './hansonEditor/vhSelect'
import vhInput from './hansonEditor/vhInput'
import vhdate from './hansonEditor/vhdate'
export default {
  components:{
    pageVHandsontable,
    VhTableColumn,
    myselect,
    vhInput,
    vhdate
  },
  data(){
    return{
      nestedHeaders:['A', { label: this.test(), colspan: 2 },'测试',{ label: '合并表头', colspan: 2 },{ label: '合并第二', colspan: 2 }],
      columnsFooter:{}
    }
  },
  mounted(){
    setTimeout(()=>{
      this.columnsFooter = {
        SECURITY_CODE:'877979',
        CLOSE_PRICE:'合计测试12',
        CHANGE_RATE:'213',
        A_SHARES_RATIO:'7878'
      }
    })
  },
  methods:{
    dateF(e,slotProps){
      return moment(e).format('YYYY-MM-DD')
    },
    onColumnsSort(e){
      console.log(e)
    },
    selectionChange(e){
      console.log(e)
    },
    handelClick(e){
      console.log(e)
    },
    test(){
      return '879898'
    },
    changew(){
      alert('9898')
    },
    handelGetData(){
      console.log(this.$refs.page.getData())
    }
  }
}
</script>

<style>

</style>

<style lang="scss" scoped>
.editorsSel{
  &.el-select{
    height: 100%;
    width: 100%;
    ::v-deep
    .el-input{
      height: 100%;
      .el-input__inner{
        height: 100%;
        width: 100%;
        padding: 0 8px;
        border: none;
        line-height:1;
        box-sizing: border-box;
      }
      .el-input__suffix{
        .el-input__icon{
          line-height:1;
        }
      }
    }
  }
}
</style>

效果:

二、Options

  • defaultSort                           [Object]     默认排序                {data:'CLOSE_PRICE',sort:'asc'}

  • width                                    [String]      table宽                   参考官网配置

  • height                                  [String]       table高                   参考官网配置

  • rowHeaders                        [Boolean]    显示列头                参考官网配置

  • rowHeights                         [Number]     行高                       参考官网配置

  • colWidths                            [Number]     列宽                       参考官网配置

  • stretchH                              [String]        列宽自适应             参考官网配置

  • className                          [String]       单元格样式              Horizontal: htLeft, htCenter, htRight, htJustify,Vertical: htTop, htMiddle, htBottom

  • currentRowClassName        [String]       选中行样式             参考官网配置

  • mergeCellsKey                     [Array]       合并行key依据        自定义功能,仅适用行并

  • manualColumnResize          [Boolean]   拖动改变宽度          参考官网配置

  • nestedHeaders                     [Array]       多表头自定义           参考官网配置

  • countFixedRowsBottom       [Boolean]   底部悬浮合计           自定义功能

  • fixedRowsBottom                 [Number]   底部悬浮[countFixedRowsBottom开启的时候必须置1]                参考官网配置

  • fixedColumnsLeft                 [Number]    左悬浮                      参考官网配置

  • columnsFooter                    [Object]       合计行显示                自定义功能,以对应columns key

三、VhTableColumn

  • type             [String]           列数据类型

  • width           [Number]        指定列宽

  • data             [String]            列绑定字段

  • title              [String]           列头显示标题

  • readOnly     [Boolean]       列可编辑

  • formatter     [Function]       列显示回调,类似element-ui

  • showOverflowTooltip [Boolean]   文字溢出省略号,显示提示

  • sortable       [Boolean]         列排序

四、VhTableColumn slot-scope

  • editors             编辑器渲染插槽

  • header            column列头渲染插槽

  • headerTips      column列头额外提示信息

  • default             column默认插槽,cell渲染内容

五、editors slot-scope 以结合Element-ui组件为例,自定义编辑器

        所有的组件需要统一使用一种组件模板,并实现对应的钩子。

1、el-input

<template>
  <el-input class="editors-input" v-model="value" placeholder="请输入内容"></el-input>
</template>

<script>
export default {
  props:{
    slotProps:Object
  },
  data(){
    return{
      value:899898
    }
  },
  created(){
    //务必注册这两个钩子
    this.slotProps['setValue'] = this.setValue
    this.slotProps['getValue'] = this.getValue
  },
  methods:{
    //编辑触发,e是当前cell值
    setValue(value){
      this.value = value
    },
    //编辑完成会调用,返回cell显示值并更新对例,
    getValue(){
      return this.value
    }
  }
}
</script>

<style lang="scss" scoped>
.editors-input{
  height: 100%;
  ::v-deep
  input{
    height: 100%;
    padding: 0 8px;
    box-sizing: border-box;
    border: none;
  }
}
</style>

效果:

2、el-select

<template>
  <el-select :popper-append-to-body="false" class="editorsSel" v-on:change="change" v-model="value" placeholder="请选择">
    <el-option
      v-for="item in options"
      :key="item.value"
      :label="item.label"
      :value="item.value"
      :disabled="item.disabled">
    </el-option>
  </el-select>
</template>

<script>
  export default {
    props:{
      slotProps:Object
    },
    data() {
      return {
        options: [{
          value: '000750',
          label: '国海证券'
        }, {
          value: '600326',
          label: '西藏天路'
        }],
        value: null
      }
    },
    created(){
      this.slotProps['setValue'] = this.setValue
      this.slotProps['getValue'] = this.getValue
    },
    methods:{
      change(e){
        let obj = this.options.find(item=>item.value==e)
        this.value = obj.value
      },
      setValue(e){
        //获取row的值,设置下拉默认选中值
        let SECURITY_CODE = this.slotProps.hot.getDataAtRowProp(this.slotProps.row,'SECURITY_CODE')
        let obj = this.options.find(item=>item.value==SECURITY_CODE)
        this.value = obj.value
      },
      getValue(){
        let obj = this.options.find(item=>item.value==this.value)
        //由于下拉显示的label和value是不一样的字段,这里需要设置对应的源数据值
        this.slotProps.hot.setSourceDataAtCell(this.slotProps.row,'SECURITY_CODE',obj.value)
        return obj.label
      }
    }
  }
</script>
<style lang="scss" scoped>
.editorsSel{
  &.el-select{
    height: 100%;
    ::v-deep
    .el-input{
      height: 100%;
      .el-input__inner{
        height: 100%;
        width: 100%;
        padding: 0 8px;
        border: none;
        line-height:1;
        box-sizing: border-box;
      }
      .el-input__suffix{
        .el-input__icon{
          line-height:1;
        }
      }
    }
  }
}
</style>

 效果:

3、el-date

<template>
  <el-date-picker
      class="editors-date"
      v-model="value"
      v-on:change="change"
      type="date"
      placeholder="选择日期">
    </el-date-picker>
</template>

<script>
export default {
  props:{
    slotProps:Object
  },
  data(){
    return{
      value:899898
    }
  },
  created(){
    this.slotProps['setValue'] = this.setValue
    this.slotProps['getValue'] = this.getValue
  },
  methods:{
    setValue(value){
      this.value = value
    },
    getValue(){
      return this.value
    },
    change(e){
      //由于element-ui的下拉层是挂在body的,这样点击日历后,table会先取消了变状态,在getValue返回的不是当前选中的值
      //所以需要这里手动设置值
      this.slotProps.hot.setSourceDataAtCell(this.slotProps.row,'TRADE_DATE',e)
    }
  }
}
</script>

<style lang="scss" scoped>
.editors-date{
  height: 100%;
  width: 100%;
  ::v-deep
  input{
    height: 100%;
    padding: 0 8px;
    box-sizing: border-box;
    border: none;
    padding-left: 30px;
  }
  ::v-deep
  .el-input__suffix{
    .el-input__icon{
      line-height: inherit;
    }
  }
  ::v-deep
  .el-input__prefix{
    .el-input__icon{
      line-height: inherit;
    }
  }
}
</style>

 效果:

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值