场景-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,预估时间,手动设定隐藏时机。
参考资料
场景-小程序的图片处理
场景描述
技术背景
方案解决
背景图片
- base64
- 将图片转为base64,然后在业务中用变量存储,在结构中用内联样式设置背景图片。
- 网路链接。
- CSS样式手动调制。
- image设置
图片填充
- 对于标题类背景图片,不要求保持比例,需要能容纳标题文本。
- 设置父元素的高度。
- image设置width和height为100%。
- image的mode设置为widthFix。
图片圆角
- 图片容器设置border-radius,同时设置overflow:hidden实现圆角。
- 图片image设置width和height为100%。
参考文献
场景-小程序首页的导航栏自定义左侧图标
场景描述
- 小程序首页的导航栏中需要自定义胶囊体所在行的左侧图标。
- 且要考虑到居中效果,即要获取胶囊体的所在行的样式。
技术背景
方案解决
- 获取胶囊体所在行的样式。
- 获取系统样式
- 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。
*
参考文献
场景-单行文本省略号未生效
场景描述
技术背景
- 省略号的样式规则
- width/max-width;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- flex布局
方案解决
- 生效条件。需要能触发内容溢出。
- 当display为flex,flex会改变元素的宽度计算逻辑,text-overflow: ellipsis 所需的 "内容溢出" 条件不满足,不会生效。
- 需要有明确的最大宽度或宽度。
参考文献
场景-按钮背景图片
场景描述
- 给按钮设置了内联样式,基于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属性。包含图片数组。
方案解决
- 针对图片预览的目标
- 1、富文本数据进行文本和图片分离,解析出文本节点和图片节点。
- 2、获取图片节点中的属性数据,封装到业务实例中。使用索引进行辅助定位。
- 3、在结构中遍历文本节点和图片节点数据,构建文本节点和图片节点,对图片节点绑定预览业务函数。
- 针对富文本数据分离文本和图片
- data中创建三个数组
- contentImages:[],存储所有图片的URL,用于预览。
- processedContent:[],存储处理后的内容节点数组,包含文本和图片。用来在结构中遍历。
- processedImageSrcs:[],存储处理后的图片base64数组。
- request请求富文本数据。
- 获取contentImages数组。
- 处理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>
技术背景
方案解决
- 针对不同页面的视口中10%位置处背景色不一致问题
- 这是由于scroll-view没有设置height,当列表项较多时,整个container的高度也会被撑开,导致视口10%位置的背景色发生了改变。
- 给scroll-view设置height即可。
参考文献
其他
结构规则
- view标签和block标签
- v-for循环时
- view会参与循环。 是一个组件,会在页面上做渲染。
- block不会参与循环。仅仅是一个包装元素,只接受控制属性,不会在页面中做任何渲染。
- 事件系统的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% 处理(等于父容器宽度)。