【sgMobileUploadTypeSelect】自定义组件:从底部弹出选择上传图片文件的方式【1、上传本地文件,2、拍摄上传】

sgMobileUploadTypeSelect.vue

html 复制代码
<template>
  <!-- 选择是直接上传手机文件还是拍摄上传 -->
  <div :class="$options.name" :show="visible">
    <div class="bg" @click="visible = false"></div>
    <div class="container">
      <div class="close" @click="visible = false">
        <i class="el-icon-close" />
      </div>

      <div class="upload-types">
        <div class="item" @click="(uploadBtn || {}).click()">
          <i class="el-icon-upload" />
        </div>
        <div class="item" @click="scan">
          <i class="el-icon-camera" />
        </div>
      </div>
    </div>
    <sgUploadCameraImage ref="sgUploadCameraImage" @change="getUploadFiles_scan" />
    <el-upload
      ref="upload"
      :accept="``"
      :action="`#`"
      :auto-upload="false"
      :multiple="true"
      :on-change="getUploadFiles_upload"
      :show-file-list="false"
      :dragenter="isDragenter"
      :drag="false"
    />
    <!-- 如果drag=true,accept必须为具体的格式,否则无法监听on-change -->
  </div>
</template>
<script>
import sgUploadCameraImage from "@/vue/components/admin/sgUploadCameraImage";

export default {
  name: `sgMobileUploadTypeSelect`,
  components: { sgUploadCameraImage },
  data() {
    return {
      visible: false,
      form: {},
      change: null,

      uploadBtn: null, //上传触发按钮
      isDragenter: false, //是否拖拽进入
    };
  },

  props: [`value`, `data`],

  watch: {
    value: {
      handler(d) {
        this.visible = d;
      },
      deep: true,
      immediate: true,
    },
    visible(d) {
      this.$emit("input", d);
    },
    data: {
      handler(newValue, oldValue) {
        //console.log(`深度监听${this.$options.name}:`, newValue, oldValue);
        if (Object.keys(newValue || {}).length) {
          this.form = this.$g.deepCopy(newValue);
          this.$g.cF2CP(`disabled`, this);
          this.$g.cF2CP(`change`, this);
        }
      },
      deep: true, //深度监听
      immediate: true, //立即执行
    },
  },
  mounted() {
    this.uploadBtn = this.$refs.upload.$children[0].$refs.input;
  },

  methods: {
    // -------------------------------------
    // 唤起摄像头拍照扫描上传
    scan(d) {
      this.$refs.sgUploadCameraImage.scan();
    },
    // 获取拍照图片文件
    getUploadFiles_scan(file) {
      this.$emit(`change`, file);
      this.change && this.change(file);
      this.visible = false;
    },
    // -------------------------------------
    // 获取上传文件----------------------------------------
    getUploadFiles_upload(file) {
      file = file.raw;
      this.$emit(`change`, file);
      this.change && this.change(file);
      this.visible = false;
    },
  },
};
</script>
<style lang="scss" scoped>
.sgMobileUploadTypeSelect {
  position: fixed;
  width: 100vw;
  height: 100vh;
  left: 0;
  bottom: 0;
  pointer-events: none;
  transition: 0.2s;
  z-index: 1;
  .bg {
    width: 100%;
    height: 100%;
    background-color: #00000099;
    opacity: 0;
    transition: 0.2s;
  }
  .container {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    transition: 0.2s;
    position: absolute;
    transform: translateY(100%);
    width: 100%;
    left: 0;
    bottom: 0;
    background-color: white;
    height: 200px;
    border-radius: 16px 16px 0 0;
    box-shadow: 0 11px 33px 0 #00000011;
    box-sizing: border-box;
    padding: 20px;
    //   padding-top: 60px;
    .close {
      position: absolute;
      right: 20px;
      top: 20px;
      z-index: 1;
      color: #666;
      i {
        font-size: 20px;
      }
    }

    .upload-types {
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: space-evenly;
      .item {
        width: 100px;
        height: 100px;
        /*禁止选中文本*/
        user-select: none;
        background-color: #eff2f7;
        color: #8896b3;
        font-size: 40px;
        display: flex;
        justify-content: center;
        align-items: center;
        border-radius: 8px;
        box-sizing: border-box;
        &:active {
          color: black;
          background-color: #c6d1de;
        }
      }
    }
  }

  &[show] {
    pointer-events: auto;
    .bg {
      opacity: 1;
    }
    .container {
      transform: translateY(0%);
    }
  }
}
</style>

demo

html 复制代码
<!-- 选择上传方式 -->
<sgMobileUploadTypeSelect
  :data="data_sgMobileUploadTypeSelect"
  v-model="show_sgMobileUploadTypeSelect"
/>


import sgMobileUploadTypeSelect from "@/vue/components/admin/sgMobileUploadTypeSelect";


rw_sgMobileUploadTypeSelect({ w = true, d = {} } = {}) {
  this.data_sgMobileUploadTypeSelect = this.$g.deepCopy(d);
  this.data_sgMobileUploadTypeSelect.disabled = !w;
  this.show_sgMobileUploadTypeSelect = true;
},



<div
  class="upload-btn"
  @click="rw_sgMobileUploadTypeSelect({ d: { change: getUploadFiles } })"
>
  <i class="el-icon-camera" />
</div>
相关推荐
牛奶15 小时前
AI双层代码治理:Monorepo × Harness Engineering
前端·aigc·ai编程
蜡台15 小时前
H5使用Chrome 权限问题
前端·javascript·chrome
掘金一周15 小时前
你们觉得房贷多少,没有压力 | 沸点周刊 4.30
前端·人工智能·后端
大貔貅喝啤酒15 小时前
接口测试_Postman(详细版)
javascript·测试工具·node.js·自动化·postman
小小码农Come on16 小时前
QML访问子项内容
前端·javascript·html
桜吹雪16 小时前
Langchain.js官方文档:构建具备按需加载技能的 SQL 助手
javascript·人工智能·node.js
han_16 小时前
一篇看懂国内外主流大模型:GPT、Claude、Gemini、DeepSeek、通义千问有什么区别?
前端·人工智能·llm
一行代码一行诗++16 小时前
注释是什么和注释该怎么写(C语言)
java·前端·javascript
涂兵兵_青石疏影16 小时前
beginPath-vs-save详解
前端
陈振wx:zchen200816 小时前
前端-面试题-JavaScript
javascript·前端面试题