基于微信小程序的场景解决

场景-loading效果

场景描述

  • 为网络请求和渲染提供加载效果,提高用户体验。
  • 简易加载要求。
    • 实现遮罩层。
    • 禁止滚动穿透。
    • 自定义加载提示信息。
    • 当数据请求开始,loading显示。
    • 当数据更新+渲染完成,loading隐藏。

技术背景

  • 微信小程序原生开发。
  • 自定义组件开发。
    • 4个文件。
    • json(配置)+wxml(结构)+wxss(样式)+js(业务)。
  • loading的设计
    • 全屏覆盖,半透明背景,禁止底层操作,禁止滚动穿透。
    • 加载动画。
    • 加载提示信息。
  • setData
    • 第二个参数为回调,当setData引起的界面更新渲染完成后的回调函数。

方案解决

创建组件

  • 配置设置
    • json中进行自定义组件声明。
    • "component":true
  • 结构
vue 复制代码
<!--component/loading.wxml-->
<view class="loading-container" wx:if="{{visible}}" catchtouchmove="true">
  <view class="loading-content-container">
    <view class="loading-spinner iconfont icon-loading"></view>
    <text class="loading-text">{{text}}</text>
  </view>
</view>
  • 样式
css 复制代码
/* component/loading.wxss */
/* 遮罩层:全屏覆盖,半透明背景,禁止底层操作 */
.loading-container {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.6); /* 半透明黑色遮罩 */
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-content-container {
  width: 500rpx;
  height: 300rpx;
  box-sizing: border-box;
  /* background-color: rgba(98, 96, 96, 0.8); */
  border-radius: 12rpx;
  padding: 40rpx 60rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 60rpx;
}

.loading-spinner {
  width: 70rpx;
  height: 70rpx;
  border: 6rpx solid #eee;
  border-top-color: #0495aa; /* 圆环进度色(主题色,与项目配色一致) */
  border-radius: 50%; /* 圆形 */
  animation: spin 1s linear infinite; /* 旋转动画:1秒一圈,无限循环 */
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

.loading-text {
  font-size: 33rpx;
  color: #ffff;
  font-family: 'Source Han Sans CN';
}
  • 业务
    • 内部自行管理显示状态,根据visible变量+wx:if指令。
    • 向外部主体提供loading组件的显示和隐藏方法。
      • 方法设置visible来控制loading的显示。
    • 内部禁止滚动穿透,通过catchtouchmove="true"。
      • 相当于preventDefault,阻止页面滚动。在手指滑动时不能滚动。
javascript 复制代码
// component/loading.js
Component({
  properties: {},

  data: {
    visible: false,
    text: '加载中...'
  },

  methods: {
    show(text = '加载中...') {
      this.setData({
        visible: true,
        text
      });
    },
    hide() {
      this.setData({
        visible: false
      });
    }
  }
});

使用组件

  • 配置设置
    • 在当前页面的json中进行引用声明。提供自定义组件的标签名和对应的自定义组件文件路径。
    • "usingComponent":{...}
  • 获取组件实例
    • 结构中使用。
    • 业务中获取实例。this.loadingComponent = this.selectComponent('#loadingComponent');
    • loading的隐藏时机
      • 在数据更新+渲染完成后隐藏。
      • setData的回调。
        • 注意隐藏不要在请求的finally中,否则还是会看不到loading。可以在catch串行中调用。
      • 若还是有冲突,考虑使用setTimeout,预估时间,手动设定隐藏时机。

参考资料

场景-小程序的图片处理

场景描述

  • 背景图片的处理
    • 小程序中wxss不支持设置背景图片。
  • 图片填充
  • 图片圆角

技术背景

  • image的mode属性。
  • CSS规则。

方案解决

背景图片

  • base64
    • 将图片转为base64,然后在业务中用变量存储,在结构中用内联样式设置背景图片。
  • 网路链接。
  • CSS样式手动调制。
  • image设置
    • 填充容器。
    • 背景上层的元素通过绝对定位展示。

图片填充

  • 对于标题类背景图片,不要求保持比例,需要能容纳标题文本。
    • 设置父元素的高度。
    • image设置width和height为100%。
    • image的mode设置为widthFix。

图片圆角

  • 图片容器设置border-radius,同时设置overflow:hidden实现圆角。
  • 图片image设置width和height为100%。

参考文献

场景-小程序首页的导航栏自定义左侧图标

场景描述

  • 小程序首页的导航栏中需要自定义胶囊体所在行的左侧图标。
    • 且要考虑到居中效果,即要获取胶囊体的所在行的样式。

技术背景

  • 结构
    • 导航栏中从上到下为顶部状态栏+胶囊体所在行。
  • 系统API。

方案解决

  • 获取胶囊体所在行的样式。
    • 获取系统样式
      • const menu = wx.getMenuButtonBoundingClientRect()
      • const systemInfo = wx.getSystemInfoSync()
    • 计算状态栏的样式
      • statusWidth = systemInfo.windowWidth
      • statusHeight = systemInfo.statusBarHeight,
    • 计算胶囊区所在行的样式,方便居中
      • buttonWidth = statusWidth
      • buttonHeight = 2*(胶囊区.top - 状态栏.height)+胶囊区.height=2 * (menu.top - statusHeight) + menu.height
  • 注意计算得到的是纯数值,需要加上尺度单位,如px。
    *

参考文献

场景-单行文本省略号未生效

场景描述

  • 在给列表项设置其中的标题为允许省略号,不换行。
    • 但是没有生效。
    • 而列表项中设置了flex布局。

技术背景

  • 省略号的样式规则
    • width/max-width;
    • white-space: nowrap;
    • overflow: hidden;
    • text-overflow: ellipsis;
  • flex布局

方案解决

  • 生效条件。需要能触发内容溢出。
    • 当display为flex,flex会改变元素的宽度计算逻辑,text-overflow: ellipsis 所需的 "内容溢出" 条件不满足,不会生效。
    • 需要有明确的最大宽度或宽度。
      • 如max-width: 100%;

参考文献

场景-按钮背景图片

场景描述

  • 给按钮设置了内联样式,基于base64码设置了背景图片,但是视觉效果显示拉伸。
    • 此外背景图片顶点处有锯齿问题,不光滑。
      • 该背景图片已经设置好圆角效果。
      • 按钮容器已设置了右对齐。align-self: flex-end;
  • 整体结构
vue 复制代码
          <view class="item-info-container width">
            <view class="item-title">{{item.title}}</view>
            <view class="item-btn-container width">
              <button
                class="item-btn screen-btn"
                bindtap="onScreenTap"
                data-id="{{item.id}}"
                style="background-image:url('{{images2Base64.projectionView}}')"
              ></button>
            </view>
          </view>

技术背景

  • CSS
    • 背景图片
    • base64转码。
    • width:fit-content;
      • CSS3新增属性。指定元素的宽度或高度根据内容自动调整,允许元素根据内容的大小来扩展或收缩。
  • 微信小程序
    • 结构规则
    • 样式规则

方案解决

  • 针对背景图片的拉伸
    • 需要等比例缩放背景图片。
    • background-size:contain;属性。尽可能缩放背景图片并保持图像的宽高比例。若有空白区域,会显示background-color设置的背景颜色。
  • 针对顶点的锯齿问题
    • 这是由于item-btn-container外层容器没有设置圆角,导致顶点处出现类似锯齿效果。
  • 针对设置了外层容器的border-radius,按钮左侧顶点仍有类似锯齿问题
    • 这是由于view为块元素,默认占满一行的宽度,按钮未能填满外层容器,需要设置外层容器为width:fit-content;,容器和按钮宽高适配。

参考文献

场景-富文本中图片预览实现

场景描述

  • 后端返回了富文本数据,里面包含了文本和图片,现在小程序中需要实现图片预览效果。

技术背景

  • 微信小程序的图片预览
    • wx.previewImage
    • 可接收base64。
  • 微信小程序的事件系统
  • 富文本
  • 正则化
  • 后端响应的数据结构
    • content属性。包含富文本数据。
    • contentImages属性。包含图片数组。
      • 数组元素。包含imageUrl。

方案解决

  • 针对图片预览的目标
    • 1、富文本数据进行文本和图片分离,解析出文本节点和图片节点。
    • 2、获取图片节点中的属性数据,封装到业务实例中。使用索引进行辅助定位。
    • 3、在结构中遍历文本节点和图片节点数据,构建文本节点和图片节点,对图片节点绑定预览业务函数。
  • 针对富文本数据分离文本和图片
    • data中创建三个数组
      • contentImages:[],存储所有图片的URL,用于预览。
      • processedContent:[],存储处理后的内容节点数组,包含文本和图片。用来在结构中遍历。
      • processedImageSrcs:[],存储处理后的图片base64数组。
    • request请求富文本数据。
    • 获取contentImages数组。
      • this.setData
    • 处理contentImages中图片,返回base64数组。processContentImages工具函数。
      • 根据contentImages元素的url,构建promise数组,发起请求。
javascript 复制代码
  processContentImages(contentImages) {
    if (!contentImages || !Array.isArray(contentImages)) {
      return Promise.resolve([]);
    }

    const imageUrls = contentImages.map(item => item.imageUrl).filter(Boolean);

    const promises = imageUrls.map(url => {
      if (!url) {
        return Promise.resolve('');
      }

      return request({
        url: url,
        method: 'GET',
        responseType: 'arraybuffer'
      })
        .then(res => {
          const base64 = wx.arrayBufferToBase64(res);
          const mimeType = 'image/jpeg';
          const dataUrl = `data:${mimeType};base64,${base64}`;
          return dataUrl;
        })
        .catch(err => {
          console.error('处理 contentImages 图片失败,URL:', url, err);
          return url; // 失败时返回原始URL
        });
    });

    return Promise.all(promises);
  },
复制代码
- 基于返回的base64的图片数组,开始解析节点数组,分离文本和图片节点。
    * 使用正则表达式分隔文本和图片,提取图片属性信息。核心是捕获当前src值。
    * 使用索引记录,方便点击预览时定位图片位置。
javascript 复制代码
  parseContentToNodes(html, processedImageSrcs, originalImageUrls) {
    const nodes = [];
    let tempHtml = html;
    let imgIndex = 0;

    // 用于存储图片信息
    const imageList = [];

    // 使用正则表达式分割文本和图片
    const imgRegex = /<img[^>]*src="([^"]*)"[^>]*>/gi;
    let lastIndex = 0;
    let match;

    while ((match = imgRegex.exec(html)) !== null) {
      // 添加图片前的文本
      if (match.index > lastIndex) {
        const textContent = html.substring(lastIndex, match.index);
        if (textContent.trim()) {
          nodes.push({
            type: 'text',
            content: textContent
          });
        }
      }

      // 添加图片节点
      const currentIndex = imgIndex;
      const originalSrc = match[1];
      const processedSrc = processedImageSrcs[currentIndex] || originalSrc;

      nodes.push({
        type: 'image',
        src: processedSrc,
        originalSrc: originalSrc,
        index: currentIndex
      });

      imageList.push(originalSrc);
      imgIndex++;
      lastIndex = imgRegex.lastIndex;
    }

    // 添加最后的文本
    if (lastIndex < html.length) {
      const textContent = html.substring(lastIndex);
      if (textContent.trim()) {
        nodes.push({
          type: 'text',
          content: textContent
        });
      }
    }

    return {
      nodes: nodes,
      imageList: imageList
    };
  },
复制代码
- 结构中遍历内容节点数组,结合wx:if区分文本节点和图片节点。
    * 绑定点击事件,调用预览函数,传递索引值,便于定位目标图片的数组位置。
vue 复制代码
    <view
      class="content-body-container"
      wx:if="{{processedContent.length > 0}}"
    >
      <block wx:for="{{processedContent}}" wx:key="index">
        <!-- 文本节点 -->
        <rich-text
          wx:if="{{item.type === 'text'}}"
          nodes="{{item.content}}"
          class="text-node"
        ></rich-text>

        <!-- 图片节点 -->
        <view
          wx:if="{{item.type === 'image'}}"
          class="image-container"
          style="margin-top: 30rpx"
        >
          <image
            src="{{item.src}}"
            mode="widthFix"
            class="content-image"
            data-index="{{item.index}}"
            bindtap="onImageTap"
            style="width: 100%; height: 100%"
          ></image>
        </view>
      </block>
    </view>
复制代码
- 预览函数
javascript 复制代码
  onImageTap(e) {
    const { index } = e.currentTarget.dataset;
    const { processedImageSrcs } = this.data;

    console.log('点击图片索引:', index);

    if (processedImageSrcs && processedImageSrcs.length > 0) {
      const imageUrls = processedImageSrcs;
      if (imageUrls.length > 0 && index >= 0 && index < imageUrls.length) {
        wx.previewImage({
          current: imageUrls[index],
          // urls: [imageUrls[index]] // 单张
          urls: imageUrls // 查看全部,可能有性能问题
        });
      }
    }
  },

参考文献

场景-背景色显示异样

场景描述

  • 页面对顶层容器container使用了渐变背景色,但不同页面,在10%位置背景色效果不一致。
    • linear-gradient(to bottom, #29c3b7 0%, #d7f4e0 10%, #ffffff 100%);
    • 页面结构是
      <view class="container"><scroll-view></scroll-view></view>

技术背景

  • CSS的渐变背景色

方案解决

  • 针对不同页面的视口中10%位置处背景色不一致问题
    • 这是由于scroll-view没有设置height,当列表项较多时,整个container的高度也会被撑开,导致视口10%位置的背景色发生了改变。
    • 给scroll-view设置height即可。

参考文献

其他

结构规则

  • view标签和block标签
    • v-for循环时
      • view会参与循环。 是一个组件,会在页面上做渲染。
      • block不会参与循环。仅仅是一个包装元素,只接受控制属性,不会在页面中做任何渲染。
        • 参考template。
  • 事件系统的dataset
    • 组件节点中可添加一些自定义数据。在WXML中,自定义数据以data-开头,多个单词由连字符-连接,会自动转为驼峰写法。

样式规则

  • rpx使用。
  • box-sizing盒模型
    • 小程序中默认盒子模型为content-box。
      • 即当前元素总宽度=内容宽度width+padding+border。
    • 设置当前view的盒子模型为border-box。
      • 表示当前view的总宽度=内容宽度width+padding+border。不包括margin,且这种盒模型不能继承给子元素。
      • 若设置当前元素的左右边距,结合calc。如box-sizing: border-box; width: calc(100% - 40rpx);
        • 注意calc(100% - 40rpx);中写好空格,不能是calc(100%-40rpx);
        • - 前后没有空格,浏览器无法解析,导致 width 被当作 100% 处理(等于父容器宽度)。
相关推荐
喵喵侠w2 小时前
uni-app微信小程序相机组件二次拍照白屏问题的排查与解决
前端·数码相机·微信小程序·小程序·uni-app
G佳伟2 小时前
微信小程序实现长按复制选中文字的效果
微信小程序·小程序·notepad++
汤姆yu3 小时前
基于微信小程序的特色农产品交易系统
微信小程序·小程序
毕设源码-赖学姐3 小时前
【开题答辩全过程】以 赣农乐微信小程序为例,包含答辩的问题和答案
微信小程序·小程序
一 乐6 小时前
远程在线诊疗|在线诊疗|基于java和小程序的在线诊疗系统小程序设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·小程序
2501_915918416 小时前
HTTP和HTTPS工作原理、安全漏洞及防护措施全面解析
android·http·ios·小程序·https·uni-app·iphone
2501_916007477 小时前
如何在 Windows 电脑上调试 iOS 设备上的 Safari?完整方案与实战经验分享
android·windows·ios·小程序·uni-app·iphone·safari
2501_915918417 小时前
uni-app iOS日志管理实战,从调试控制台到系统日志的全链路采集与分析指南
android·ios·小程序·https·uni-app·iphone·webview
毕设源码-钟学长8 小时前
【开题答辩全过程】以 二手小型电子产品商城小程序为例,包含答辩的问题和答案
小程序