tencent cloud

腾讯云超级应用服务

原生组件

PDF
聚焦模式
字号
最后更新时间: 2025-04-22 18:11:25

原生组件

我们部分组件是由客户端创建的原生组件。这些原生组件是由小程序客户端实现的,具有更高的性能和更丰富的功能。
原生组件包括:
camera:相机组件,用于调用摄像头拍照或录像;
Canvas:画布组件,用于绘制图形、动画等;
input:仅在 focus 时表现为原生组件;
textarea:多行输入框组件,用于输入多行文本;
video:视频组件,用于播放视频;
liver-player:实时音视频播放组件,用于播放直播流;
live-pusher:实时音视频录制组件,用于推送直播流;
map:地图组件,用于显示地图和地图上的标记、路线等;
ad:Banner 广告;
web-view:承载网页的容器。

原生组件的使用限制

由于原生组件脱离在 WebView 渲染流程外,因此在使用时有以下限制:
原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上。后插入的原生组件可以覆盖之前的原生组件。
原生组件无法在<picker-view>中使用。
部分 CSS 样式无法应用于原生组件,例如:
无法对原生组件设置 CSS 动画。
无法定义原生组件为position: fixed
不能在父级节点使用overflow: hidden来裁剪原生组件的显示区域。
原生组件的事件监听不能使用bind:eventname的写法,只支持bindeventname。原生组件也不支持catchcapture的事件绑定方式。
原生组件会遮挡 vConsole 弹出的调试面板。
说明:
在工具上,原生组件是用 web 组件模拟的,因此很多情况并不能很好的还原真机的表现,建议开发者在使用到原生组件时尽量在真机上进行调试。

安卓平台非同层渲染限制

原生组件在 ​iOS 上采用同层渲染​,而安卓均为非同层渲染,所以安卓平台下存在以下特有限制:

​1. 层级绝对优先

安卓原生组件始终处于视图最顶层,即使后插入的普通组件也无法覆盖。

解决方案:

使用专为覆盖原生组件设计的组件 cover-viewcover-image
示例代码
<video>
<cover-view class="controls">自定义播放控件按钮</cover-view>
</video>
注意:
仅支持嵌套在指定原生组件内
样式属性受限(仅支持opacity\\padding\\border-radius\\rotate\\scaleX\\scaleY\\width\\height\\left\\top\\background-color等简单样式)
无法包含其他普通子组件

​2. 动态位置调整受限

动态调整原生组件位置时可能出现闪烁、残影,尤其在快速移动、缩放时,原生渲染层与WebView视图层异步渲染机制易导致画面撕裂。

解决方案:

通过 wxs 响应触摸事件,实时计算坐标,动态调整原生组件位置。由于 wxs 能够直接处理视图层的事件,减少了与逻辑层的通信开销。例如对于频繁触发的触摸事件,使用 wxs 可以获得更好的性能表现。
示例代码
WXML
WXS
WXSS
<wxs src="./index.wxs" module="touch" />

<view class="container">
<view class="videoBox"
bind:touchstart="{{touch.touchstart}}"
bind:touchmove="{{touch.touchmove}}"
bind:touchend="{{touch.touchend}}">
<video class="video-item" src="视频地址1" controls />
<video class="video-item" src="视频地址2" controls />
<video class="video-item" src="视频地址3" controls />
</view>
</view>
// index.wxs
let startY = 0; // 起始Y坐标
let isStart = false; // 是否开始滑动
let moveDistance = 0; // 移动距离
let currentOffset = 0; // 保存累计偏移量


// 触摸开始事件
function touchstart(event, ins) {
if (!isStart) {
isStart = true;
const touch = event.touches[0];
startY = touch.pageY;
}
}


// 触摸移动事件
function touchmove(event, ins) {
const { pageY } = event.touches[0];
moveDistance = currentOffset + (pageY - startY);
// 更新元素位置
ins.selectComponent('.videoBox').setStyle({
transform: `translateY(${moveDistance}px)`
});
}


// 触摸结束事件
function touchend(event, ins) {
isStart = false;
currentOffset = moveDistance;
}


module.exports = {
touchstart,
touchmove,
touchend
};
.container {
width: 100vw;
height: 100%;
position: relative;
overflow: hidden;
top: 0;
position: absolute;
background: #000;
}

.videoBox {
width: 100vw;
height: 100%;
position: absolute;
}

.video-item {
width: 100vw;
height: 100%;
display: block;
}

3. 动态内容更新受限

覆盖在原生组件上的 cover-view 内容更新延迟或闪烁(如实时文本更新)。

解决方案:

减少高频更新(如用防抖函数控制渲染频率),或改用静态内容。
示例代码
WXML
JAVASCRIPT
<live-pusher>
<cover-view class="danmu">{{danmuText}}</cover-view>
</live-pusher>
// utils/debounce.js
function debounce(fn, delay = 300, immediate = false) {
let timer = null;
return function (...args) {
if (timer) clearTimeout(timer);
if (immediate && !timer) {
fn.apply(this, args); // 立即执行一次
}
timer = setTimeout(() => {
if (!immediate) {
fn.apply(this, args);
}
timer = null;
}, delay);
};
}
module.exports = debounce;



// pages/live.js
const debounce = require('../../utils/debounce');

Page({
data: { danmuText: '' },
onLoad() {
// 创建防抖后的更新函数,并绑定当前 Page 的 this
this.debouncedUpdateDanmu = debounce(this.updateDanmu.bind(this), 300);
},

updateDanmu(text) {
this.setData({ danmuText: text });
}

// 接收WebSocket实时消息
onSocketMessage(msg) {
this.debouncedUpdateDanmu(msg.content); // 高频调用会自动合并
}
});

4. 底部弹出层受限

当需要覆盖全屏原生组件(如videolive-player)实现底部弹出层时,虽然可以通过 cover-view 实现,但会存在以下限制:
交互能力受限cover-view仅支持嵌套cover-viewcover-image,所以弹出层中无法包含复杂交互,例如表单提交。
性能瓶颈:弹出层内如果需要插入大量cover-viewcover-image时易引发渲染卡顿。

解决方案:

通过动态调整原生组件容器高度,使弹出层与原生组件在布局上无重叠,从而使用普通组件(如 view)实现弹出层。
示例代码
WXML
JAVASCRIPT
WXSS
<view class="container">
<live-pusher class="liver-pusher" url="{{pusherUrl}}" autopush="{{true}}" mode="RTC">
<cover-view class="action-button" catchtap="handleOpen">打开弹出层</cover-view>
<cover-view class="action-button close" catchtap="handleClose">关闭弹出层</cover-view>
</live-pusher>
<view class="comments-modal" wx:if="{{open}}">
<input placeholder="这是一个输入框"/>
</view>
</view>
Page({
data: {
open: false,
},
handleOpen: function () {
this.setData({
open: true
})
},
handleClose: function () {
this.setData({
open: false
})
},
})
.container {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
background-color: #000;
}
.liver-pusher {
width: 100%;
flex: 1;
}
.action-button {
position: absolute;
height: 50px;
line-height: 50px;
text-align: center;
background-color: white;
}

.close {
left: 100px;
}

.comments-modal {
width: 100%;
background-color: #fff;
height: 40vh;
}


帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈