مكتبة DOM الظاهرية مع التركيز على البساطة والنموذجية والميزات القوية والأداء.
بفضل Browserstack لتوفير الوصول إلى أدوات اختبار المتصفح الرائعة.
الإنجليزية | 简体中文 | الهندية
دوم الافتراضي رائع. إنها تتيح لنا التعبير عن وجهة نظرنا كدالة لحالتها. لكن الحلول الحالية كانت متضخمة للغاية ، وبطيئة للغاية ، وتفتقر إلى الميزات ، وكان لها واجهة برمجة تطبيقات متحيزة تجاه OOP ، و/أو تفتقر إلى الميزات التي احتاجها.
يتكون Snabbdom من جوهر بسيط للغاية وأداء وقابل للتمديد والذي لا يزيد عن 200 SLOC. إنه يوفر بنية معيارية مع وظائف غنية للتمديدات من خلال وحدات مخصصة. للحفاظ على البساطة الأساسية ، يتم تفويض جميع الوظائف غير الضرورية إلى الوحدات النمطية.
يمكنك صب snabbdom في كل ما تريد! اختر واختيار وتخصيص الوظائف التي تريدها. بدلاً من ذلك ، يمكنك فقط استخدام الامتدادات الافتراضية والحصول على مكتبة DOM الظاهرية ذات الأداء العالي والحجم الصغير وجميع الميزات المذكورة أدناه.
h وظيفة لإنشاء عقد DOM الظاهرية بسهولة.h Helper. import {
init ,
classModule ,
propsModule ,
styleModule ,
eventListenersModule ,
h
} from "snabbdom" ;
const patch = init ( [
// Init patch function with chosen modules
classModule , // makes it easy to toggle classes
propsModule , // for setting properties on DOM elements
styleModule , // handles styling on elements with support for animations
eventListenersModule // attaches event listeners
] ) ;
const container = document . getElementById ( "container" ) ;
const vnode = h (
"div#container.two.classes" ,
{ on : { click : ( ) => console . log ( "div clicked" ) } } ,
[
h ( "span" , { style : { fontWeight : "bold" } } , "This is bold" ) ,
" and this is just normal text" ,
h ( "a" , { props : { href : "/foo" } } , "I'll take you places!" )
]
) ;
// Patch into empty DOM element – this modifies the DOM as a side effect
patch ( container , vnode ) ;
const newVnode = h (
"div#container.two.classes" ,
{ on : { click : ( ) => console . log ( "updated div clicked" ) } } ,
[
h (
"span" ,
{ style : { fontWeight : "normal" , fontStyle : "italic" } } ,
"This is now italic type"
) ,
" and this is still just normal text" ,
h ( "a" , { props : { href : "/bar" } } , "I'll take you places!" )
]
) ;
// Second `patch` invocation
patch ( vnode , newVnode ) ; // Snabbdom efficiently updates the old view to the new state initpatchhfragment (تجريبي)toVNodeinitinsertremove الخطافdestroyremovedestroyيوفر جوهر Snabbdom فقط الوظائف الأكثر أهمية. إنه مصمم ليكون بسيطًا قدر الإمكان بينما لا يزال سريعًا وقابلًا للتمديد.
init الكوور يعرض وظيفة واحدة فقط init . يأخذ هذا init قائمة بالوحدات النمطية ويعيد وظيفة patch التي تستخدم مجموعة الوحدات النمطية المحددة.
import { classModule , styleModule } from "snabbdom" ;
const patch = init ( [ classModule , styleModule ] ) ;patch وظيفة patch التي تم إرجاعها بواسطة init تأخذ وسيطتين. الأول هو عنصر dom أو vnode يمثل العرض الحالي. والثاني هو vnode يمثل العرض الجديد المحدث.
إذا تم تمرير عنصر DOM مع أحد الوالدين ، فسيتم تحويل newVnode إلى عقدة DOM ، وسيتم استبدال العنصر الذي تم تمريره بعقدة DOM التي تم إنشاؤها. إذا تم تمرير Vnode القديم ، فسيقوم Snabbdom بتعديله بكفاءة لمطابقة الوصف في Vnode الجديد.
يجب أن يكون أي vnode القديم الذي تم تمريره هو vnode الناتج من مكالمة سابقة إلى patch . هذا ضروري لأن Snabbdom يخزن المعلومات في Vnode. هذا يجعل من الممكن تنفيذ بنية أبسط وأكثر أداء. هذا يتجنب أيضًا إنشاء شجرة Vnode القديمة الجديدة.
patch ( oldVnode , newVnode ) ; على الرغم من عدم وجود API خصيصًا لإزالة شجرة Vnode من عنصر Mount Point الخاص بها ، إلا أن إحدى طرق تحقيق ذلك تقريبًا هي توفير تعليق vnode كوسيطة ثانية patch ، مثل:
patch (
oldVnode ,
h ( "!" , {
hooks : {
post : ( ) => {
/* patch complete */
}
}
} )
) ;بالطبع ، إذن لا تزال هناك عقدة تعليق واحدة في جبل بوينت.
h يوصى باستخدام h لإنشاء vnodes. يقبل علامة/محدد كسلسلة ، وكائن بيانات اختياري ، وسلسلة اختيارية أو مجموعة من الأطفال.
import { h } from "snabbdom" ;
const vnode = h ( "div#container" , { style : { color : "#000" } } , [
h ( "h1.primary-title" , "Headline" ) ,
h ( "p" , "A paragraph" )
] ) ;fragment (تجريبي)تحذير: هذه الميزة تجريبية حاليًا ويجب اختيارها. قد يتم تغيير واجهة برمجة التطبيقات الخاصة به بدون عثرة إصدار رئيسية.
const patch = init ( modules , undefined , {
experimental : {
fragments : true
}
} ) ;ينشئ عقدة افتراضية سيتم تحويلها إلى جزء مستند يحتوي على الأطفال المعينين.
import { fragment , h } from "snabbdom" ;
const vnode = fragment ( [ "I am" , h ( "span" , [ " a" , " fragment" ] ) ] ) ;toVNodeيحول عقدة DOM إلى عقدة افتراضية. مفيد بشكل خاص للتصحيح على محتوى HTML الذي تم إنشاؤه من جانب الخادم.
import {
init ,
styleModule ,
attributesModule ,
h ,
toVNode
} from "snabbdom" ;
const patch = init ( [
// Initialize a `patch` function with the modules used by `toVNode`
attributesModule // handles attributes from the DOM node
datasetModule , // handles `data-*` attributes from the DOM node
] ) ;
const newVNode = h ( "div" , { style : { color : "#000" } } , [
h ( "h1" , "Headline" ) ,
h ( "p" , "A paragraph" ) ,
h ( "img" , { attrs : { src : "sunrise.png" , alt : "morning sunrise" } } )
] ) ;
patch ( toVNode ( document . querySelector ( ".container" ) ) , newVNode ) ;السنانير هي وسيلة لربط دورة حياة العقد DOM. يقدم Snabbdom مجموعة غنية من السنانير. يتم استخدام السنانير بواسطة وحدات لتمديد Snabbdom ، وفي التعليمات البرمجية العادية لتنفيذ التعليمات البرمجية التعسفية في النقاط المطلوبة في حياة العقدة الافتراضية.
| اسم | نشأت عندما | الحجج إلى رد الاتصال |
|---|---|---|
pre | تبدأ عملية التصحيح | لا أحد |
init | تمت إضافة vnode | vnode |
create | تم إنشاء عنصر DOM بناءً على vnode | emptyVnode, vnode |
insert | تم إدخال عنصر في DOM | vnode |
prepatch | عنصر على وشك أن يتم تصحيحه | oldVnode, vnode |
update | يتم تحديث عنصر | oldVnode, vnode |
postpatch | تم تصحيح عنصر | oldVnode, vnode |
destroy | يتم إزالة عنصر مباشرة أو غير مباشر | vnode |
remove | تتم إزالة عنصر مباشرة من DOM | vnode, removeCallback |
post | تتم عملية التصحيح | لا أحد |
السنانير التالية متاحة للوحدات النمطية: pre ، create ، update ، destroy ، remove ، post .
تتوفر السنانير التالية في خاصية hook للعناصر الفردية: init ، create ، insert ، prepatch ، update ، postpatch ، destroy ، remove .
لاستخدام السنانير ، مررها ككائن hook حقل وسيطة كائن البيانات.
h ( "div.row" , {
key : movie . rank ,
hook : {
insert : ( vnode ) => {
movie . elmHeight = vnode . elm . offsetHeight ;
}
}
} ) ; initيتم استدعاء هذا الخطاف أثناء عملية التصحيح عند العثور على عقدة افتراضية جديدة. يتم استدعاء الخطاف قبل أن يعالج Snabbdom العقدة بأي شكل من الأشكال. أي قبل أن تنشئ عقدة DOM استنادًا إلى Vnode.
insertيتم استدعاء هذا الخطاف بمجرد إدراج عنصر DOM لـ Vnode في المستند ويتم بقية دورة التصحيح. هذا يعني أنه يمكنك إجراء قياسات DOM (مثل استخدام GetBoundingClientRect في هذا الخطاف بأمان ، مع العلم أنه لن يتم تغيير أي عناصر بعد ذلك يمكن أن تؤثر على موضع العناصر المدرجة.
remove الخطاف يسمح لك بالتوصيل في إزالة عنصر ما. يتم استدعاء الخطاف بمجرد إزالة vnode من DOM. تستقبل وظيفة المناولة كلاً من Vnode و Pallback. يمكنك التحكم في الإزالة وتأخيرها باستخدام رد الاتصال. يجب أن يتم استدعاء رد الاتصال بمجرد الانتهاء من القيام بعمله ، وسيتم إزالة العنصر فقط بمجرد remove جميع السنانير عن رد الاتصال.
يتم تشغيل الخطاف فقط عندما يتم إزالة عنصر ما من والديه - ليس إذا كان طفل عنصر يتم إزالته. لذلك ، انظر خطاف destroy .
destroyيتم استدعاء هذا الخطاف على عقدة افتراضية عند إزالة عنصر DOM الخاص به من DOM أو إذا تمت إزالة الوالد من DOM.
لمعرفة الفرق بين هذا الخطاف remove ، فكر في مثال.
const vnode1 = h ( "div" , [ h ( "div" , [ h ( "span" , "Hello" ) ] ) ] ) ;
const vnode2 = h ( "div" , [ ] ) ;
patch ( container , vnode1 ) ;
patch ( vnode1 , vnode2 ) ; يتم تشغيل destroy هنا لكل من عنصر div الداخلي وعنصر span الذي يحتوي عليه. remove ، من ناحية أخرى ، يتم تشغيلها فقط على عنصر div لأنه العنصر الوحيد الذي يتم فصله عن والده.
يمكنك ، على سبيل المثال ، استخدام remove الرسوم المتحركة عند إزالة عنصر ما واستخدام خطاف destroy لتحريك اختفاء أطفال العنصر الذي تمت إزالته بالإضافة إلى ذلك.
تعمل الوحدات النمطية عن طريق تسجيل المستمعين العالميين على السنانير. الوحدة النمطية هي ببساطة أسماء ربط القاموس إلى وظائف.
const myModule = {
create : ( oldVnode , vnode ) => {
// invoked whenever a new virtual node is created
} ,
update : ( oldVnode , vnode ) => {
// invoked whenever a virtual node is updated
}
} ;مع هذه الآلية ، يمكنك بسهولة زيادة سلوك Snabbdom. للمظاهرة ، ألق نظرة على تطبيقات الوحدات الافتراضية.
هذا يصف الوحدات الأساسية. جميع الوحدات اختيارية. تفترض أمثلة JSX أنك تستخدم jsx Pragma المقدمة من هذه المكتبة.
توفر وحدة الفئة طريقة سهلة لتبديل الفصول ديناميكيًا على العناصر. يتوقع كائن في خاصية بيانات class . يجب أن يقوم الكائن بتخطيط أسماء الفصول إلى المنطقيات التي تشير إلى ما إذا كان يجب أن يبقى الفصل أم لا أو يذهب على Vnode.
h ( "a" , { class : { active : true , selected : false } } , "Toggle" ) ; في JSX ، يمكنك استخدام class مثل هذا:
< div class = { { foo : true , bar : true } } />
// Renders as: <div class="foo bar"></div>يسمح لك بتعيين خصائص على عناصر DOM.
h ( "a" , { props : { href : "/foo" } } , "Go to Foo" ) ; في JSX ، يمكنك استخدام props مثل هذا:
< input props = { { name : "foo" } } />
// Renders as: <input name="foo" /> with input.name === "foo"يمكن تعيين الخصائص فقط. لم تتم إزالتها. على الرغم من أن المتصفحات تسمح بإضافة وحذف الخصائص المخصصة ، إلا أن الحذف لن تتم تجربته بواسطة هذه الوحدة. هذا أمر منطقي ، لأنه لا يمكن إزالة خصائص DOM الأصلية. وإذا كنت تستخدم خصائص مخصصة لتخزين القيم أو الرجوع إلى الكائنات على DOM ، فيرجى التفكير في استخدام سمات البيانات-بدلاً من ذلك. ربما عبر وحدة مجموعة البيانات.
مثل الدعائم ، ولكن تعيين سمات بدلاً من الخصائص على عناصر DOM.
h ( "a" , { attrs : { href : "/foo" } } , "Go to Foo" ) ; في JSX ، يمكنك استخدام attrs مثل هذا:
< div attrs = { { "aria-label" : "I'm a div" } } />
// Renders as: <div aria-label="I'm a div"></div> تتم إضافة السمات وتحديثها باستخدام setAttribute . في حالة وجود سمة تمت إضافتها/تعيينها مسبقًا ولم تعد موجودة في كائن attrs ، تتم إزالتها من قائمة سمات عنصر DOM باستخدام removeAttribute .
في حالة السمات المنطقية (على سبيل المثال ، disabled ، hidden ، selected ...) ، لا يعتمد المعنى على قيمة السمة ( true أو false ) ولكنه يعتمد بدلاً من ذلك على وجود/عدم وجود السمة نفسها في عنصر DOM. يتم التعامل مع هذه السمات بشكل مختلف بواسطة الوحدة النمطية: إذا تم تعيين سمة منطقية على قيمة falsy ( 0 ، -0 ، null ، false ، NaN ، undefined ، أو السلسلة الفارغة ( "" )) ، فسيتم إزالة السمة من قائمة السمة لعنصر DOM.
يسمح لك بتعيين سمات بيانات مخصصة ( data-* ) على عناصر DOM. يمكن بعد ذلك الوصول إليها باستخدام خاصية htmlelement.dataset.
h ( "button" , { dataset : { action : "reset" } } , "Reset" ) ; في JSX ، يمكنك استخدام dataset مثل هذا:
< div dataset = { { foo : "bar" } } />
// Renders as: <div data-foo="bar"></div>وحدة النمط هي لجعل HTML تبدو البقعة والحيوية بسلاسة. في جوهره يتيح لك تعيين خصائص CSS على العناصر.
h (
"span" ,
{
style : {
border : "1px solid #bada55" ,
color : "#c0ffee" ,
fontWeight : "bold"
}
} ,
"Say my name, and every colour illuminates"
) ; في JSX ، يمكنك استخدام style مثل هذا:
< div
style = { {
border : "1px solid #bada55" ,
color : "#c0ffee" ,
fontWeight : "bold"
} }
/>
// Renders as: <div style="border: 1px solid #bada55; color: #c0ffee; font-weight: bold"></div> يتم دعم خصائص CSS المخصصة (المعروفة أيضًا باسم متغيرات CSS) ، ويجب أن تكون مسبوقة بـ --
h (
"div" ,
{
style : { "--warnColor" : "yellow" }
} ,
"Warning"
) ; يمكنك تحديد الخصائص على أنها تأخير. كلما تغيرت هذه الخصائص ، لا يتم تطبيق التغيير إلا بعد الإطار التالي.
h (
"span" ,
{
style : {
opacity : "0" ,
transition : "opacity 1s" ,
delayed : { opacity : "1" }
}
} ,
"Imma fade right in!"
) ;هذا يجعل من السهل تنشيط دخول العناصر.
لا يتم دعم all قيمة transition-property .
remove سوف تسري الأنماط التي تم تعيينها في خاصية remove بمجرد أن تتم إزالتها من DOM. يجب أن تكون الأنماط المطبقة متحركة مع انتقالات CSS. بمجرد الانتهاء من جميع الأنماط ، سيتم إزالة العنصر من DOM.
h (
"span" ,
{
style : {
opacity : "1" ,
transition : "opacity 1s" ,
remove : { opacity : "0" }
}
} ,
"It's better to fade out than to burn away"
) ;هذا يجعل من السهل تنشيط إزالة العناصر.
لا يتم دعم all قيمة transition-property .
destroy h (
"span" ,
{
style : {
opacity : "1" ,
transition : "opacity 1s" ,
destroy : { opacity : "0" }
}
} ,
"It's better to fade out than to burn away"
) ; لا يتم دعم all قيمة transition-property .
توفر وحدة مستمعي الأحداث إمكانات قوية لإرفاق مستمعي الأحداث.
يمكنك إرفاق وظيفة بحدث على Vnode من خلال تزويد on مع خاصية تتوافق مع اسم الحدث الذي تريد الاستماع إليه. سيتم استدعاء الوظيفة عندما يحدث الحدث وسيتم نقله إلى كائن الحدث الذي ينتمي إليه.
function clickHandler ( ev ) {
console . log ( "got clicked" ) ;
}
h ( "div" , { on : { click : clickHandler } } ) ; في JSX ، يمكنك on مثل هذا:
< div on = { { click : clickHandler } } />يسمح Snabbdom بمبادلة معالجات الأحداث بين العروض. يحدث هذا دون لمس معالجات الأحداث المرتبطة بـ DOM.
لاحظ ، مع ذلك ، أنه يجب أن تكون حذراً عند مشاركة معالجات الأحداث بين VNODES ، نظرًا للتقنية التي تستخدمها هذه الوحدة لتجنب إعادة ربط معالجات الأحداث إلى DOM. (وبشكل عام ، لا يضمن مشاركة البيانات بين VNODES العمل ، لأنه يُسمح للوحدات النمطية بتطوير البيانات المحددة).
على وجه الخصوص ، يجب ألا تفعل شيئًا كهذا:
// Does not work
const sharedHandler = {
change : ( e ) => {
console . log ( "you chose: " + e . target . value ) ;
}
} ;
h ( "div" , [
h ( "input" , {
props : { type : "radio" , name : "test" , value : "0" } ,
on : sharedHandler
} ) ,
h ( "input" , {
props : { type : "radio" , name : "test" , value : "1" } ,
on : sharedHandler
} ) ,
h ( "input" , {
props : { type : "radio" , name : "test" , value : "2" } ,
on : sharedHandler
} )
] ) ; بالنسبة للعديد من هذه الحالات ، يمكنك استخدام المعالجات المستندة إلى المصفوفة بدلاً من ذلك (الموضحة أعلاه). بدلاً من ذلك ، تأكد من تمرير كل عقدة فريدة من نوعها on القيم:
// Works
const sharedHandler = ( e ) => {
console . log ( "you chose: " + e . target . value ) ;
} ;
h ( "div" , [
h ( "input" , {
props : { type : "radio" , name : "test" , value : "0" } ,
on : { change : sharedHandler }
} ) ,
h ( "input" , {
props : { type : "radio" , name : "test" , value : "1" } ,
on : { change : sharedHandler }
} ) ,
h ( "input" , {
props : { type : "radio" , name : "test" , value : "2" } ,
on : { change : sharedHandler }
} )
] ) ; يعمل SVG فقط عند استخدام وظيفة h لإنشاء العقد الافتراضية. يتم إنشاء عناصر SVG تلقائيًا مع مساحات الأسماء المناسبة.
const vnode = h ( "div" , [
h ( "svg" , { attrs : { width : 100 , height : 100 } } , [
h ( "circle" , {
attrs : {
cx : 50 ,
cy : 50 ,
r : 40 ,
stroke : "green" ,
"stroke-width" : 4 ,
fill : "yellow"
}
} )
] )
] ) ;انظر أيضًا مثال SVG ومثال SVG Carousel.
لا تدعم بعض المتصفحات (مثل IE <= 11) خاصية classList في عناصر SVG. نظرًا لأن وحدة الفئة تستخدم classList داخليًا ، فلن تعمل في هذه الحالة إلا إذا كنت تستخدم Polyfill. (إذا كنت لا ترغب في استخدام polyfill ، فيمكنك استخدام سمة class مع وحدة السمات ).
تأخذ وظيفة thunk محددًا ، ومفتاحًا لتحديد thunk ، ودالة تُرجع vnode وكمية متغيرة من معلمات الحالة. إذا تم الاحتجاج بها ، فستتلقى وظيفة العرض حجج الحالة.
thunk(selector, key, renderFn, [stateArguments])
يتم استدعاء renderFn فقط إذا تم تغيير renderFn أو [stateArguments] طول صفيف أو تم تغيير عناصره.
key اختياري. يجب توفيره عندما يكون selector فريدًا بين أشقاء ثونكس. هذا يضمن أن يتم مطابقة thunk دائمًا بشكل صحيح عند الانتشار.
Thunks هي استراتيجية تحسين يمكن استخدامها عندما يتعامل المرء مع البيانات غير القابلة للتغيير.
فكر في وظيفة بسيطة لإنشاء عقدة افتراضية بناءً على رقم.
function numberView ( n ) {
return h ( "div" , "Number is: " + n ) ;
} يعتمد العرض فقط على n . هذا يعني أنه إذا لم يتغير n ، فإن إنشاء عقدة DOM الظاهرية وتصحيحها مقابل vnode القديم يكون مضيئًا. لتجنب النفقات العامة ، يمكننا استخدام وظيفة المساعد thunk .
function render ( state ) {
return thunk ( "num" , numberView , [ state . number ] ) ;
} بدلاً من استدعاء وظيفة numberView في الواقع ، سيضع هذا فقط Vnode دمية في الشجرة الافتراضية. عندما يقوم Snabbdom بتصحيح هذا vnode الوهمية مقابل vnode السابق ، فإنه سيقارن قيمة n . إذا لم يتغير n ، فسيقوم ببساطة بإعادة استخدام Vnode القديم. هذا يتجنب إعادة إنشاء عرض الأرقام وعملية الاختلاف تمامًا.
وظيفة العرض هنا ليست سوى مثال. في الممارسة العملية ، تكون Thunks ذات صلة فقط إذا كنت تقوم بتقديم وجهة نظر معقدة تتطلب وقتًا حسابيًا كبيرًا لتوليدها.
لاحظ أن شظايا JSX لا تزال تجريبية ويجب اختيارها. انظر قسم fragment للحصول على التفاصيل.
أضف الخيارات التالية إلى tsconfig.json :
{
"compilerOptions" : {
"jsx" : " react " ,
"jsxFactory" : " jsx " ,
"jsxFragmentFactory" : " Fragment "
}
} ثم تأكد من استخدام ملحق ملف .tsx واستيراد وظيفة jsx ووظيفة Fragment في الجزء العلوي من الملف:
import { Fragment , jsx , VNode } from "snabbdom" ;
const node : VNode = (
< div >
< span > I was created with JSX </ span >
</ div >
) ;
const fragment : VNode = (
< >
< span > JSX fragments </ span >
are experimentally supported
</ >
) ;أضف الخيارات التالية إلى تكوين بابل الخاص بك:
{
"plugins" : [
[
" @babel/plugin-transform-react-jsx " ,
{
"pragma" : " jsx " ,
"pragmaFrag" : " Fragment "
}
]
]
} ثم استيراد وظيفة jsx ووظيفة Fragment في الجزء العلوي من الملف:
import { Fragment , jsx } from "snabbdom" ;
const node = (
< div >
< span > I was created with JSX </ span >
</ div >
) ;
const fragment = (
< >
< span > JSX fragments </ span >
are experimentally supported
</ >
) ; ملكيات
تحدد خاصية sel عنصر HTML من VNode ، اختياريا id المسبق بواسطة # ، والصفر أو أكثر فئات كل ما قبل . . بناء الجملة مستوحى من محددات CSS. فيما يلي بعض الأمثلة:
div#container.bar.baz - عنصر div مع container المعرف bar الفئات baz .li - عنصر li مع عدم وجود id ولا فصول.button.alert.primary - عنصر button مع alert الفئتين و primary . من المفترض أن يكون المحدد ثابتًا ، أي أنه لا ينبغي أن يتغير على مدى عمر العنصر. لتعيين id ديناميكي ، استخدم وحدة الدعائم ولتعيين الفئات الديناميكية ، استخدم وحدة الفئة.
نظرًا لأن المحدد ثابت ، فإن Snabbdom يستخدمه كجزء من هوية Vnodes. على سبيل المثال ، إذا كان الطفل vnodes
[ h ( "div#container.padding" , children1 ) , h ( "div.padding" , children2 ) ] ;مصححة ضد
[ h ( "div#container.padding" , children2 ) , h ( "div.padding" , children1 ) ] ;ثم يستخدم Snabbdom المحدد لتحديد vNodes وإعادة ترتيبها في شجرة DOM بدلاً من إنشاء عنصر DOM جديد. يتجنب استخدام المختارين هذا الحاجة إلى تحديد المفاتيح في كثير من الحالات.
خاصية .data للعقدة الافتراضية هي المكان المناسب لإضافة معلومات للوحدات النمطية للوصول إلى عنصر DOM الحقيقي ومعالجته عند إنشاؤه ؛ أضف الأنماط ، فئات CSS ، السمات ، إلخ.
كائن البيانات هو المعلمة الثانية (الاختيارية) إلى h()
على سبيل المثال h('div', {props: {className: 'container'}}, [...]) ستنتج عقدة افتراضية مع
( {
props : {
className : "container"
}
} ) ; ككائن .data .
h() .children .children
على سبيل المثال h('div', {}, [ h('h1', {}, 'Hello, World') ])
[
{
sel : "h1" ,
data : { } ,
children : undefined ,
text : "Hello, World" ,
elm : Element ,
key : undefined
}
] ; كما .children .
يتم إنشاء خاصية .text عند إنشاء عقدة افتراضية مع طفل واحد فقط يمتلك نصًا ويتطلب فقط document.createTextNode() لاستخدامه.
على سبيل المثال: h('h1', {}, 'Hello') ستقوم بإنشاء عقدة افتراضية مع Hello as sterment .text .
خاصية .elm للعقدة الافتراضية هي مؤشر لعقدة DOM الحقيقية التي تم إنشاؤها بواسطة Snabbdom. هذه الخاصية مفيدة للغاية لإجراء الحسابات في السنانير وكذلك الوحدات النمطية.
يتم إنشاء خاصية .key عند توفير مفتاح داخل كائن .data الخاص بك. يتم استخدام خاصية .key للحفاظ على المؤشرات لعقد DOM التي كانت موجودة سابقًا لتجنب إعادة إنشاءها إذا كانت غير ضرورية. هذا مفيد جدًا لأشياء مثل إعادة ترتيب قائمة. يجب أن يكون المفتاح إما سلسلة أو رقم للسماح بالبحث السليم حيث يتم تخزينه داخليًا كزوج مفتاح/قيمة داخل كائن ، حيث .key هو المفتاح والقيمة هي خاصية .elm .
إذا تم توفيره ، يجب أن تكون خاصية .key فريدة بين عناصر الأخوة.
على سبيل المثال: h('div', {key: 1}, []) ستقوم بإنشاء كائن عقدة افتراضية مع خاصية .key بقيمة 1 .
Snabbdom هي مكتبة DOM الظاهرية منخفضة المستوى. إنه غير معقول فيما يتعلق بكيفية تنظيم تطبيقك.
فيما يلي بعض الأساليب لبناء التطبيقات مع Snabbdom.
تأكد من مشاركته إذا كنت تقوم ببناء تطبيق بطريقة أخرى باستخدام Snabbdom.
يجب وضع علامة على الحزم المتعلقة بـ Snabbdom مع الكلمة الرئيسية snabbdom ونشرها على NPM. يمكن العثور عليها باستخدام keywords:snabbdom .
Uncaught NotFoundError: Failed to execute 'insertBefore' on 'Node':
The node before which the new node is to be inserted is not a child of this node.
سبب هذا الخطأ هو إعادة استخدام VNodes بين التصحيحات (انظر مثال الرمز) ، يقوم Snabbdom بتخزين عقد DOM الفعلية داخل عقد DOM الافتراضية التي تم تمريرها إليها كتحسين في الأداء ، لذلك لا يتم إعادة استخدام العقد بين البقع.
const sharedNode = h ( "div" , { } , "Selected" ) ;
const vnode1 = h ( "div" , [
h ( "div" , { } , [ "One" ] ) ,
h ( "div" , { } , [ "Two" ] ) ,
h ( "div" , { } , [ sharedNode ] )
] ) ;
const vnode2 = h ( "div" , [
h ( "div" , { } , [ "One" ] ) ,
h ( "div" , { } , [ sharedNode ] ) ,
h ( "div" , { } , [ "Three" ] )
] ) ;
patch ( container , vnode1 ) ;
patch ( vnode1 , vnode2 ) ;يمكنك إصلاح هذه المشكلة عن طريق إنشاء نسخة ضحلة من الكائن (هنا مع بناء جملة نشر الكائن):
const vnode2 = h ( "div" , [
h ( "div" , { } , [ "One" ] ) ,
h ( "div" , { } , [ { ... sharedNode } ] ) ,
h ( "div" , { } , [ "Three" ] )
] ) ;حل آخر هو لف vnodes المشتركة في وظيفة المصنع:
const sharedNode = ( ) => h ( "div" , { } , "Selected" ) ;
const vnode1 = h ( "div" , [
h ( "div" , { } , [ "One" ] ) ,
h ( "div" , { } , [ "Two" ] ) ,
h ( "div" , { } , [ sharedNode ( ) ] )
] ) ; يجب أن يتم دمج طلبات السحب التي قد يهتم بها المجتمع بتقديم ملاحظات عليها بعد هذه الفرصة لبضعة أيام.