微信小程序-组件开发

微信小程序提供了视图容器组件、基础内容组件、表单组件、操作反馈组件、导航组件、媒体组件、地图组件、画布组件等8类组件,包括了大部分UI需要用到的组件。

组件的通用属性

1.id属性

id属性为字符串类型(String),是组件的唯一标示,在同一页面中id属性必须保持唯一,不能重复。

id 用于定位:仅用于获取组件实例或CSS锚点,不要用于样式选择器(性能差)

2.class属性

class 属性为字符串类型(String),通过class属性来设置组件的样式类。该属性的值为样式类名称,该样式类的CSS样式定义在对应的WXSS文件中。如果与动态数据绑定相结合,组件的class也将具有动态变换的能力。

3.style属性

style属性为字符串类型(String),通过style属性可设置组件的内联样式。style属性值中可设置CSS的各种属性。如果与动态数据绑定相结合,组件的style也将具有动态变换的能力。

样式优先用 class:静态样式用 class,动态样式用 style

4. hidden 属性

hidden属性是一个逻辑值(Boolean),用来决定该组件是否显示。默认情况下,hidden属性的值为false,即组件为显示状态(不隐藏)。

隐藏用 hidden:频繁切换用 hidden,初始不显示用 wx:if

5.data-*属性

data-*属性可为任何类型,可用来为组件设置任意的自定义属性值。当组件上绑定的事件触发时,这些自定义属性将作为参数发送给事件处理函数,在事件处理函数中可通过传人参数对象的currentTarget.dataset方式来获取自定义属性的值。

html 复制代码
<!-- 传递多个数据 -->
<button 
  data-user-id="12345"
  data-user-name="张三"
  data-user-age="25"
  bindtap="handleUserInfo"
>
  传递用户信息
</button>

<!-- 支持驼峰命名(会自动转小写) -->
<view data-userName="李四" data-userAge="30" bindtap="handleData">
  测试驼峰命名
</view>
javascript 复制代码
Page({
  handleUserInfo(event) {
    // 通过 currentTarget.dataset 获取
    const userId = event.currentTarget.dataset.userId;    // "12345"
    const userName = event.currentTarget.dataset.userName; // "张三"
    const userAge = event.currentTarget.dataset.userAge;   // "25"
    
    console.log(userId, userName, userAge);
  },
  
  handleData(event) {
    // 驼峰命名会自动转小写
    console.log(event.currentTarget.dataset.username);    // "李四"
    console.log(event.currentTarget.dataset.userage);     // "30"
  }
});

注意事项:

  • 属性名中不能有大写字母,如需使用驼峰,实际会转为小写

  • 建议全部使用小写加短横线:data-user-name

数据传递用 data-*:简单数据传递优先使用 dataset

冒泡数据用 mark:需要多层级数据时使用 mark

6. bind* / catch* 事件绑定

用来为组件定义事件,bind和 catch的区别是,bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡。

html 复制代码
<!-- bind:事件会冒泡 -->
<view bindtap="parentTap">
  <button bindtap="childTap">冒泡事件</button>
</view>

<!-- catch:阻止冒泡 -->
<view bindtap="parentTap">
  <button catchtap="childTap">阻止冒泡</button>
</view>

<!-- 支持事件类型后缀 -->
<input bindinput="onInput" bindfocus="onFocus" bindblur="onBlur" />
<scroll-view bindscroll="onScroll" />

7. mut-bind:* 互斥绑定

同一节点上多个互斥绑定事件,只会触发其中一个。

html 复制代码
<!-- 点击时只会触发一个(通常是最外层的或特定规则) -->
<view mut-bind:tap="handleTap1" mut-bind:tap="handleTap2">
  互斥绑定测试
</view>

8. capture-bind:* / capture-catch:* 捕获阶段事件

执行顺序: 捕获阶段(从外到内)→ 目标阶段 → 冒泡阶段(从内到外

html 复制代码
<!-- 捕获阶段绑定(先于冒泡阶段执行) -->
<view capture-bind:tap="captureTap">
  <view bindtap="bubbleTap">点击测试</view>
</view>

<!-- 捕获阶段阻止事件传递 -->
<view capture-catch:tap="captureStopTap">
  <view bindtap="bubbleTap">不会触发bubbleTap</view>
</view>

9. mark:* 标记数据

data-* 类似,但 mark 数据会在冒泡时合并传递

html 复制代码
<view mark:parentId="p001" bindtap="parentTap">
  <button mark:childId="c001" bindtap="childTap">点击</button>
</view>
javascript 复制代码
Page({
  childTap(event) {
    // 可以同时获取父组件和子组件的 mark 数据
    console.log(event.mark.parentId); // "p001"
    console.log(event.mark.childId);  // "c001"
  },
  
  parentTap(event) {
    console.log(event.mark.parentId); // "p001"
    console.log(event.mark.childId);  // undefined(从子组件冒泡过来才有)
  }
});

mark 与 dataset 的区别:

  • dataset:只包含当前组件的 data-* 数据

  • mark:包含冒泡路径上所有组件的 mark:* 数据(会合并)

视图容器组件

视图容器组件包括view、scroll-view、swiper及swiper-item,主要用于控制视图样式与内容展现。

用于布局和结构组织的基础组件,它们负责承载其他组件、控制布局方式以及实现滚动、轮播等高级交互功能。

组件名 主要功能 适用场景
<view> 基础容器,类似div 普通布局、结构划分
<block> 逻辑容器,不渲染 批量渲染、条件判断
<scroll-view> 可滚动视图 长列表、横向滚动、滚动动画
<swiper> 轮播容器 图片轮播、卡片滑动、引导页
<movable-view> 可移动容器 拖拽排序、悬浮窗
<cover-view> 覆盖原生组件 地图、视频上叠加文本/按钮
<page-container> 页面级容器 弹窗、抽屉、半屏效果
<share-element> 共享元素动画 页面转场动画

1. <view> - 基础容器

最基础的视图容器,功能类似于 HTML 的 <div>,用于布局、分组和样式控制。

特殊属性:

  • hover-class:点击时的样式类(默认 none

  • hover-stop-propagation:阻止点击状态向父节点传递

  • hover-start-time:点击后多久出现点击态(单位ms)

  • hover-stay-time:点击态保持时间(单位ms)

html 复制代码
<view 
  hover-class="view-hover" 
  hover-start-time="50" 
  hover-stay-time="400"
  hover-stop-propagation="{{true}}"
>
  带点击反馈的视图
</view>

2. <block> - 逻辑容器

不渲染 任何节点的包装器,只用于逻辑控制(条件、循环)。不支持 classstyleid 等样式属性,因为它不会被渲染到DOM中。

html 复制代码
<!-- 条件渲染 -->
<block ="{{hasPermission}}">
  <view>管理员菜单1</view>
  <view>管理员菜单2</view>
</block>

<!-- 列表渲染 -->
<block ="{{userList}}" ="id">
  <view class="user-item">{{item.name}}</view>
  <view class="user-desc">{{item.desc}}</view>
</block>

<!-- 混合使用 -->
<block ="{{showSection}}">
  <block ="{{items}}" ="index">
    <view>{{item}}</view>
  </block>
</block>

3. <scroll-view> - 可滚动视图

实现区域滚动,支持横向、纵向滚动,常用于长列表、横向滑动菜单。

html 复制代码
<!-- 纵向滚动 -->
<scroll-view 
  scroll-y="{{true}}"
  style="height: 500rpx;"
  bindscrolltolower="loadMore"
  lower-threshold="50"
>
  <view ="{{100}}" ="index">列表项 {{index}}</view>
</scroll-view>

<!-- 横向滚动 -->
<scroll-view 
  scroll-x="{{true}}"
  class="horizontal-scroll"
  bindscroll="onScroll"
>
  <view class="scroll-item" ="{{banners}}" ="id">
    <image src="{{item.image}}" mode="widthFix" />
  </view>
</scroll-view>

<!-- 滚动到指定位置 -->
<scroll-view 
  scroll-y="{{true}}"
  scroll-into-view="item-{{currentIndex}}"
  scroll-with-animation="{{true}}"
>
  <view id="item-0">项目0</view>
  <view id="item-1">项目1</view>
  <view id="item-2">项目2</view>
</scroll-view>

常用属性:

属性 类型 说明
scroll-x Boolean 允许横向滚动
scroll-y Boolean 允许纵向滚动
scroll-top Number 设置竖向滚动条位置
scroll-left Number 设置横向滚动条位置
scroll-into-view String 滚动到指定id的元素
scroll-with-animation Boolean 滚动时使用动画
bindscrolltolower EventHandle 滚动到底部/右边触发
lower-threshold Number 距底部多远触发(默认50)
bindscroll EventHandle 滚动时触发

4. <swiper> - 轮播容器

实现触摸滑动轮播效果,常用于首页Banner、卡片轮播。

html 复制代码
<!-- 基础轮播 -->
<swiper 
  indicator-dots="{{true}}"
  autoplay="{{true}}"
  interval="3000"
  duration="500"
  circular="{{true}}"
  bindchange="onSwiperChange"
>
  <swiper-item ="{{banners}}" ="id">
    <image src="{{item.image}}" mode="aspectFill" class="banner-img" />
  </swiper-item>
</swiper>

<!-- 垂直轮播 -->
<swiper 
  vertical="{{true}}"
  indicator-dots="{{true}}"
  autoplay="{{true}}"
  style="height: 200rpx;"
>
  <swiper-item>
    <view class="notice-item">公告1:系统升级通知</view>
  </swiper-item>
  <swiper-item>
    <view class="notice-item">公告2:活动即将开始</view>
  </swiper-item>
</swiper>

<!-- 卡片式轮播(设置间距和边距) -->
<swiper 
  next-margin="30rpx"
  previous-margin="30rpx"
  display-multiple-items="1"
>
  <swiper-item ="{{cards}}" ="id">
    <view class="card">{{item.title}}</view>
  </swiper-item>
</swiper>

常用属性:

属性 类型 说明
indicator-dots Boolean 是否显示面板指示点
autoplay Boolean 是否自动切换
interval Number 自动切换时间间隔(ms)
duration Number 滑动动画时长(ms)
circular Boolean 是否循环播放
vertical Boolean 滑动方向是否为纵向
current Number 当前所在滑块的索引
bindchange EventHandle current改变时触发

5. <movable-view> - 可移动容器

需要配合 <movable-area> 使用,实现可拖拽移动的组件。

html 复制代码
<!-- 基础拖拽 -->
<movable-area style="width: 600rpx; height: 600rpx; background: #f0f0f0;">
  <movable-view 
    style="width: 100rpx; height: 100rpx; background: #07c160;"
    direction="all"
    bindchange="onMovableChange"
  >
    拖拽
  </movable-view>
</movable-area>

<!-- 限制拖拽范围 -->
<movable-area style="width: 100%; height: 400rpx;">
  <movable-view 
    x="{{x}}" 
    y="{{y}}"
    direction="all"
    out-of-bounds="{{false}}"
    bindchange="onChange"
  >
    <view class="drag-item">可拖动</view>
  </movable-view>
</movable-area>

常用属性:

  • direction:移动方向(all/vertical/horizontal/none)

  • x/y:初始位置

  • out-of-bounds:是否超出边界

  • damping:阻尼系数(超出边界后)

6. <cover-view> - 覆盖原生组件

覆盖在原生组件(如 <video><map><canvas>)之上的视图。

html 复制代码
<!-- 视频上叠加控件 -->
<video src="{{videoUrl}}" controls>
  <cover-view class="video-controls">
    <cover-view class="play-btn" bindtap="togglePlay">
      {{isPlaying ? '暂停' : '播放'}}
    </cover-view>
    <cover-view class="time">{{currentTime}}/{{duration}}</cover-view>
  </cover-view>
</video>

<!-- 地图上叠加信息 -->
<map latitude="{{latitude}}" longitude="{{longitude}}">
  <cover-view class="map-marker">
    <cover-image src="/images/marker.png" />
    <cover-view>当前位置</cover-view>
  </cover-view>
</map>

注意事项:

  • 仅支持部分组件:buttonimagetextview

  • 不支持 overflowposition: fixed 等CSS属性

  • 建议使用 cover-image 显示图片

7. <page-container> - 页面级容器

实现弹窗、抽屉、半屏等效果,类似于半透明遮罩层。

html 复制代码
<!-- 底部弹出 -->
<button bindtap="showPopup">显示弹窗</button>

<page-container 
  show="{{showPopup}}"
  position="bottom"
  round="{{true}}"
  bindafterleave="onPopupClose"
>
  <view class="popup-content">
    <view class="popup-header">标题</view>
    <view class="popup-body">弹窗内容</view>
    <button bindtap="closePopup">关闭</button>
  </view>
</page-container>
javascript 复制代码
Page({
  data: {
    showPopup: false
  },
  showPopup() {
    this.setData({ showPopup: true });
  },
  closePopup() {
    this.setData({ showPopup: false });
  }
});

常用属性:

  • show:是否显示

  • position:弹出位置(top/bottom/left/right/center)

  • round:是否显示圆角

  • overlay:是否显示遮罩层

  • close-on-slide-down:是否允许下滑关闭

基础内容组件

基础内容组件包括icon、text和progress,用于在视图界面中展现图标、文本内容及进度条等信息。用于展示最基础UI内容的组件,包括文本、图标、进度条等。它们是构建用户界面的最小单元,几乎所有页面都会用到。

组件名 主要功能 适用场景
<text> 文本展示 普通文本、内联文本、长按复制
<icon> 图标展示 状态图标、提示图标、简单图标
<progress> 进度条 加载进度、下载进度、完成率展示
<rich-text> 富文本渲染 渲染HTML、文章内容、格式化文本
<view> 基础容器 布局容器(已在视图容器中介绍)

1. <text> - 文本组件

最基础的文本展示组件,支持长按复制、嵌套等特性。

属性 类型 说明
selectable Boolean 是否支持长按选中复制(默认false)
space String 显示连续空格(ensp/emsp/nbsp)
decode Boolean 是否解码HTML实体(&nbsp;等)
user-select Boolean 是否支持用户选择(基础库2.12.1+)
html 复制代码
<!-- 长按复制文本 -->
<text selectable="{{true}}" user-select="{{true}}">
  这段文字可以被长按复制
</text>

<!-- 显示连续空格 -->
<text space="ensp">文  本(中文空格)</text>
<text space="emsp">文  本(em空格)</text>
<text space="nbsp">文  本(不断行空格)</text>

<!-- 解码HTML实体 -->
<text decode="{{true}}">&lt; &gt; &amp; &nbsp; &ensp; &emsp;</text>
<!-- 输出: < > &      -->

文本嵌套

html 复制代码
<!-- text支持嵌套,内层会继承外层样式 -->
<text class="outer">
  外层文本
  <text class="inner" selectable>内层可复制文本</text>
  继续外层文本
</text>

<!-- 实现文本截断效果 -->
<text class="ellipsis">
  很长很长很长很长很长很长很长很长的文本会被截断
</text>


/* 文本截断样式 */
.ellipsis {
  display: block;
  width: 300rpx;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

2. <icon> - 图标组件

提供内置的图标库,无需图片资源即可使用常见图标。

可用图标类型

type值 说明 默认颜色
success 成功图标(圆形打勾) #07c160
success_no_circle 成功图标(无圆形) #07c160
info 信息图标(圆形i) #1989fa
warn 警告图标(三角感叹号) #fa2c19
waiting 等待图标(圆形时钟) #ff976a
cancel 取消图标(圆形叉) #999
download 下载图标 #666
search 搜索图标(放大镜) #666
clear 清除图标(叉) #ccc

属性说明

属性 类型 默认值 说明
type String - 图标类型(必填)
size Number/String 23 图标大小(单位px)
color String 各类型默认色 图标颜色
html 复制代码
<!-- 自定义大小和颜色 -->
<icon type="success" size="32" color="#ff6600" />
<icon type="info" size="20" color="#00b26a" />

<!-- 结合文本使用 -->
<view class="status-item">
  <icon type="success" size="16" />
  <text>操作成功</text>
</view>

3. <progress> - 进度条组件

展示操作进度,支持百分比显示、动画、圆角等。

属性 类型 默认值 说明
percent Number 0 进度百分比(0-100)
show-info Boolean false 是否显示百分比文字
stroke-width Number 6 进度条高度(单位px)
color String #09BB07 进度条颜色
backgroundColor String #EBEBEB 背景条颜色
active Boolean false 是否从左到右动画
active-mode String backwards 动画模式(backwards/forwards)
border-radius Number 0 圆角大小(单位px)
duration Number 30 动画持续时间(ms)
html 复制代码
<!-- 简单进度条 -->
<progress percent="30" />

<!-- 带文字百分比 -->
<progress percent="50" show-info stroke-width="8" />

<!-- 自定义颜色 -->
<progress 
  percent="75" 
  color="#1989fa" 
  backgroundColor="#e5e5e5" 
  stroke-width="10"
  border-radius="5"
/>

<!-- 带动画效果 -->
<progress 
  percent="{{progressPercent}}" 
  active="{{true}}" 
  active-mode="forwards"
  duration="1000"
  show-info
/>
javascript 复制代码
Page({
  data: {
    progressPercent: 0
  },
  
  onLoad() {
    // 模拟进度更新
    let progress = 0;
    const timer = setInterval(() => {
      progress += 10;
      this.setData({ progressPercent: progress });
      
      if (progress >= 100) {
        clearInterval(timer);
      }
    }, 500);
  }
});

4. <rich-text> - 富文本组件

用于渲染HTML字符串,支持常见的HTML标签和样式。

html 复制代码
<!-- 基础HTML渲染 -->
<rich-text nodes="<h1>标题</h1><p>这是一个段落</p>" />

<!-- 通过数据绑定 -->
<rich-text nodes="{{htmlContent}}" />
javascript 复制代码
Page({
  data: {
    htmlContent: `
      <div style="padding: 20rpx;">
        <h2 style="color: #333;">文章标题</h2>
        <p style="font-size: 28rpx; line-height: 1.6;">
          这是一段<span style="color: red;">高亮文字</span>。
        </p>
        <img src="https://example.com/image.jpg" style="width: 100%;" />
        <ul>
          <li>列表项1</li>
          <li>列表项2</li>
        </ul>
      </div>
    `
  }
});

nodes 支持两种格式:字符串数组

表单组件

用于收集用户输入信息的重要组件,涵盖文本输入、选择器、开关、按钮等交互元素,是构建用户交互界面的核心。

组件名 主要功能 适用场景
<button> 按钮 表单提交、页面跳转、授权触发
<input> 输入框 文本、数字、密码、身份证输入
<textarea> 多行输入框 评论、反馈、文章编辑
<checkbox> 多选框 多项选择、协议确认
<radio> 单选框 性别选择、选项切换
<switch> 开关 状态切换、设置项
<slider> 滑动选择器 音量、亮度、数值范围选择
<picker> 选择器 日期、时间、地区、自定义选择
<picker-view> 嵌入式选择器 三级联动、自定义滚动选择
<form> 表单容器 批量收集表单数据

1. <button> - 按钮组件

最核心的交互组件,支持多种类型、尺寸和状态。

属性 类型 默认值 说明
type String default 按钮类型(default/primary/warn)
size String default 按钮大小(default/mini)
plain Boolean false 是否镂空
disabled Boolean false 是否禁用
loading Boolean false 是否显示加载图标
form-type String - 表单类型(submit/reset)
open-type String - 开放能力(contact/share/getPhoneNumber等)
hover-class String button-hover 点击态样式
hover-stop-propagation Boolean false 阻止点击态冒泡
hover-start-time Number 20 点击后多久出现点击态
hover-stay-time Number 70 点击态保持时长

开放能力(open-type)

html 复制代码
<!-- 获取用户信息 -->
<button open-type="getUserInfo" bindgetuserinfo="onGetUserInfo">
  获取用户信息
</button>

<!-- 获取手机号 -->
<button open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumber">
  获取手机号
</button>

<!-- 分享 -->
<button open-type="share">分享给朋友</button>

<!-- 客服 -->
<button open-type="contact" bindcontact="onContact">
  联系客服
</button>

<!-- 打开APP -->
<button open-type="launchApp">打开APP</button>

<!-- 反馈 -->
<button open-type="feedback">意见反馈</button>
javascript 复制代码
Page({
  onGetUserInfo(e) {
    console.log(e.detail.userInfo);
  },
  
  onGetPhoneNumber(e) {
    console.log(e.detail.code);
    console.log(e.detail.errMsg);
  }
});

2. <input> - 输入框

最常用的文本输入组件,支持多种输入类型。

属性 类型 说明
value String 输入框内容
type String 类型(text/number/idcard/digit)
password Boolean 是否密码类型
placeholder String 占位符
placeholder-style String 占位符样式
placeholder-class String 占位符样式类
disabled Boolean 是否禁用
maxlength Number 最大长度(0不限制)
cursor-spacing Number 光标与键盘距离
focus Boolean 自动获取焦点
confirm-type String 键盘右下角按钮类型
confirm-hold Boolean 点击确认按钮是否保持键盘
adjust-position Boolean 键盘弹起时是否自动上推页面
hold-keyboard Boolean 聚焦时点击页面不收起键盘
auto-fill String 自动填充内容

3. <textarea> - 多行输入框

用于输入多行文本,如评论、反馈等场景。

html 复制代码
<textarea 
  placeholder="请输入评论内容"
  maxlength="200"
  auto-height="{{true}}"
  show-confirm-bar="{{false}}"
  bindinput="onTextareaInput"
/>

<!-- 固定高度文本域 -->
<textarea 
  style="height: 200rpx;"
  maxlength="500"
  placeholder-style="color: #999;"
/>

常用属性:

  • auto-height:是否自动增高

  • show-confirm-bar:是否显示键盘上方完成栏

  • disable-default-padding:是否移除默认内边距

4. <checkbox> - 多选框

用于多选场景,需配合 <checkbox-group> 使用。

html 复制代码
<!-- 单个多选框 -->
<checkbox-group bindchange="onCheckboxChange">
  <label>
    <checkbox value="agree" checked="{{isAgreed}}"/>
    同意用户协议
  </label>
</checkbox-group>

<!-- 多选组 -->
<checkbox-group bindchange="onHobbyChange">
  <label ="{{hobbies}}" ="value">
    <checkbox value="{{item.value}}" checked="{{item.checked}}"/>
    {{item.name}}
  </label>
</checkbox-group>
javascript 复制代码
Page({
  data: {
    hobbies: [
      { name: '阅读', value: 'read', checked: false },
      { name: '音乐', value: 'music', checked: true },
      { name: '运动', value: 'sport', checked: false }
    ]
  },
  
  onHobbyChange(e) {
    console.log('选中的值:', e.detail.value);
    // e.detail.value: ['music', 'read']
  }
});

5. <radio> - 单选框

用于单选场景,需配合 <radio-group> 使用。

html 复制代码
<radio-group bindchange="onGenderChange">
  <label>
    <radio value="male" checked="{{gender === 'male'}}"/>
    男
  </label>
  <label>
    <radio value="female" checked="{{gender === 'female'}}"/>
    女
  </label>
</radio-group>
javascript 复制代码
Page({
  data: {
    gender: 'male'
  },
  
  onGenderChange(e) {
    this.setData({
      gender: e.detail.value
    });
  }
});

6. <switch> - 开关

用于切换状态,类似设置项。

html 复制代码
<switch checked="{{isEnabled}}" bindchange="onSwitchChange" />

<!-- 自定义颜色 -->
<switch 
  checked="{{isVibrate}}"
  color="#07c160"
  type="switch"
  bindchange="onVibrateChange"
/>

<!-- 复选框样式 -->
<switch type="checkbox" checked="{{isSelected}}" />
javascript 复制代码
Page({
  data: {
    isEnabled: true,
    isVibrate: false
  },
  
  onSwitchChange(e) {
    this.setData({
      isEnabled: e.detail.value
    });
  }
});

7. <slider> - 滑动选择器

通过滑动选择数值,适合音量、亮度调节。

html 复制代码
<!-- 基础滑块 -->
<slider value="{{50}}" bindchange="onSliderChange" />

<!-- 带边界值 -->
<slider 
  min="0" 
  max="100" 
  step="1"
  value="{{volume}}"
  show-value
  bindchanging="onVolumeChanging"
  bindchange="onVolumeChange"
/>

<!-- 自定义样式 -->
<slider 
  block-size="20"
  block-color="#07c160"
  active-color="#07c160"
  backgroundColor="#e5e5e5"
/>
javascript 复制代码
Page({
  data: {
    volume: 50
  },
  
  onVolumeChanging(e) {
    // 拖动过程中实时触发
    console.log('当前值:', e.detail.value);
  },
  
  onVolumeChange(e) {
    // 拖动结束触发
    this.setData({
      volume: e.detail.value
    });
  }
});

8. <picker> - 选择器

从底部弹起的滚动选择器,支持多种模式

html 复制代码
普通选择器
<picker 
  mode="selector"
  range="{{selectorItems}}"
  value="{{selectorIndex}}"
  bindchange="onSelectorChange"
>
  <view>当前选择:{{selectorItems[selectorIndex]}}</view>
</picker>


多列选择器
<picker 
  mode="multiSelector"
  range="{{multiArray}}"
  value="{{multiIndex}}"
  bindchange="onMultiChange"
  bindcolumnchange="onColumnChange"
>
  <view>当前选择:{{multiArray[0][multiIndex[0]]}} - {{multiArray[1][multiIndex[1]]}}</view>
</picker>


时间选择器
<picker 
  mode="time"
  value="{{time}}"
  start="09:00"
  end="18:00"
  bindchange="onTimeChange"
>
  <view>当前时间:{{time}}</view>
</picker>

<picker 
  mode="date"
  value="{{date}}"
  start="2020-01-01"
  end="2030-12-31"
  bindchange="onDateChange"
>
  <view>当前日期:{{date}}</view>
</picker>


地区选择器
<picker 
  mode="region"
  value="{{region}}"
  bindchange="onRegionChange"
>
  <view>当前地区:{{region[0]}} {{region[1]}} {{region[2]}}</view>
</picker>
javascript 复制代码
Page({
  data: {
    selectorItems: ['选项1', '选项2', '选项3'],
    selectorIndex: 0,
    time: '12:00',
    date: '2024-01-15',
    region: ['广东省', '广州市', '海珠区']
  },
  
  onSelectorChange(e) {
    this.setData({
      selectorIndex: e.detail.value
    });
  },
  
  onTimeChange(e) {
    this.setData({
      time: e.detail.value
    });
  },
  
  onDateChange(e) {
    this.setData({
      date: e.detail.value
    });
  },
  
  onRegionChange(e) {
    this.setData({
      region: e.detail.value
    });
  }
});

9. <form> - 表单容器

用于统一收集表单组件的值,简化数据获取。

html 复制代码
<form bindsubmit="onFormSubmit" bindreset="onFormReset">
  <input name="username" placeholder="用户名" />
  <input name="password" password placeholder="密码" />
  
  <radio-group name="gender">
    <radio value="male">男</radio>
    <radio value="female">女</radio>
  </radio-group>
  
  <switch name="agree" value="{{true}}" />
  
  <button form-type="submit">提交</button>
  <button form-type="reset">重置</button>
</form>
javascript 复制代码
Page({
  onFormSubmit(e) {
    const formData = e.detail.value;
    console.log(formData);
    // { username: '张三', password: '123', gender: 'male', agree: true }
    
    // 提交到服务器
    wx.request({
      url: 'https://api.example.com/submit',
      data: formData,
      success: (res) => {
        wx.showToast({ title: '提交成功' });
      }
    });
  },
  
  onFormReset(e) {
    console.log('表单已重置');
  }
});

互动操作组件

用于增强用户与应用之间的交互体验,涵盖手势识别、弹窗菜单、消息提示等场景。

组件/API 类型 主要功能 适用场景
手势组件 Skyline组件 拖拽、缩放、长按等手势识别 半屏弹窗、图片缩放、拖拽排序
<button> 表单组件 触发交互、开放能力 分享、获取手机号、客服
ActionSheet 扩展组件/API 底部弹出操作菜单 多选项选择、操作面板
Modal API 模态对话框 重要确认、信息输入
Toast/Loading API 轻提示/加载提示 操作反馈、加载状态

互动组件选型建议

场景 推荐方案
半屏弹窗+拖拽关闭 Skyline手势组件
图片缩放/双指操作 <scale-gesture-handler>
底部操作菜单 wx.showActionSheet
重要确认弹窗 wx.showModal
简单操作反馈 wx.showToast
异步加载状态 wx.showLoading
微信分享/获取手机号 Button open-type

1. 手势组件(Skyline渲染引擎)

手势组件是Skyline渲染引擎内置的虚组件,直接在UI线程响应,避免了传统JS线程通信的延迟,性能更好。

组件名称 触发时机
<tap-gesture-handler> 点击时触发
<double-tap-gesture-handler> 双击时触发
<long-press-gesture-handler> 长按时触发
<pan-gesture-handler> 拖拽移动时触发
<vertical-drag-gesture-handler> 纵向滑动时触发
<horizontal-drag-gesture-handler> 横向滑动时触发
<scale-gesture-handler> 多指缩放时触发
<force-press-gesture-handler> iPhone重按时触发
html 复制代码
<!-- 拖拽手势 -->
<pan-gesture-handler worklet:ongesture="handlePan">
  <view class="drag-box">拖拽我</view>
</pan-gesture-handler>

<!-- 纵向拖拽(与scroll-view协同) -->
<vertical-drag-gesture-handler 
  worklet:ongesture="handleVerticalDrag"
  native-view="scroll-view"
>
  <scroll-view scroll-y style="height: 500rpx;">
    <view ="{{100}}" ="index">列表项 {{index}}</view>
  </scroll-view>
</vertical-drag-gesture-handler>

手势回调中的state字段表示当前手势状态:

状态值 常量名 说明
0 POSSIBLE 手势未识别
1 BEGIN 手势已识别
2 ACTIVE 连续手势活跃中
3 END 手势正常结束
4 CANCELLED 手势被取消

2. 操作菜单(ActionSheet)

底部弹出的操作菜单,用于提供多个操作选项。

javascript 复制代码
Page({
  showActionSheet() {
    wx.showActionSheet({
      alertText: "请选择操作",      // 提示文案
      itemList: ["编辑", "删除", "分享"],
      itemColor: "#000000",
      success: (res) => {
        console.log("点击了第" + res.tapIndex + "个按钮");
        if (res.tapIndex === 0) {
          // 编辑操作
        } else if (res.tapIndex === 1) {
          // 删除操作
        }
      },
      fail: (error) => {
        console.log("调用失败", error);
      }
    });
  }
});

3. 模态对话框(Modal)

用于需要用户确认的重要操作。

属性 类型 说明
title String 对话框标题
content String 对话框内容
showCancel Boolean 是否显示取消按钮
cancelText String 取消按钮文字
confirmText String 确认按钮文字
editable Boolean 是否显示输入框
placeholderText String 输入框提示文字
javascript 复制代码
Page({
  showConfirm() {
    wx.showModal({
      title: "温馨提示",
      content: "是否确认删除该条记录?",
      showCancel: true,
      cancelText: "取消",
      cancelColor: "#999",
      confirmText: "确认",
      confirmColor: "#fa2c19",
      success: (res) => {
        if (res.confirm) {
          // 用户点击确认
          console.log("确认删除");
        } else if (res.cancel) {
          // 用户点击取消
          console.log("取消删除");
        }
      }
    });
  },
  
  // 带输入框的模态框(基础库2.17.1+)
  showPrompt() {
    wx.showModal({
      title: "输入昵称",
      editable: true,
      placeholderText: "请输入新昵称",
      success: (res) => {
        if (res.confirm && res.content) {
          console.log("输入内容:", res.content);
        }
      }
    });
  }
});

4. 轻提示(Toast)

自动消失的提示信息,适合操作结果反馈。

javascript 复制代码
Page({
  showSuccess() {
    wx.showToast({
      title: "保存成功",
      icon: "success",   // success/error/loading/none
      duration: 2000,
      mask: true        // 防止背景被点击
    });
  },
  
  showError() {
    wx.showToast({
      title: "操作失败",
      icon: "error",
      duration: 2000
    });
  },
  
  // 手动隐藏
  hideToast() {
    wx.hideToast();
  }
});

5. 加载提示(Loading)

需要手动关闭的加载提示,适合异步操作。

javascript 复制代码
Page({
  async loadData() {
    // 显示加载中
    wx.showLoading({
      title: "加载中...",
      mask: true
    });
    
    try {
      // 模拟异步请求
      const res = await this.fetchData();
      // 处理数据...
    } catch (error) {
      wx.showToast({ title: "加载失败", icon: "error" });
    } finally {
      // 手动关闭loading
      wx.hideLoading();
    }
  }
});

6. Button开放能力

Button组件的open-type属性可调用微信开放能力

html 复制代码
<!-- 获取用户信息 -->
<button open-type="getUserInfo" bindgetuserinfo="onGetUserInfo">
  获取用户信息
</button>

<!-- 获取手机号(需后端配合) -->
<button open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumber">
  获取手机号
</button>

<!-- 分享给朋友 -->
<button open-type="share">分享</button>

<!-- 打开客服会话 -->
<button open-type="contact" bindcontact="onContact">联系客服</button>

<!-- 打开意见反馈 -->
<button open-type="feedback">意见反馈</button>

<!-- 打开APP(需APP关联) -->
<button open-type="launchApp" app-parameter="key=value">打开APP</button>
javascript 复制代码
Page({
  onGetUserInfo(e) {
    console.log(e.detail.userInfo);
  },
  
  onGetPhoneNumber(e) {
    // 新版接口返回code,需后端换取手机号
    console.log(e.detail.code);
  },
  
  onShareAppMessage() {
    return {
      title: '分享标题',
      path: '/pages/index/index'
    };
  }
});

页面导航组件

核心指的就是 <navigator> 组件。它主要负责在页面之间构建链接,实现用户点击后的页面跳转。简单来说,它类似于 HTML 中的 <a> 标签,但功能更丰富,能适应小程序中不同类型页面的跳转规则

1. 关键属性速查

属性名 类型 说明 最低版本
url String 当前小程序内的跳转链接,路径后可以带参数-1-5 1.0.0
open-type String 跳转方式,这是最关键的属性,决定了跳转时的页面栈行为-5 1.0.0
delta Number open-type="navigateBack" 时有效,表示回退的页面层数,默认为 1-5 1.0.0
hover-class String 指定点击时的样式类,默认值为 navigator-hover。可以设置为 none 来去掉点击态效果-5 1.0.0

2. open-type 跳转方式详解

这是 <navigator> 的核心,它决定了跳转时页面栈的变化,具体有5种模式-5-6

open-type 功能说明 对应API 页面栈表现
navigate 保留当前页面,跳转到应用内的某个页面。这是默认值 -5 wx.navigateTo 新页面入栈,页面栈加1。
redirect 关闭当前页面,跳转到应用内的某个页面。 wx.redirectTo 当前页面出栈,新页面入栈,页面栈大小不变。
switchTab 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。 wx.switchTab 清除非 tabBar 页面,切换到指定的 tabBar 页面。
reLaunch 关闭所有页面,打开到应用内的某个页面。 wx.reLaunch 清空所有页面,新页面入栈。
navigateBack 关闭当前页面,返回上一页面或多级页面。 wx.navigateBack 页面出栈,直到回到目标页面。

3. 使用注意事项

  1. 路径写法url 属性中的路径建议使用以 / 开头的绝对路径,这样最不容易出错。

  2. 页面栈限制 :小程序页面栈最多支持 10 层。使用 navigate 跳转时需注意,避免页面层级过深导致无法再打开新页面。

  3. 样式定制<navigator> 组件自带点击态效果(灰色背景)。你可以通过修改 .navigator-hover 这个类名来全局自定义样式,或者给某个导航单独设置 hover-class 属性

<navigator> 组件是微信小程序页面跳转的基础,掌握它对于构建流畅的用户交互至关重要。

  • 判断目标页面类型 :在写代码前,先问自己"要跳转的页面是不是 Tab 页?"。如果是,open-type 必须用 switchTab;如果不是,大多数情况用默认的 navigate 即可。

  • 传递简单参数 :直接在 url 后用 ? 拼接,格式为 ?key1=value1&key2=value2。参数可以在目标页面的 onLoad(options) 中通过 options 参数接收-1-9

  • 后退操作 :小程序自带返回箭头,如需自定义返回按钮,使用 open-type="navigateBack"

除了声明式的 <navigator> 组件,小程序也支持通过 wx.navigateTowx.redirectTo 等 API 进行编程式导航

媒体组件

用于在应用中展示图片、音视频、地图等富媒体内容

组件名 主要功能 适用场景
<image> 图片展示 头像、商品图、轮播图、背景图
<video> 视频播放 短视频、课程视频、直播回放
<camera> 相机组件 拍照、扫码、人脸识别
<live-player> 直播播放 实时直播、体育赛事
<live-pusher> 直播推流 主播开播、视频会议
<audio> 音频播放(旧版) 背景音乐、语音播放
<map> 地图组件 位置展示、导航、轨迹记录

1. <image> - 图片组件

最常用的媒体组件,支持多种图片模式和懒加载。

属性 类型 默认值 说明
src String - 图片资源地址
mode String scaleToFill 图片裁剪、缩放的模式
lazy-load Boolean false 是否懒加载
show-menu-by-longpress Boolean false 长按是否显示菜单
webp Boolean false 是否支持WebP格式
binderror EventHandle - 图片加载失败触发
bindload EventHandle - 图片加载完成触发

mode 模式详解

mode 值 说明 适用场景
scaleToFill 拉伸填充,不保持比例 图标、背景图
aspectFit 保持比例,完整显示 商品图、相册
aspectFill 保持比例,裁剪溢出 头像、封面图
widthFix 宽度固定,高度自适应 文章配图、详情图
heightFix 高度固定,宽度自适应 横向滚动图
top/center/bottom 裁剪模式 特定位置对齐
html 复制代码
<!-- 头像:保持比例,居中裁剪 -->
<image class="avatar" mode="aspectFill" src="{{avatar}}" />

<!-- 商品图:完整显示,可能留白 -->
<image class="product" mode="aspectFit" src="{{productImage}}" />

<!-- 文章图:宽度固定,高度自适应 -->
<image mode="widthFix" src="{{articleImage}}" />
javascript 复制代码
.avatar {
  width: 80rpx;
  height: 80rpx;
  border-radius: 50%;
}

.product {
  width: 100%;
  height: 300rpx;
  background-color: #f5f5f5;
}

2. <video> - 视频组件

功能强大的视频播放器,支持多种格式和播放控制。

属性 类型 默认值 说明
src String - 视频地址
controls Boolean true 显示默认播放控件
autoplay Boolean false 自动播放
loop Boolean false 循环播放
muted Boolean false 静音播放
initial-time Number 0 初始播放位置(秒)
duration Number - 视频时长(秒)
poster String - 视频封面图
object-fit String contain 填充模式(contain/fill/cover)
show-center-play-btn Boolean true 显示中央播放按钮
enable-progress-gesture Boolean true 开启手势进度调节
show-fullscreen-btn Boolean true 显示全屏按钮
show-play-btn Boolean true 显示播放按钮

3. <camera> - 相机组件

用于调用设备摄像头,实现拍照、扫码等功能。

属性 类型 默认值 说明
device-position String back 前置/后置摄像头(front/back)
flash String off 闪光灯状态(auto/on/off/torch)
frame-size String medium 帧数据尺寸(small/medium/large)
scan-area Array - 扫码识别区域
binderror EventHandle - 用户不允许授权或错误
html 复制代码
<camera 
  id="myCamera"
  device-position="{{devicePosition}}"
  flash="{{flashMode}}"
  binderror="onError"
  style="width: 100%; height: 600rpx;"
/>

<view class="camera-controls">
  <button bindtap="toggleCamera">切换摄像头</button>
  <button bindtap="toggleFlash">闪光灯: {{flashMode}}</button>
  <button bindtap="takePhoto">拍照</button>
  <button bindtap="scanCode">扫码</button>
</view>

<image ="{{photoPath}}" src="{{photoPath}}" mode="widthFix" />
javascript 复制代码
Page({
  data: {
    devicePosition: 'back',
    flashMode: 'off',
    photoPath: ''
  },
  
  onReady() {
    this.cameraContext = wx.createCameraContext();
  },
  
  toggleCamera() {
    this.setData({
      devicePosition: this.data.devicePosition === 'back' ? 'front' : 'back'
    });
  },
  
  toggleFlash() {
    const modes = ['off', 'on', 'torch'];
    const currentIndex = modes.indexOf(this.data.flashMode);
    const nextMode = modes[(currentIndex + 1) % modes.length];
    this.setData({ flashMode: nextMode });
  },
  
  takePhoto() {
    this.cameraContext.takePhoto({
      quality: 'high',
      success: (res) => {
        this.setData({ photoPath: res.tempImagePath });
        wx.saveImageToPhotosAlbum({
          filePath: res.tempImagePath,
          success: () => {
            wx.showToast({ title: '保存成功' });
          }
        });
      }
    });
  },
  
  scanCode() {
    this.cameraContext.startScanCode({
      success: (res) => {
        console.log('扫码结果:', res.result);
        wx.showModal({
          title: '扫描结果',
          content: res.result
        });
      }
    });
  }
});

4. <live-player> - 直播播放组件

用于播放实时直播流,支持RTMP、HLS等协议。

使用 live-player 需要申请相应的类目权限。

html 复制代码
<live-player 
  src="{{liveUrl}}"
  mode="live"
  autoplay="{{true}}"
  muted="{{false}}"
  bindstatechange="onStateChange"
  binderror="onError"
  style="width: 100%; height: 400rpx;"
/>
javascript 复制代码
Page({
  data: {
    liveUrl: 'rtmp://example.com/live/stream'
  },
  
  onStateChange(e) {
    console.log('播放状态:', e.detail.code);
    // 状态码: 2001-2004 开始播放/播放中/暂停/停止
  },
  
  onError(e) {
    console.error('播放错误:', e.detail);
  }
});

地图组件

展示地图、标记点、路线等功能。

属性 类型 说明
latitude Number 中心纬度
longitude Number 中心经度
scale Number 缩放级别(3-20)
markers Array 标记点数组
polyline Array 路线数组
circles Array 圆数组
controls Array 控件数组
show-location Boolean 显示带有方向的当前定位点
enable-zoom Boolean 是否支持缩放
enable-scroll Boolean 是否支持拖动
html 复制代码
<map 
  id="myMap"
  latitude="{{latitude}}"
  longitude="{{longitude}}"
  scale="{{scale}}"
  markers="{{markers}}"
  polyline="{{polyline}}"
  show-location
  bindmarkertap="onMarkerTap"
  bindregionchange="onRegionChange"
/>

<view class="map-controls">
  <button bindtap="getUserLocation">定位当前位置</button>
  <button bindtap="addMarker">添加标记</button>
</view>
javascript 复制代码
Page({
  data: {
    latitude: 39.9042,   // 北京天安门
    longitude: 116.4074,
    scale: 14,
    markers: [{
      id: 1,
      latitude: 39.9042,
      longitude: 116.4074,
      title: '天安门',
      iconPath: '/images/marker.png',
      width: 30,
      height: 30,
      callout: {
        content: '天安门广场',
        color: '#333',
        fontSize: 14
      }
    }],
    polyline: [{
      points: [
        { latitude: 39.9042, longitude: 116.4074 },
        { latitude: 39.9142, longitude: 116.4174 }
      ],
      color: '#07c160',
      width: 4,
      dottedLine: false
    }]
  },
  
  onReady() {
    this.mapContext = wx.createMapContext('myMap');
  },
  
  getUserLocation() {
    wx.getLocation({
      type: 'gcj02',
      success: (res) => {
        this.setData({
          latitude: res.latitude,
          longitude: res.longitude
        });
        this.mapContext.moveToLocation();
      }
    });
  },
  
  addMarker() {
    const newMarker = {
      id: Date.now(),
      latitude: this.data.latitude + 0.001,
      longitude: this.data.longitude + 0.001,
      title: '新标记',
      iconPath: '/images/marker.png'
    };
    this.setData({
      markers: [...this.data.markers, newMarker]
    });
  },
  
  onMarkerTap(e) {
    const markerId = e.detail.markerId;
    wx.showModal({
      title: '标记点',
      content: `点击了标记点ID: ${markerId}`
    });
  },
  
  onRegionChange(e) {
    if (e.type === 'end') {
      console.log('地图移动结束');
    }
  }
});

地图性能

  • 标记点过多时使用聚合

  • 及时调用 moveToLocation 定位

  • 避免频繁更新 markers

画布组件

用于自由绘制图形的矩形区域,它提供了强大的绘图能力,可以满足从基础图形绘制到复杂动画、图像处理等多种场景需求

与其他大部分组件不同,<canvas> 组件本身只是一个空白的画布容器,具体的绘制工作需要通过调用相应的 API 来完成

  1. 两种版本,从 "旧" 到 "新"

微信小程序的 Canvas 主要经历了两个版本的演进,强烈建议新项目直接使用新版 2D Canvas

  • 旧版 Canvas(已过时)

    • 通过 canvas-id 来标识,使用 wx.createCanvasContext(canvasId) 获取绘图上下文。

    • 所有绘图操作都是异步的,最后需要调用 .draw() 方法才会真正将内容渲染到画布上,逻辑较复杂,性能也相对较差。

  • 新版 Canvas 2D(推荐)

    • 基础库 2.7.0 开始支持,通过 type="2d" 来声明。

    • 它的 API 接口与 Web 标准对齐,通过 Canvas.getContext('2d') 获取的上下文与 Web 开发一致,绘图操作是同步的,性能更好,开发体验也更流畅。

2. 关键属性速查

在新版 Canvas 2D 中,常用属性如下:

属性名 类型 说明
type String 必须 。定义画布类型,2D 绘图应设为 "2d"
id String 必须。组件的唯一标识,用于后续获取 Canvas 实例
disable-scroll Boolean 当在 canvas 中移动且有绑定手势事件时,禁止屏幕滚动
bindtouchstart EventHandle 手指触摸动作开始
bindtouchmove EventHandle 手指触摸后移动
bindtouchend EventHandle 手指触摸动作结束
html 复制代码
<!-- canvasDemo.wxml -->
<canvas id="myCanvas" type="2d" style="width: 300px; height: 150px; border: 1px solid #ccc;"></canvas>

在页面的 onReady 生命周期中,获取节点和渲染上下文,然后进行绘制。

javascript 复制代码
// canvasDemo.js
Page({
  onReady() {
    // 1. 通过 SelectorQuery 获取 Canvas 节点
    const query = wx.createSelectorQuery();
    query.select('#myCanvas')
      .fields({ node: true, size: true })
      .exec((res) => {
        // 2. 获取 Canvas 对象和 2D 渲染上下文
        const canvas = res[0].node;
        const ctx = canvas.getContext('2d');
        
        // 3. 处理设备像素比(DPI),防止图片在高分屏上模糊
        const dpr = wx.getSystemInfoSync().pixelRatio;
        canvas.width = res[0].width * dpr;
        canvas.height = res[0].height * dpr;
        ctx.scale(dpr, dpr);
        
        // 4. 开始绘图:绘制一个红色正方形
        ctx.fillStyle = 'red';
        ctx.fillRect(10, 10, 50, 50);
      });
  }
});

代码解析

  • wx.createSelectorQuery():用于查询页面节点。

  • canvas.getContext('2d'):获取 2D 绘图上下文,这是所有绘图操作的基础。

  • canvas.width / canvas.height:设置画布的实际像素尺寸。这与 CSS 定义的渲染尺寸(300*150px)不同,乘以 dpr 是为了保证绘图在高清屏上不会模糊。

  • ctx.fillRect(x, y, width, height):绘制一个实心矩形。

Canvas 可以用来实现很多复杂的功能:

  • 图表绘制 :利用路径(beginPath, lineTo)和贝塞尔曲线(bezierCurveTo)等方法,可以绘制各种统计图表,如平滑的折线图。

  • 图像处理:在 canvas 上加载并绘制图片,并为其添加文字或图形水印,保护图片版权。

  • 动画与游戏 :通过 canvas.requestAnimationFrame 方法可以创建流畅的逐帧动画,是实现小程序游戏的基础。

使用 wxml2canvas-2d 生成海报

在实际开发中,我们经常遇到将一段复杂的UI(如包含图片、文字、头像的卡片)一键生成海报并保存或分享的需求。手动用 Canvas API 去计算每个元素的位置非常繁琐。

这时,就可以使用像 wxml2canvas-2d 这样的第三方库,它允许你像写普通页面一样,通过 WXML 和 CSS 来描述海报的样式,然后由它自动帮你绘制到 Canvas 上,极大地提高了开发效。

基本使用思路如下:

  • 安装和引入 :通过 npm 安装 wxml2canvas-2d 并在页面的 usingComponents 中注册。

  • 编写 "海报模板":在 WXML 中,用一个特定类名的容器包裹起你想生成海报的内容,并像平时写样式一样,用 WXSS 定义好每个元素的样式。

  • 调用方法生成图片 :在 JS 中,通过 selectComponent 获取组件实例,调用其 draw()toTempFilePath() 方法,就能得到一张海报图片。

相关推荐
CHU7290353 小时前
在线教学课堂APP功能版块设计方案:重构学习场景的交互逻辑
java·学习·小程序·重构
焦糖玛奇朵婷4 小时前
盲盒小程序开发,盲盒小程序怎么做
java·大数据·服务器·前端·小程序
想七想八不如114084 小时前
【GitHub开源】一款极简跨平台 Todo 应用:微信小程序 + Windows 桌面挂件 + 实时同步
微信小程序·开源·github
笨笨狗吞噬者4 小时前
代理的妙用:uni-app 小程序是怎样用 `Proxy` 和 `wrapper` 抹平平台差异的
前端·微信小程序·uni-app
CHU7290351 天前
便捷约玩,沉浸推理:线上剧本杀APP功能版块设计详解
前端·小程序
px不是xp1 天前
微信小程序组件化开发最佳实践
微信小程序·小程序·notepad++
曲江涛1 天前
微信小程序 摄像头 授权同页面丝滑调用
微信小程序
code_Bo1 天前
kiro生成小程序商业案例
前端·微信小程序·小程序·云开发
编程迪1 天前
基于SpringBoot开发的预约停车系统共享停车位小程序app
小程序·停车场小程序·预约停车·错峰出行·共享车位app