支付宝小程序 | 上传图片组件(添加默认样式以及自定义上传样式)

支付宝,程序,上传,图片,组件,添加,默认,样式,以及,自定义 · 浏览次数 : 81

小编点评

```typescript import { useComponents, useMemo } from 'antd'; import { uploadImage } from '/components/upload-image/upload-image'; import './upload-images.less.ts'; // 定义组件 const Tip1 = useMemo(() => 添加图片(非必传), ['tip1']); const Tip2 = useMemo(() => 最多可以添加{{imgCount}}张图片, ['tip2']); // 获取默认标题 const defaultTitle = useMemo(() => '上传图片', ['defaultTitle']); // handleUpload函数 const handleUpload = (file, fileList) => { this.setData({ imgValue: fileList, deleteImage: file }); }; // handleDelete函数 const handleDelete = (file, fileList) => { const arr = [] let { deleteImage } = this.data arr.push(file) const newImage = deleteImage.concat(arr) this.setData({ imgValue: fileList, deleteImage: newImage }); }; // 生成内容时带简单的排版 const content = useMemo(() => { // 定义排版 const tip1 = ; const tip2 = ; // 使用默认标题 const defaultTitle = ; // 生成内容时带排版 return (
{tip1} {tip2}
{/* 加载图标 */}
{defaultTitle}
); }, [defaultTitle]); // 使用memo缓存默认标题 export default content; ```

正文

使用my.uploadFile、 my.chooseImage 的方式实现图片上传

注意: 使用该方式上传文件,后端也需要参照官方文档进行修改

https://opendocs.alipay.com/mini/api/kmq4hc

一、展示效果

默认上传

demo4.gif

自定义上传

demo5.gif

二、上代码

(一)、上传组件

image.png

<view class="custom-upload-container">
  <view a:for="{{imageUrl}}" class="custom-upload images-show">
    <view class="clear" catchTap="handleDelete" data-url="{{item}}">
      <am-icon type="CloseCircleFill" color="#333333" size="x-small" />
    </view>
    <view a:if="{{item.status == 'fail' ? true : false}}" class="loading">
      <loading type="spin" size="small" text="上传中..." loading="{{true}}" />
    </view>
    <image
      mode="aspectFill"
      src={{item}}
      catchTap="hanldeImageLook"
      data-url="{{item}}"
      data-index="{{index}}"
    />
  </view>

  <view
    a:if="{{imageUrl.length < maxCount && imageUrl.length > 0 ? true:false}}"
    class="custom-upload "
  >
    <view class="add" catchTap="handleSelectImage">
      <am-icon type="AddOutline" color="#333333" size="small" />
    </view>
  </view>

  <view catchTap="handleSelectImage" style="width:100%">
    <slot a:if="{{ imageUrl.length == 0 ?true:false }}">
      <view class="default-upload">
        <am-icon type="AddOutline" color="#333333" size="small" />
      </view>
    </slot>
  </view>
</view>

upload-image.ts

Component({
  mixins: [],
  data: {
    imageUrl: [],
    maxCount: 1,
    action: '', //上传的url地址
  },
  props: {
    maxCount: 1,
    onUpload: (image, imageArr) => {},
    onDelete: (image, imageArr) => {},
    value: [],
    action: '',
  },
  didMount() {
    const maxCount = this.props?.maxCount || 1
    const value = this.props?.value || []
    const action =
      this.props?.action ||  'xxxxxxxx'
    this.setData({
      maxCount,
      imageUrl: value,
      action,
    })
  },
  didUpdate() {},
  didUnmount() {},
  methods: {
    handleSelectImage() {
      const { imageUrl, maxCount } = this.data
      if (imageUrl.length == maxCount) {
        my.showToast({
          content: `最多上传${maxCount}张图片`,
        })
        return
      }
      my.chooseImage({
        sourceType: ['camera', 'album'],
        count: 1,
        success: (res) => {
          const path = res.apFilePaths[0]
          const DeviceId = my.getStorageSync({ key: 'DeviceId' }).data
          const ACCESS_TOKEN = my.getStorageSync({ key: '__AT__' }).data
          const { account } = my.getStorageSync({ key: 'userinfo' }).data as any
          const { action } = this.data
          const SYSTEM_ID =
            (my.getStorageSync({ key: 'SyStemId' }).data as string)
          my.uploadFile({
            url: action,
            fileType: 'image',
            fileName: 'file',
            filePath: path,
            name: 'file',
            //请求头信息
            header: {
              DeviceId: DeviceId,
              uname: account,
              System: SYSTEM_ID,
            },
            success: (res) => {
              const value = JSON.parse(res.data)
              if (value?.code == 200) {
                const { imageUrl } = this.data
                const newImageUrl = imageUrl.concat(value?.data)
                this.setData({
                  imageUrl: newImageUrl,
                })
                this.props.onUpload(value?.data, newImageUrl)
              } else {
                my.showToast({
                  content: value?.msg || '上传失败',
                })
              }
            },
            fail: (err) => {
              my.showToast({
                content: '上传失败',
              })
              const { imageUrl } = this.data
              const newImageUrl = imageUrl.concat([])
              this.setData({
                imageUrl: newImageUrl,
                status: 'fail',
              })
            },
          })
        },
      })
    },
    handleDelete(e) {
      const { url } = e.currentTarget.dataset
      const { imageUrl } = this.data
      const newData = imageUrl.filter((i) => i !== url)
      this.setData({
        imageUrl: newData,
      })
      this.props.onDelete(index, newData)
    },
    hanldeImageLook(e) {
      const { imageUrl } = this.data
      const { index } = e.currentTarget.dataset
      my.previewImage({
        current: index, // 当前显示图片
        urls: imageUrl,
        success: (res) => {
          console.log('debug----res', res)
        },
        fail: (error) => {
          console.log('debug----error', error)
        },
      })
    },
  },
})

upload-image.less

.custom-upload-container {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  background: #ffffff;
  padding: 16px;
  border-radius: 8px;
  .custom-upload,
  .images-show {
    width: 80px;
    height: 80px;
    background: #ffffff;
    border: 1px dashed #979797;
    border-radius: 6px;
    display: flex;
    justify-content: center;
    align-items: center;
    position: relative;
    margin-right: 30px;
    .add {
      position: absolute;
      margin: auto;
    }
    .clear {
      position: absolute;
      top: 0;
      right: 0;
      margin-top: -6px;
      margin-right: -6px;
    }
    > image {
      width: 100%;
      height: 100%;
      border-radius: 4px;
      background: #fff;
    }
    .loading {
      position: absolute;
      margin: auto;
      width: 100%;
      height: 100%;
      background-color: rgba(0, 0, 0, 0.5);
      .amd-loading-spin-container {
        width: 100%;
        height: 100%;
      }
      .amd-loading-spin-text {
        color: #ffff;
      }
    }
  }
  .custom-upload:nth-of-type(3n) {
    margin-right: 0px;
  }
  .images-show {
    border: none;
  }

  .default-upload {
    width: 100%;
    height: 80px;
    border-radius: 4px;
    border: 1px dashed #979797;
    display: flex;
    justify-content: center;
    align-items: center;
    background: #ffffff;
  }
}

upload-image.json

    {
      "component": true,
      "usingComponents": {
        "am-icon": "antd-mini/es/Icon/index",
        "loading": "antd-mini/es/Loading/index"
      }
    }

(二)、在页面中引用组件

pageX.axml

//自定义上传样式
<upload-image
  maxCount="{{imgCount}}"
  value="{{imgValue}}"
  onUpload="handleUpload"
  onDelete="handleDelete"
>
  <view class="uplload-images">
    <text class="tip1">添加图片(非必传)</text>
    <text class="tip2">最多可以添加{{imgCount}}张图片</text>
  </view>
</upload-image>

//默认样式
<upload-image
  maxCount="{{imgCount}}"
  value="{{imgValue}}"
  onUpload="handleUpload"
  onDelete="handleDelete"
>
</upload-image>

pageX.less

.uplload-images {
  width: 100%;
  height: 80px;
  background: #ffffff;
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  .tip1 {
    font-size: 14px;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #333333;
    line-height: 20px;
  }
  .tip2 {
    font-size: 12px;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #999999;
    line-height: 16px;
    margin-top: 8px;
  }
}

pageX.json

{
  "defaultTitle": "上传图片",
  "usingComponents": {
       "upload-image":"/components/upload-image/upload-image" // 组件的路径
  }
}

pageX.ts

  data:{
    imgValue:[],
    imgCount:3,
   },
   handleUpload(file, fileList) {
      this.setData({
        imgValue: fileList,
      })
   },
    handleDelete(file, fileList) {
    const arr = []
    let { deleteImage } = this.data
    arr.push(file)
    const newImage = deleteImage.concat(arr)
    this.setData({
      imgValue: fileList,
      deleteImage: newImage,
    })
  },

与支付宝小程序 | 上传图片组件(添加默认样式以及自定义上传样式)相似的内容:

支付宝小程序 | 上传图片组件(添加默认样式以及自定义上传样式)

人们害怕他们不理解的东西。 People are afraid of what they don't understand.

支付宝小程序 | 下拉刷新、自动刷新、上拉加载

下拉刷新 (一)onPullDownRefresh方法 模拟器效果展示 实现如下 1、配置下拉选项 demo.json { "pullRefresh": true } 2、定义下拉方法 demo.js onPullDownRefresh() { //做相应的逻辑处理 }, 3、停止下拉 在加载完数据

小程序中使用 lottie 动画 | 踩坑经验分享

最近被拉去支援紧急需求(赶在五一节假日前上线的,双休需要加班),参与到项目中才知道,开发的项目是微信小程序技术栈的。由于是临时支援,笔者也很久没开发过微信小程序了,所以挑选了相对独立,业务属性相对轻薄的模块参与。 其中有个营销活动(领红包)的弹窗动画就要用到 lottie 动画。 本文就

支付宝小程序 | 自定义标题导航栏

效果 一 、page.json "transparentTitle": "always" 二、page.axml

支付宝小程序 | 获取网络状态

追光者终将光芒万丈

基于uniapp+vue3自定义增强版table表格组件「兼容H5+小程序+App端」

vue3+uniapp多端自定义table组件|uniapp加强版综合表格组件 uv3-table:一款基于uniapp+vue3跨端自定义手机端增强版表格组件。支持固定表头/列、边框、斑马纹、单选/多选,自定义表头/表体插槽、左右固定列阴影高亮显示。支持编译兼容H5+小程序端+App端。 如下图:

uniapp+vue3聊天室|uni-app+vite4+uv-ui跨端仿微信app聊天语音/朋友圈

原创研发uniapp+vue3+pinia2跨三端仿微信app聊天模板Uniapp-Wechat。 uni-vue3-wchat基于uni-app+vue3+pinia2+uni-ui+uv-ui等技术跨端仿制微信App界面聊天项目,支持编译到H5+小程序端+App端。实现编辑框多行消息/emoj混

DevOps|1024程序员节怎么做?介绍下我的思路

1024,祝每个程序员小哥哥小姐姐节日快乐。 因为在研发效能部门,我支持过几次 1024 程序员节的活动,所以经常有朋友问我1024 程序员节怎么做,本篇就是简单介绍下我的思路,希望对你有用。 1024程序员节的由来 俄罗斯把每年第256(=2^8)天,即平年9月13日或闰年9月12日定为国际程序员

网易面试:SpringBoot如何开启虚拟线程?

虚拟线程(Virtual Thread)也称协程或纤程,是一种轻量级的线程实现,与传统的线程以及操作系统级别的线程(也称为平台线程)相比,它的创建开销更小、资源利用率更高,是 Java 并发编程领域的一项重要创新。 PS:虚拟线程正式发布于 Java 长期支持版(Long Term Suort,LT

uniapp微信小程序转支付宝小程序踩坑(持续更新)

首先第一个,真有被折磨到! // 微信正常使用,支付宝不行 // 以下两种 微信、支付宝都正常使用