البداية السريعة
التثبيت
pnpm add @dopejs/pingoيعتمد تطبيقك على حزمة واحدة فقط هي @dopejs/pingo. أمّا @dopejs/pingo-host و@dopejs/pingo-jsx وغيرهما فهي حزم تنفيذ داخلية خارج العقد العلني، وماسح الترحيل يرفض استيرادها مباشرة.
تركيب أوّل canvas
import { createElement, createHostedCanvasRoot } from "@dopejs/pingo";
const canvas = document.querySelector<HTMLCanvasElement>("#app")!;
canvas.width = 800;
canvas.height = 600;
const root = await createHostedCanvasRoot(canvas);
root.render(
createElement("container", {
width: 800,
height: 600,
backgroundColor: "#ffffffff",
padding: 24,
children: createElement("text", {
value: "Hello doper",
fontSize: 24,
lineHeight: 32,
color: "#1f2329ff",
}),
}),
);تكتشف createHostedCanvasRoot قدرات المتصفّح وتختار مسار النقل بين SharedArrayBuffer وpostMessage وCanvas2D على الخيط الرئيسي، فلا تحتاج إلى كتابة تفرّعات من أجل التراجع. وتعيد root.mode المسار الذي جرى اختياره فعلًا.
استخدام TSX
اضبط tsconfig.json:
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@dopejs/pingo"
}
}عندها يمكنك أن تكتب:
function OrderRow({ index }: { index: number }) {
return (
<container width={480} height={32} padding={[6, 12, 6, 12]}>
<text value={`الطلب رقم ${index}`} fontSize={13} lineHeight={20} />
</container>
);
}
root.render(<OrderRow index={1} />);عناصر المضيف
في المحرّك خمسة عناصر مدمجة فقط، وكلّها تقابل عقد Scene مباشرة؛ لا تتالي CSS ولا محدِّدات.
| العنصر | الغرض |
|---|---|
container | تجميع عام وخلفية وحشو داخلي وتحويلات |
text | مقطع نصّي (التشكيل والالتفاف وهندسة المؤشّر من النواة) |
scroll | حاوية قابلة للتمرير تملكها النواة |
virtualList | قائمة افتراضية تخطّط النواة نافذتها |
editableText | بدائية النصّ القابل للتحرير |
أمّا TextField وTextArea فهما عنصران مركَّبان فوق editableText (إطار وحالة خطأ) ولا يُدخلان أيّ مسار إدخال جديد.
الحالة والتأثيرات الجانبية
import { signal, useEffect, useSignal, useState } from "@dopejs/pingo";
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => setCount((value) => value + 1), 1000);
return () => clearInterval(timer);
}, []);
return createElement("text", { value: `مرّت ${count} ثانية` });
}البدائيات التفاعلية المتاحة: signal وcomputed وeffect وbatch وuntracked، إضافةً إلى الخطّافات useState وuseSignal وuseMemo وuseCallback وuseRef وuseEffect.
لا قراءة متزامنة للتخطيط
القراءة المتزامنة لتخطيط الـ Worker على طريقة useLayoutEffect غير مدعومة، لأنّ التخطيط يجري على ساعة أخرى. استخدم العقد اللامتزامن عند الحاجة إلى نتيجة التخطيط، ولا تحاول قراءة الهندسة بشكل متزامن أثناء العرض.
مراقبة السلوك أثناء التشغيل
const root = await createHostedCanvasRoot(canvas, {
onFrame: (report) => {
console.log(report.commands, report.displayListBytes, report.core?.sceneNodes);
},
onHostError: (error) => report(error),
});تعطي onFrame في كلّ إطار عدد الأوامر وحجم DisplayList بالبايت، ومن جهة النواة عدّادات العقد المتّسخة وحجم عمل التخطيط وبصمة picture؛ وهي المصدر الأوّل لتحليل الأداء. للمزيد انظر التشخيص.
الخطوة التالية
- نظرة عامة على البنية: كيف يقتسم الغلاف والنواة العمل
- التمرير الافتراضي والنصّ والتحرير
- Playground: عروض حيّة قابلة للتفاعل