vue excel导入导出(封装)

本文介绍了如何使用Vue和ElementUI组件库实现Excel文件的导入和导出功能。通过封装Upload组件,实现了文件上传并调用自定义的上传函数处理数据。同时,提供了下载模板和导入数据的界面,支持拖拽上传。文章还展示了cus-modal(自定义模态框)、cus-button(自定义按钮)等组件的代码实现,并提供了接口导入数据的示例。
摘要由CSDN通过智能技术生成

方法一:参考链接:Vue + Element 实现导入导出Excel_程序猿小白的博客-CSDN博客_vue 导出excel

方法二 封装代码:下载数据封装(cus-upload.vue)

<template>
  <Upload action="//jsonplaceholder.typicode.com/posts/"
          :before-upload="onBeforeUpload"
          :show-upload-list="false"
          :maxSize="maxSize"
          :accept="accept">
    <slot></slot>
  </Upload>
</template>

<script>
export default {
  name: 'cus-upload',
  props: {
    autoUpload: {
      type: Boolean,
      default: false
    },
    accept: {
      type: String,
      // excel -> application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel
      // zip -> application/zip
      default: ''
    },
    maxSize: {
      type: Number,
      default: 12048
    },
    uploadFnc: {
      type: Function,
      default: () => {
      }
    },
    fileName: {
      type: String,
      default: 'file'
    },
    cusParams: {
      type: Object,
      default: () => {
        return {}
      }
    }
  },
  mounted () {
    this.onBeforeUpload()
  },
  methods: {
    onBeforeUpload (file) {
      if (file && this.autoUpload) {
        this.$cu.showLoading()
        let params = new FormData()
        params.append(this.fileName, file)
        this.uploadFnc(params).then(res => {
          if ( res.code === 200 ) {
            console.log(res)
            this.$cu.hideLoading()
            this.$Message.success('文件上传成功')
            this.$emit('onOk')
          } else this.$cu.hideLoading(1.5)
        }).catch(() => this.$cu.hideLoading(1.5))
      } 
      else if (file) this.$emit('onBeforeUpload', file)
      return false
    }
  }
}
</script>

<style scoped>

</style>

导入文件封装()

<template>
  <div>
    <cus-modal ref="modal" title="导入数据" @on-visible-change="onVisibleChange"
               width="520">
      <div class="draw-section">
        <Card class="draw-section-item" @click.native="downloadTemp">
          <div class="draw-section-item-logo flex">
            <svg t="1628043668627" class="icon" viewBox="0 0 1417 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
                 p-id="19836" width="128" height="128">
              <path
                d="M708.923077 356.273231c29.617231 0 54.035692 22.528 56.950154 51.436307l0.315077 5.828924v343.04l81.289846-81.211077a57.265231 57.265231 0 0 1 76.327384-4.17477l4.726154 4.17477a57.265231 57.265231 0 0 1 4.096 76.327384l-4.174769 4.726154-179.042461 178.963692a57.265231 57.265231 0 0 1-76.406154 4.17477l-4.568616-4.17477-179.042461-179.042461a57.265231 57.265231 0 0 1 76.406154-85.149539l4.568615 4.17477 81.289846 81.211077V413.538462c0-26.939077 18.589538-49.624615 43.716923-55.611077l7.719385-1.339077L708.923077 356.273231zM708.923077 17.092923c203.303385 0 376.359385 143.123692 408.969846 336.344615l-2.048-10.712615 13.627077 3.308308c126.660923 33.870769 218.112 143.202462 224.964923 271.753846l0.393846 15.596308c0 164.706462-137.688615 298.062769-307.278769 298.062769h-24.260923a56.792615 56.792615 0 0 1-57.501539-56.162462c0-31.113846 25.836308-56.162462 57.501539-56.162461h24.260923c106.338462 0 192.354462-83.259077 192.354462-185.737846 0-97.516308-78.296615-178.648615-178.884924-185.344a56.871385 56.871385 0 0 1-53.484307-51.672616C995.643077 246.075077 865.516308 129.339077 708.923077 129.339077s-286.72 116.736-298.692923 267.027692a56.871385 56.871385 0 0 1-53.405539 51.672616c-100.588308 6.695385-178.806154 87.827692-178.806153 185.344 0 102.4 85.937231 185.737846 192.275692 185.737846h24.260923c31.586462 0 57.501538 25.048615 57.501538 56.162461a56.792615 56.792615 0 0 1-57.501538 56.162462H370.215385C200.704 931.446154 63.015385 798.089846 63.015385 633.383385c0-143.675077 105.550769-266.24 249.540923-292.864l-10.633846 2.284307 1.339076-6.774154C341.858462 157.459692 501.366154 25.521231 690.491077 17.486769z"
                p-id="19837"></path>
            </svg>
          </div>
          <div class="draw-section-item-title">下载模板</div>
          <div class="draw-section-item-label">下载模板文件</div>
        </Card>
        <Card class="draw-section-item">
          <cus-upload :uploadFnc="uploadFnc" :autoUpload="true" :accept="accept" @onOk="onOk" :cus-params="cusParams"
                      :fileName="fileName">
            <div class="draw-section-item-logo flex">
              <svg t="1628043694436" class="icon" viewBox="0 0 1157 1024" version="1.1"
                   xmlns="http://www.w3.org/2000/svg" p-id="24667" width="118" height="118">
                <path
                  d="M0.09216 582.528c0-124.37504 82.23744-233.71264 192.1536-266.112C253.07648 156.0832 403.70688 40.96 579.93216 40.96c177.64352 0 324.18304 115.07712 384.96768 275.456 113.4336 33.152 192.19968 141.06624 192.19968 266.112 0 153.96864-119.57248 279.14752-270.91968 279.14752-28.34432 0-53.92896-26.60864-53.92896-56.06912 0-33.8176 25.58464-56.1152 53.92896-56.1152 91.22816 0 163.80928-74.09664 163.80928-166.87616 0-49.61792-21.44768-95.67744-56.64768-125.1328l-9.66144-9.43616a48.96256 48.96256 0 0 0-12.46208-10.05568c-2.75968-3.60448-9.03168-3.60448-12.46208-6.49728h-3.42528c-2.75968-3.5584-6.23104-3.5584-9.0368-6.4512h-3.47136c-2.75968 0-6.23104-3.5584-9.65632-3.5584-2.75968 0-6.23104 0-6.23104-2.8928h-9.0368c-3.47136 0-6.23104 0-9.7024-3.60448h-25.4976c-2.75968-10.81344-6.23104-18.688-6.23104-29.50144-2.75968 0-2.75968-3.5584-2.75968-6.4512-3.42528-6.49728-3.42528-12.90752-6.23104-19.44576 0-3.5584-3.42528-3.5584-3.42528-7.16288-2.75968-6.49728-6.23104-12.90752-9.65632-19.4048v-6.49728c-2.80576-6.4512-9.07776-12.90752-12.46208-19.44576-53.18144-92.11392-151.38816-154.63936-261.97504-154.63936-113.34144 0-211.46624 62.5664-264.68864 154.63936l-9.0368 19.44576c0 2.18112-1.42336 2.18112-2.08896 4.31616l-1.3824 2.18112-9.7024 19.4048v7.16288l-8.94464 19.44576v6.4512c-3.47136 10.77248-6.94272 18.688-6.94272 29.46048h-28.30336c-2.75968 3.60448-6.23104 3.60448-8.94464 3.60448h-6.23104c-2.75968 2.18112-4.14208 2.8928-4.89472 2.8928a1.24928 1.24928 0 0 1-2.048 0c-2.75968 0-6.23104 3.5584-9.03168 3.5584h-6.23104c-3.42528 2.93376-6.23104 2.93376-9.65632 6.49728h-3.42528c-2.75968 2.8928-6.23104 2.8928-9.07776 6.49728h-3.42528c-2.75968 3.5584-6.23104 6.4512-9.7024 10.05568-6.23104 2.84672-8.94464 6.49728-12.416 9.39008-35.24608 29.50656-53.2224 75.56096-53.2224 125.17888 0 92.77952 72.58112 166.87616 160.37888 166.87616 32.4864 0 56.69376 22.29248 56.69376 56.06912 0 29.50656-24.20736 56.07424-56.69376 56.07424-147.82976 0.04096-270.8736-125.13792-270.8736-279.01952v-0.09216z"
                  p-id="24668"></path>
                <path
                  d="M362.94656 566.72768c0-16.54784 6.23104-28.78976 12.46208-39.56224l163.7632-186.90048c10.41408-10.81344 24.91904-16.55296 40.8064-16.55296 15.92832 0 28.34432 5.7856 41.47712 16.512l160.37888 186.98752c21.5296 22.19008 21.00224 57.63072-1.18784 79.16544a56.00256 56.00256 0 0 1-39.57248 15.80032c-15.92832 0-27.67872-8.6784-38.04672-19.45088l-69.10976-78.40768v281.9584c0 33.8176-24.21248 55.3984-53.93408 55.3984-31.104 0-53.2224-21.5808-53.2224-55.3984v-281.91232L457.69728 602.7264c-10.368 10.81344-25.54368 19.45088-41.43104 19.45088-28.3904 0-53.31456-25.90208-53.31456-55.40352v-0.04608z"
                  p-id="24669"></path>
              </svg>
            </div>
            <div class="draw-section-item-title">导入excel</div>
            <div class="draw-section-item-label">导入excel文件 <br/> 可拖拽上传</div>
          </cus-upload>
        </Card>
      </div>
      <div slot="footer">
        <div class="modal-footer">
          <cus-button size="small" class="mr_2" @onClick="onCancel">关闭</cus-button>
        </div>
      </div>
    </cus-modal>
  </div>
</template>

<script>

  /**
   * @tempSrc       模板导出地址
   * @uploadFnc     文件上传方法
   * @accept        上传文件类型
   * @fileName      文件名,默认file
   * @cusParams     自定义额外参数
   *
   * @onClear 导入文件
   */
  const form = {
    id: '',
    name: '',
    age: '',
    phonenumber: '',
    userId: '',
    // index: [],
    // phone: '',
    // administration: '',
    // descr: ''
  }

  export default {
    name: 'addSupplier',
    data() {
      return {
        form: form
      }
    },
    props: {
      tempSrc: {
        type: String,
        default: ''
      },
      uploadFnc: {
        type: Function,
        default: () => {
        }
      },
      accept: {
        type: String,
        // excel -> application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel
        default: ''
      },
      fileName: {
        type: String,
        default: 'file'
      },
      cusParams: {
        type: Object,
        default: () => {
          return {}
        }
      }
    },
    mounted() {
      this.form = this.$cu.deepClone(form)
    },
    methods: {
      onVisibleChange(v) {
        if (!v) this.form = this.$cu.deepClone(form)
      },
      onCancel() {
        this.$refs['modal'].show = false
      },
      onOk() {
        this.$refs['modal'].show = false
        this.$emit('onOk')
        console.log('保存成功')
      },
      show() {
        this.$refs['modal'].show = true
      },
      downloadTemp() {
        window.location.href = this.tempSrc
      }
    }
  }
</script>

<style scoped lang="less">
  .draw {
    &-section {
      display: flex;
      align-items: center;
      justify-content: space-around;

      &-item {
        background: white;
        display: flex;
        flex-direction: column;
        align-items: center;
        height: 220px;
        cursor: pointer;
        width: 170px;


        &-title {
          text-align: center;
          margin-top: 10px;
          color: rgba(51, 51, 51, 1);
        }

        &-label {
          text-align: center;
          color: rgba(153, 153, 153, 1);
        }
      }
    }
  }
</style>

cus-model(卡片)

<template>
  <Modal v-model="show" :styles="styles" :class-name="className"
         :closable="closable"
         :mask-closable="maskClosable"
         @on-visible-change="onVisibleChange">
    <div slot="header" class="modal-header">
      <span class="ml_10">{{ title }}</span>
      <div class="modal-header-fullscreen" v-if="showFullscreen">
        <Icon type="ios-expand" color="#999" size="17" v-if="!fullscreen" @click="fullscreen = !fullscreen"/>
        <Icon type="ios-contract" color="#999" size="17" v-if="fullscreen" @click="fullscreen = !fullscreen"/>
      </div>
    </div>
    <slot></slot>
    <div slot="footer">
      <slot name="footer">
        <div class="modal-footer">
          <cus-button size="small" class="mr_2" @onClick="onCancel">取消</cus-button>
          <cus-button type="primary" size="small" @onClick="onOk">确认</cus-button>
        </div>
      </slot>
    </div>
  </Modal>
</template>

<script>
export default {
  name: 'cus-modal',
  data () {
    return {
      fullscreen: false,
      show: false,
    }
  },
  props: {
    title: {
      type: String,
      default: '添加'
    },
    width: {
      type: [String, Number],
      default: 700
    },
    showFullscreen: {
      type: Boolean,
      default: false
    },
    closable: {
      type: Boolean,
      default: true,
    },
    maskClosable: {
      type: Boolean,
      default: true
    }
  },
  computed: {
    styles () {
      let style = {}
      if (!this.fullscreen) {
        /*if (style.width.indexOf('px') !== -1 || style.width.indexOf('%') !== -1 || style.width.indexOf('vw') !== -1 || style.width.indexOf('vh') !== -1 || style.width.indexOf('rem') !== -1) {
          style.width = `${this.width}`;
        } else style.width = `${this.width}px`;*/
        style.width = `${this.width}px`
      } else {
        style.width = '100%'
        style.top = 0
      }
      return style
    },
    className () {
      if (this.fullscreen) {
        return 'fullscreen-modal'
      } else {
        return ''
      }
    }
  },
  methods: {
    onOk () {
      this.$emit('onOk')
    },
    onCancel () {
      this.show = false;
    },
    onVisibleChange (v) {
      this.$emit('on-visible-change', v)
    }
  }
}
</script>

<style lang="less">
.modal-header {
  display: flex;
  /*justify-content: center;*/
  align-items: center;
  position: relative;
  height: 20px;
  font-size: 16px;
  font-family: PingFangSC-Medium, PingFang SC;
  font-weight: 500;
  color: rgba(0, 0, 0, 0.85);

  &-fullscreen {
    position: absolute;
    right: 30px;
    cursor: pointer;

    i:hover {
      color: black !important;
    }
  }
}

.modal-footer {
  display: flex;
  justify-content: flex-end;
  align-items: center;
}
</style>

cus-button

<template>
  <Button :style="[btnStyle]" :disabled="disabled" :type="type" @click="onClick" :ghost="ghost">
    <slot></slot>
  </Button>
</template>

<script>
  export default {
    name: "cus-button",
    props: {
      type: {
        type: String,
        default: null
      },
      size: {
        type: String,
        default: 'default'
      },
      ghost: {
        type: Boolean,
        default: false,
      },
      shape: {
        type: String,
        default: 'default'
      },
      cusStyle: {
        type: Object,
        default: () => {
          return {}
        }
      },
      disabled: {
        type: Boolean,
        default: false
      }
    },
    computed: {
      btnStyle() {
        let style = {
          transition: 'all .1s',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          fontSize: '16px',
          padding: '0 16px',
          fontFamily: "PingFangSC-Regular, PingFang SC",
          // borderRadius: '2px',
          cursor: 'pointer',
        };
        if (this.shape == 'circle') style.borderRadius = '34px';
        style = Object.assign(style,this.cusStyle);
        if (this.size == 'default') {
          style.height = '40px';
        } else if (this.size == 'small') {
          style.height = '32px';
          style.fontSize = '12px';
        }

        return style;
      }
    },
    methods: {
      onClick() {
        this.$emit('onClick');
      }
    }
  }
</script>

<style scoped lang="less">

</style>

接口导入

// Excel导入用户信息
export const getUserImportData = (params = {}) => { // 文件上传
    return http.post(`${baseURL}/user/importData`, params, { headers: { 'Content-Type': 'multipart/form-data' }
    }).then(res => res.data)
  }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

韩召华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值