沃梦达 / IT编程 / 前端开发 / 正文

基于element-ui组件手动实现单选和上传功能

下面是“基于element-ui组件手动实现单选和上传功能”的完整攻略:

下面是“基于element-ui组件手动实现单选和上传功能”的完整攻略:

前言

element-ui是一款非常流行的UI组件库,提供了很多常用的组件和功能。但是在实际的开发中,我们有时候需要根据自己的业务需求对组件进行一些改造或扩展。本攻略将详细讲解如何基于element-ui组件手动实现单选和上传功能。

单选功能实现

目标

我们需要实现一个单选框组件,在选中某个选项时,其他选项都需要变为未选中状态。

实现

首先,我们可以使用element-ui提供的radio组件作为基础,然后再进行扩展。具体步骤如下:

  1. 创建一个单选框组件(RadioGroup),继承自element-ui的RadioGroup组件。
<template>
  <el-radio-group v-model="selectedValue">
    <slot></slot>
  </el-radio-group>
</template>

<script>
import { RadioGroup } from 'element-ui';

export default {
  name: 'MyRadioGroup',
  extends: RadioGroup,
  data() {
    return {
      selectedValue: ''
    };
  }
};
</script>
  1. 在RadioGroup组件中使用插槽来渲染子选项(Radio)。
<template>
  <el-radio-group v-model="selectedValue">
    <slot></slot>
  </el-radio-group>
</template>
  1. 在子选项(Radio)中添加点击事件,当点击某个选项时将其他选项设置为未选中。
<template>
  <el-radio @click.native="handleClick"
            v-bind="$attrs"
            :label="label">
    <slot></slot>
  </el-radio>
</template>

<script>
import { Radio } from 'element-ui';

export default {
  name: 'MyRadio',
  extends: Radio,
  methods: {
    handleClick() {
      this.$emit('input', this.label);
      this.$parent.$children
        .filter((c) => c !== this)
        .forEach((c) => (c.selected = false));
    }
  }
};
</script>
  1. 最后,在使用组件的地方,我们可以如下方式渲染:
<template>
  <my-radio-group v-model="selectedValue">
    <my-radio label="选项1">选项1</my-radio>
    <my-radio label="选项2">选项2</my-radio>
    <my-radio label="选项3">选项3</my-radio>
  </my-radio-group>
</template>

<script>
import MyRadioGroup from '@/components/MyRadioGroup.vue';
import MyRadio from '@/components/MyRadio.vue';

export default {
  components: { MyRadioGroup, MyRadio },
  data() {
    return {
      selectedValue: ''
    };
  }
};
</script>

上传功能实现

目标

我们需要实现一个上传文件的组件,用户可以选择文件并上传到服务器,同时支持拖拽上传。

实现

和上面的单选框组件一样,我们可以使用element-ui提供的Upload组件作为基础,然后再进行扩展。具体步骤如下:

  1. 创建一个上传文件组件,继承自element-ui的Upload组件。
<template>
  <div v-drag-and-drop="handleDragAndDrop">
    <slot name="tip"></slot>
    <el-upload :headers="headers"
               :action="action"
               :data="data"
               :multiple="multiple"
               :show-file-list="showFileList"
               :auto-upload="autoUpload"
               :on-preview="onPreview"
               :on-remove="onRemove"
               :on-progress="onProgress"
               :on-success="onSuccess"
               :on-error="onError">
      <slot></slot>
      <el-button slot="trigger">
        <i class="el-icon-upload"></i>
        <span>{{ buttonText }}</span>
      </el-button>
      <el-button v-if="showClearButton"
                 slot="append"
                 @click.stop="handleClear">
        {{ clearButtonText }}
      </el-button>
    </el-upload>
  </div>
</template>

<script>
import { Upload } from 'element-ui';
import Vue from 'vue';

export default {
  name: 'MyUpload',
  extends: Upload,
  props: {
    showClearButton: {
      type: Boolean,
      default: false
    },
    clearButtonText: {
      type: String,
      default: '清空文件'
    }
  },
  data() {
    return {
      headers: {},
      action: '',
      data: {},
      multiple: false,
      showFileList: true,
      autoUpload: false,
      buttonText: '选择文件'
    };
  },
  methods: {
    handleClear() {
      this.$refs.upload.clearFiles();
    },
    handleDragAndDrop(e) {
      if (e.type === 'dragover') {
        e.preventDefault();
      } else if (e.type === 'drop') {
        e.preventDefault();

        const files = e.dataTransfer.files;

        for (let i = 0; i < files.length; i++) {
          const file = files.item(i);
          const xhr = new XMLHttpRequest();
          const formData = new FormData();

          formData.append('file', file);

          xhr.upload.addEventListener('progress', (e) => {
            if (e.lengthComputable) {
              const percent = Math.round((e.loaded / e.total) * 100);

              Vue.set(file, 'percent', percent);
            }
          });

          xhr.addEventListener('load', () => {
            const response = JSON.parse(xhr.responseText);
            Vue.set(file, 'url', response.data.url);
          });

          xhr.open('POST', this.action, true);
          xhr.setRequestHeader('Authorization', 'Bearer token');
          xhr.send(formData);
        }
      }
    }
  }
};
</script>
  1. 在MyUpload组件中添加新的props和methods,用于在拖拽上传时进行处理。
<script>
export default {
  name: 'MyUpload',
  extends: Upload,
  props: {
    showClearButton: {
      type: Boolean,
      default: false
    },
    clearButtonText: {
      type: String,
      default: '清空文件'
    }
  },
  data() {
    return {
      headers: {},
      action: '',
      data: {},
      multiple: false,
      showFileList: true,
      autoUpload: false,
      buttonText: '选择文件'
    };
  },
  methods: {
    handleClear() {
      this.$refs.upload.clearFiles();
    },
    handleDragAndDrop(e) {
      if (e.type === 'dragover') {
        e.preventDefault();
      } else if (e.type === 'drop') {
        e.preventDefault();

        const files = e.dataTransfer.files;

        for (let i = 0; i < files.length; i++) {
          const file = files.item(i);
          const xhr = new XMLHttpRequest();
          const formData = new FormData();

          formData.append('file', file);

          xhr.upload.addEventListener('progress', (e) => {
            if (e.lengthComputable) {
              const percent = Math.round((e.loaded / e.total) * 100);

              Vue.set(file, 'percent', percent);
            }
          });

          xhr.addEventListener('load', () => {
            const response = JSON.parse(xhr.responseText);
            Vue.set(file, 'url', response.data.url);
          });

          xhr.open('POST', this.action, true);
          xhr.setRequestHeader('Authorization', 'Bearer token');
          xhr.send(formData);
        }
      }
    }
  }
};
</script>
  1. 在使用组件的地方,我们可以如下方式渲染:
<template>
  <my-upload
    action="/upload"
    :before-upload="beforeUpload"
    :on-progress="handleProgress"
    :on-success="handleSuccess"
    :on-error="handleError"
    :show-clear-button="true"
    :clear-button-text="'清空记录'">
    <div class="my-upload-header">
      <span>上传文件</span>
    </div>
    <div class="my-upload-content">
      <el-button>选择文件</el-button>
    </div>
  </my-upload>
</template>

<script>
import MyUpload from '@/components/MyUpload.vue';

export default {
  components: { MyUpload },
  methods: {
    beforeUpload(file) {
      console.log('before upload', file);
    },
    handleProgress(event, file, fileList) {
      console.log('uploading', file, fileList);
    },
    handleSuccess(response, file, fileList) {
      console.log('upload success', response, file, fileList);
    },
    handleError(error, file, fileList) {
      console.log('upload error', error, file, fileList);
    }
  }
};
</script>

以上就是“基于element-ui组件手动实现单选和上传功能”的完整攻略。

本文标题为:基于element-ui组件手动实现单选和上传功能