vue剪切板功能的封装以及使用

文章目录


项目效果图

一、剪切板的用处?

为满足业务的快速操作便捷,往往业务只知道商品的编码和需要的对应数量,此时复制简单内容往剪切板一丢,就能填写想要的对应数据。

二、封装剪切板

1.封装button

<template>

          <span>  
 
             <template v-else-if="type === 'copyPaste'">
    
                  <el-button

                    size="small"

                    type="primary"

                    :disabled="disabled"

                    @click="handleCopyPaste"

                      >

                        剪切板

                  </el-button>

                </template>

         </span>
        <CopyPaste
              ref="copyPasteDialog"
              :paste="paste"
              :copy-paste-function="copyPasteFunction"
              @close-callback="$emit('getProductData')"
        />

</template>
<script>
props: {
    copyPasteFunction: {
        //copyPaste 剪贴板判断使用方式 byTransfer:调拨单剪切板
        type: String,
        default: '',
      }, 
 paste: {
        type: Function,
        default: () => {
          return Function
        },
      },
 beforePasteOpen: {
        type: Function,
        default: () => Function,
      },
}
//点击事件
handleCopyPaste() {
     if (!this.beforePasteOpen()) return
     this.$refs.copyPasteDialog.open()
},

handleCopyPaste() {
        if (!this.beforePasteOpen()) return
        this.$refs.copyPasteDialog.open()
      },
</script>

2.封装剪切板组件(弹窗可以直接用原生)

<template>
  <DragDialog
    :is-need-footer="true"
    :dialog-visible.sync="visible"
    :title="$t('common.copyPaste')"
    :append-to-body="true"
    @submit="handleOk"
  >
    <template slot="dialog-main">
      <div class="tiplabel">
        请粘贴产品编码/数量到此处
        <span class="download" @click="handleExport()">模版下载</span>
      </div>
      <el-input
        v-model="textarea"
        type="textarea"
        :autosize="{ minRows: 6, maxRows: 10 }"
        placeholder="请粘贴内容"
        @change="change"
      >
        >
      </el-input>
      <div v-if="err.length">
        产品编号:
        <span
          v-for="(item, index) in err"
          :key="index"
          style="color: red; padding: 0 5px"
        >
          {{ item }}
        </span>
        不存在,请修改Excel再进行尝试!
      </div>
    </template>
  </DragDialog>
</template>

<script>
  import DragDialog from '@/components/DragDialog'
  import { baseURL } from '@/config' //项目的基础地址
  import axios from 'axios'
  import store from '@/store' //仓库 获取token
  import { details } from '@/api/commodity/product' //获取商品的详情接口 后续看你们自己什么业务
  import { tenantId } from '@/utils/token'
  export default {
    name: 'CopyPaste',
    components: { DragDialog },
    props: {
      paste: {
        type: Function,
        default: () => {
          return Function
        },
      },
      copyPasteFunction: {
        //copyPaste 剪贴板判断使用方式 byTransfer:调拨单剪切板
        type: String,
        default: '',
      },
    },
    data() {
      return {
        err: [],
        textarea: '',
        visible: false,
      }
    },
    computed: {
      uploadHeaders() {
        return {
          Authorization: `bearer ${store.getters['user/token']}`, //获取token
        }
      },
      templateUrl() { //模板下载地址
        let fileName = '剪贴板模板.xls'
        this.copyPasteFunction === 'byTransfer' &&
          (fileName = `调拨单剪贴板模板.xls`)
        return `${baseURL}/tfle/v1/files/download-by-key?fileKey=inventory/template/product/${tenantId()}/${fileName}`
      },
    },
    methods: {
      change() {
        //处理你需要的数据结构
        let str = this.textarea
        let target = str.split('\n') //切割拿到input框的值进行下面操作
        let list = []
        target.map((item) => {
          let itemArr = item.split('\t')
          if (itemArr[0]) {
            let obj =
              this.copyPasteFunction === 'byTransfer'
                ? {
                    outLogicWarehouseName: itemArr[0],
                    inLogicWarehouseName: itemArr[1],
                    productCode: itemArr[2],
                    applyQuantity: itemArr[3] || 0,
                  }
                : {
                    productCode: itemArr[0],
                    applyQuantity: itemArr[1] || 0,
                  }
            list.push(obj)
          }
        })
        //判断你传进来的是什么类型,这里可以根据你传进来的剪贴板判断使用方式 进行不同的操作
        if (this.copyPasteFunction === 'byTransfer') {
          this.data = list
        } else {
            //不是调拨单剪切板进行接口请求操作
          this.verify(list)
        }
      },
      verify(list) {
        let data = [],
          err = []
        list.map((item) => {
          details({ productCode: item.productCode }).then((res) => {
            if (res.success == false) {
              err.push(item.productCode)
            } else {
              res.applyQuantity = item.applyQuantity
              data.push(res)
            }
          })
        })
        this.err = err
        if (err.length) {
          return false
        }
        this.data = data
      },
      open() {
        // if (!this.checkUrl()) {
        this.visible = true
        // }
      },
      close() {
        this.visible = false
      },
      handleOk() {
        if (this.data.length) {
          console.log('这里的', this.data)
          this.visible = false
          this.paste(this.data) //传进来的函数接收处理完的数据进行操作
        }
      },
        //模板下载操作
      handleExport() {
        axios
          .get(this.templateUrl, {
            responseType: 'blob',
            headers: { ...this.uploadHeaders },
          })
          .then((res) => {
            if (res.status === 200) {
              var dom = document.createElement('a')
              dom.download = '剪贴板模板.xls'
              dom.style.display = 'none'
              dom.href = window.URL.createObjectURL(res.data)
              dom.click()
              this.$message({
                type: 'success',
                message: '下载成功',
              })
            }
          })
          .catch((err) => {
            this.$message.error(`下载失败,${err.message}`)
          })
      },
    },
  }
</script>

<style scoped lang="scss">
  .export-line {
    background: #e8e8e8;
    height: 1px;
    width: 100%;
    margin-bottom: 24px;
    clear: both;
  }
  .export-title {
    margin: 12px auto;
    line-height: 24px;
    font-size: 16px;
    color: #333;
  }
  .el-tree {
    color: #333;
  }
  .download {
    color: red;
    cursor: pointer;
  }
  .tiplabel {
    margin-bottom: 7px;
  }
</style>

3.弹窗封装(附带,有国际化操作 自己使用需要去除 或者引用国际化)

<template>
  <el-dialog
    v-if="destroyOnClose"
    v-el-drag-dialog
    :title="title"
    :visible.sync="visible"
    :close-on-click-modal="false"
    :width="width"
    :append-to-body="appendToBody"
    :show-close="!isLoading"
    :fullscreen="dialogFull"
    @dragDialog="handleDrag"
    @close="close"
  >
    <template slot="title">
      <div class="avue-crud__dialog__header">
        <span class="el-dialog__title">
          <span
            style="
              display: inline-block;
              background-color: #3478f5;
              width: 3px;
              height: 20px;
              margin-right: 5px;
              float: left;
              margin-top: 2px;
            "
          ></span>
          {{ title }}
        </span>
        <div
          v-if="isShowFullScreen"
          class="avue-crud__dialog__menu"
          @click="dialogFull ? (dialogFull = false) : (dialogFull = true)"
        >
          <i class="el-icon-full-screen"></i>
        </div>
      </div>
    </template>
    <div class="drag-dialog-container">
      <div
        ref="dragDialogContainerBody"
        class="main-bar"
        :style="{ maxHeight: maxHeight, minHeight: minHeight }"
      >
        <slot name="dialog-main" />
      </div>
      <div v-if="isNeedFooter" class="dialog-footer">
        <slot name="dialog-footer">
          <!-- 有默认的button,如果需要自定义,在外面通过slot传入也可以,如果使用默认按钮,记得传入相应按钮事件 -->
          <el-button
            v-show="isMore"
            type="primary"
            size="small"
            :loading="isLoading"
            @click="moreButton"
          >
            {{ moreButtonText || $t('common.ok') }}
          </el-button>
          <el-button
            v-show="isHidden"
            type="primary"
            size="small"
            :loading="isLoading"
            @click="submit"
          >
            {{ submitText || $t('common.ok') }}
          </el-button>
          <!-- 审批流 提交时禁止取消-->
          <el-button plain size="small" :disabled="isLoading" @click="cancel">
            {{ cancelText || $t('buttonTxt.cancel') }}
          </el-button>
        </slot>
      </div>
    </div>
  </el-dialog>
</template>

<script>
  import elDragDialog from '@/directive/el-drag-dialog'
  import { Debounce } from '../../utils/public.js'

  export default {
    name: 'DragDialog',
    directives: { elDragDialog },
    props: {
      title: {
        type: String,
        default: '',
      },
      dialogVisible: {
        type: Boolean,
        default: false,
      },
      isNeedFooter: {
        // 是否需要footer, 默认需要
        type: Boolean,
        default: true,
      },
      maxHeight: {
        type: String,
        default: '70vh',
      },
      minHeight: {
        type: String,
        default: '350px',
      },
      width: {
        type: String,
        default: '50%',
      },
      cancelText: {
        type: String,
        default: '',
      },
      submitText: {
        type: String,
        default: '',
      },
      appendToBody: {
        // 是否是嵌套
        type: Boolean,
        default: false,
      },
      destroyOnClose: {
        // 是否关闭时销毁 Dialog 中的元素
        type: Boolean,
        default: true,
      },
      isLoading: {
        type: Boolean,
        default: false,
      },
      moreButtonText: {
        type: String,
        default: '',
      },
      isMore: {
        type: Boolean,
        default: false,
      },
      isHidden: {
        type: Boolean,
        default: true,
      },
      isShowFullScreen: {
        type: Boolean,
        default: false,
      },
    },
    data() {
      return {
        dialogFull: false,
      }
    },
    computed: {
      visible: {
        get() {
          return this.dialogVisible
        },
        set(val) {
          this.$emit('update:dialogVisible', val)
          this.$emit('resetThContent') // 关闭弹窗的时候进行重置
        },
      },
    },
    methods: {
      // v-el-drag-dialog onDrag callback function
      handleDrag() {
        console.log('you had handle drag')
      },
      close() {
        this.$emit('close')
      },
      submit: Debounce(function () {
        this.$emit('submit')
      }, 500),
      cancel() {
        this.visible = false
        this.$emit('cancel')
      },
      getBodyRefs() {
        return this.$refs.dragDialogContainerBody
      },
      moreButton() {
        this.$emit('moreButton')
      },
    },
  }
</script>
<style lang="scss" scoped>
  .drag-dialog-container {
    position: relative;
    padding-bottom: 52px;
    // overflow: auto;
    .main-bar {
      overflow-y: auto;
      overflow-x: hidden;
      padding: 24px 24px 0;
      min-height: 200px !important;
    }
    .dialog-footer {
      width: 100%;
      height: 52px;
      position: absolute;
      bottom: 0;
      left: 0;
      text-align: right;
      padding: 0 20px 0;
      border-top: 1px solid $dashed-01;
      line-height: 52px;
      .el-button--default {
        border: 1px solid #d9d9d9;
      }
      button {
        margin-left: 24px;
        margin-right: 0 !important;
      }
    }
  }
  .el-dialog__header {
    padding: 15px 20px 15px;
  }
  .el-dialog__headerbtn {
    top: 15px;
  }

  /*dialog header*/
  .el-dialog__header {
    background: #e3eaed;
  }
  .avue-crud__dialog__header {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    -webkit-box-pack: justify;
    -ms-flex-pack: justify;
    justify-content: space-between;
  }
  .el-dialog__title {
    color: rgba(0, 0, 0, 0.85);
    font-weight: 500;
    word-wrap: break-word;
  }
  .avue-crud__dialog__menu {
    padding-right: 20px;
    float: left;
  }
  .avue-crud__dialog__menu i {
    color: #909399;
    font-size: 15px;
  }
  .el-icon-full-screen {
    cursor: pointer;
  }
  .el-icon-full-screen:before {
    content: '\e719';
    color: #fff;
    font-size: 22px;
    margin-right: 6px;
  }
</style>

 三、使用剪切板

<OperateButton
            type="copyPaste"
            copy-paste-function="byTransfer" //传入的使用方式
            :before-paste-open="beforePasteOpen" //传入前的函数判断
            :paste="addDetail"
/>


addDetail(data) {
    //data就是封装那边返回来的数据填写的 需要统一格式可以封装好数据
    //这里若是还需要调接口进行其它操作

    //若是不进行其它操作 只需要商品数据,下面即可
    let list = data.map((item) => {
          return {
            productName: item.productName,
            productCode: item.productCode,
            applyQuantity: item.applyQuantity,
            isSet: true,
          }
        })
    this.$refs.Detailed.list = this.$refs.Detailed.list.concat(list)
}


beforePasteOpen() {
        if (!this.schema_model.businessType) {
          this.$message.error('请先选择业务类型')
          return false
        }
        return true
},

 


总结

剪切板有需要的可以自取,有问题可以咨询

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值