ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

taro-canvas-core 组件深度解析:Taro H5 端 Canvas 的 Web Components 封装与长按交互实现

taro-canvas-core 组件深度解析:Taro H5 端 Canvas 的 Web Components 封装与长按交互实现 taro-canvas-core 组件深度解析Taro H5 端 Canvas 的 Web Components 封装与长按交互实现【免费下载链接】taro开放式跨端跨框架解决方案支持使用 React/Vue 等框架来开发微信/京东/百度/支付宝/字节跳动/ QQ 小程序/H5/React Native 等应用。项目地址: https://gitcode.com/gh_mirrors/tar/tarotaro-canvas-core是 Taro 组件库packages/taro-components中用于 H5 渲染的 Canvas 画布组件它基于 StencilJS 以 Web Components 形式实现为跨端框架提供统一的Canvas /能力。本文以该组件的官方 API 文档为骨架结合源码实现、样式定义与单元/端到端测试逐项拆解它的属性、事件、默认样式与底层实现原理帮助读者在 H5 与 harmony_hybrid 场景下正确使用 Canvas 组件并理解其长按手势检测、尺寸同步等关键机制。一、组件定位为什么需要一个taro-canvas-core在 Taro 的多端架构中packages/taro-components 通过 StencilJS 将 H5 端组件编译为标准的 Web Components 自定义元素这样无论是 React、Vue3 还是 Solid 的运行时都能以统一的标签形态如taro-canvas-core使用这些组件。Canvas 组件在 H5 端的实体就是这个taro-canvas-core。从类型注册可以看到它的跨框架接入方式packages/taro-components/types/index.vue3.d.ts 中将taro-canvas-core注册为 Vue3 组件packages/taro-components/types/index.solid.d.ts 中同样将其映射为 Solid 组件TransformReact2SolidTypeCanvasProps。也就是说业务代码中书写Canvas canvasIdxxx /最终在 H5 端渲染出的就是带有canvas-id属性、内部包含原生canvas元素的taro-canvas-core。二、组件 API 一览继承自官方文档组件对外暴露的属性与事件如下与 readme.md 中的定义完全一致。PropertiesPropertyAttributeDescriptionTypeDefaultcanvasIdidCanvas 组件唯一标识符stringundefinedheightheight画布高度stringundefinednativeProps--透传到内部 H5 标签的属性集合{}{}widthwidth画布宽度stringundefinedEventsEventDescriptionTypelongtap手指长按 500ms 后触发CustomEventany值得注意的是canvasId与 attributeid的映射关系源码中通过Prop({ attribute: id }) canvasId: string声明因此在 HTML 层面使用id属性即可设置画布标识同时组件渲染出的原生canvas会携带canvas-id{canvasId}这与小程序端canvas-id的约定保持一致详见下文源码解析。三、核心实现源码解析组件的全部实现位于 packages/taro-components/src/components/canvas/canvas.tsx主体代码如下import { Component, h, ComponentInterface, Prop, Element, Event, EventEmitter } from stencil/core const LONG_TAP_DELAY 500 Component({ tag: taro-canvas-core, styleUrl: ./style/index.scss }) export class Canvas implements ComponentInterface { private timer: ReturnTypetypeof setTimeout Prop({ attribute: id }) canvasId: string Prop({ mutable: true, reflect: true }) height: string Prop({ mutable: true, reflect: true }) width: string Prop() nativeProps {} Element() el: HTMLElement Event({ eventName: longtap }) onLongTap: EventEmitter onTouchStart () { this.timer setTimeout(() { this.onLongTap.emit() }, LONG_TAP_DELAY) } onTouchMove () { clearTimeout(this.timer) } onTouchEnd () { clearTimeout(this.timer) } componentDidRender (): void { const [canvas] this.el.children as unknown as HTMLCanvasElement[] if (!this.height || !this.width) { let style window.getComputedStyle(canvas) this.height || style.height this.width || style.width } canvas.height parseInt(this.height) canvas.width parseInt(this.width) } render () { const { canvasId, nativeProps } this return ( canvas canvas-id{canvasId} style{{ width: 100%, height: 100% }} onTouchStart{this.onTouchStart} onTouchMove{this.onTouchMove} onTouchCancel{this.onTouchEnd} onTouchEnd{this.onTouchEnd} {...nativeProps} / ) } }3.1canvasId与id属性映射Prop({ attribute: id }) canvasId表明业务代码中传入canvasIdStencil 会把它序列化为 Web Component 的idattribute。随后在render()中canvas-id{canvasId}被设置到原生canvas元素上。这样做既保留了 H5 侧自定义元素的标识又让内部画布节点具备与小程序端一致的canvas-id属性便于Taro.createCanvasContext(canvasId)等 API 在 H5 端按标识查找画布。3.2 尺寸处理与像素级同步componentDidRenderheight与width均为mutablereflect属性即允许内部修改并反射回 DOM attribute。componentDidRender中完成了两件事兜底取计算样式当用户未显式传入height/width时通过window.getComputedStyle(canvas)读取内部画布的实际渲染尺寸并回填到组件属性同步位图大小将height/width通过parseInt解析为整数后写入canvas.height/canvas.width。这一步是 H5 Canvas 最容易踩坑的点——CSS 中的width/height只影响画布在页面上的显示尺寸而绘制分辨率位图缓冲区大小必须单独通过canvas.width/height属性设置否则会出现绘制模糊或比例失调。同时内部画布的样式被固定为width: 100%; height: 100%因此实际显示尺寸由外层taro-canvas-core或其父容器决定而绘制分辨率则由解析后的width/height数值决定两者职责清晰分离。3.3nativeProps透传Prop() nativeProps {}的默认值是空对象。在render()中通过{...nativeProps}展开到原生canvas上用于将 Web Component 层面的自定义属性透传到内部 H5 标签例如设置data-*自定义数据、style覆盖等。这一点在 packages/taro-components/types/Canvas.d.ts 的类型注释中也有对应说明用于透传 WebComponents 上的属性到内部 H5 标签上并标注支持h5, harmony_hybrid。3.4longtap长按事件500ms 计时器实现事件实现是一个非常典型的定时器 触摸状态机模式常量LONG_TAP_DELAY 500onTouchStart启动 500ms 定时器到点即emit()派发longtap事件onTouchMove触摸发生移动时清除定时器——移动说明用户是滑动而非长按onTouchEnd/onTouchCancel手指抬起或触摸被打断如来电、弹窗时清除定时器。配合事件监听onTouchCancel{this.onTouchEnd}保证了任何中断路径都不会误触发长按。这正好呼应了 packages/taro-components/types/Canvas.d.ts 中对onLongTap的语义描述手指长按 500ms 之后触发触发了长按事件后进行移动不会触发屏幕的滚动。四、默认样式与初始尺寸样式定义位于 packages/taro-components/src/components/canvas/style/index.scsstaro-canvas-core { display: block; position: relative; width: 300px; height: 150px; }display: block让自定义元素按块级布局占位position: relative作为内部画布及可能的叠加层如手写签名、绘图面板的定位上下文默认尺寸300px × 150px在未传入width/height时这就是组件在页面上的初始占位大小。此默认值在端到端测试中有明确断言见下文第五节。五、测试验证从源码到断言仓库为组件配备了单元测试与端到端测试可佐证上述行为。5.1 单元测试 canvas.spec.tsxconst canvasId my-canvas page await newSpecPage({ components: [Canvas], template: () (taro-canvas-core canvasId{canvasId} /), }) await page.waitForChanges() const canvas page.root?.firstChild as HTMLCanvasElement expect(canvas).toBeInstanceOf(HTMLCanvasElement) expect(canvas.getAttribute(canvas-id)).toBe(canvasId)该用例验证了渲染树结构taro-canvas-core的第一个子节点必须是原生HTMLCanvasElement并且其canvas-id属性值正确等于传入的canvasId。5.2 端到端测试 canvas.e2e.tspage await newE2EPage({ html: taro-canvas-core canvas-id${canvasId}/taro-canvas-core, })端到端测试通过真实浏览器渲染并断言了两点el.getAttribute(canvas-id)等于传入的canvasId属性映射正确计算样式style.width为300px、style.height为150px默认尺寸生效。这从测试层面锁定了本文第二节 API 表与第四节默认样式的行为属于文档即契约的最佳实践组件的公开行为由测试回归保护。六、完整的CanvasProps类型与跨端支持虽然taro-canvas-core只负责 H5/harmony_hybrid 的渲染但业务侧使用的Canvas /类型定义在 packages/taro-components/types/Canvas.d.ts 中更完整其中包含了各端能力差异的supported标注属性说明支持端type指定 canvas 类型支持2d和webglweapp, alipay, tt, ascfcanvasIdcanvas 组件唯一标识符指定了type则无需再指定weapp, swan, tt, qq, jd, h5, harmony_hybrid, ascfdisableScrollcanvas 中移动且有手势绑定时禁止屏幕滚动与下拉刷新默认falseweapp, alipay, swan, qq, jd, ascfid组件唯一标识符同一页面中不可重复alipay, h5, harmony_hybridwidth/height画布宽高alipay, h5, harmony_hybridnativeProps透传到内部 H5 标签h5, harmony_hybridonTouchStart/onTouchMove/onTouchEnd/onTouchCancel触摸生命周期事件weapp, alipay, swan, tt, qq, jd, h5, harmony_hybrid, ascfonLongTap长按 500ms 触发weapp, alipay, swan, qq, jd, h5, harmony_hybrid, ascfonError错误事件detail { errMsg: something wrong }weapp, swan, qq, jd, ascfonTap/onReady点击 / 初始化成功alipay此外类型注释明确说明Canvas /组件的RN 版本尚未实现RN 版本尚未实现且组件分类为canvas。因此在使用时需注意Canvas 能力在 H5、各小程序平台与 harmony_hybrid 上可用但不可用于 RN 端。七、实际使用示例React 用法import { Canvas } from tarojs/components class App extends Component { render () { // 支付宝小程序需额外加上 id 属性值与 canvasId 一致 return ( Canvas stylewidth: 300px; height: 200px; canvasIdcanvas / ) } }Vue3 用法template !-- 如果是支付宝小程序则要加上 id 属性值和 canvasId 一致 -- canvas stylewidth: 300px; height: 200px; canvas-idcanvas / /template两个示例均摘自 packages/taro-components/types/Canvas.d.ts 的example_react与example_vue注释是官方推荐的起始写法。在此基础上H5 端可通过nativeProps透传自定义属性并通过onLongTap监听长按手势例如实现长按画布弹出颜色选择器或长按删除图层等交互。八、小结taro-canvas-core虽然是一个仅百余行的组件但它完整呈现了 Taro H5 组件体系中 Web Components 封装的几个核心范式属性映射canvasId↔id↔canvas-id、尺寸双向同步CSS 显示尺寸与位图分辨率分离componentDidRender兜底回填、透传机制nativeProps展开到内部节点以及手势事件实现500ms 定时器 移动/中断即取消的长按判定。配合 canvas.spec.tsx 与 canvas.e2e.ts 的回归测试其公开行为形成了完整闭环。在需要为 H5/harmony_hybrid 实现绘图、签名、图表等画布能力的场景中理解本组件的 API 契约与底层实现能够帮助开发者避免尺寸模糊、长按误触发等常见问题。【免费下载链接】taro开放式跨端跨框架解决方案支持使用 React/Vue 等框架来开发微信/京东/百度/支付宝/字节跳动/ QQ 小程序/H5/React Native 等应用。项目地址: https://gitcode.com/gh_mirrors/tar/taro创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表