في المادة ، التي ننشر ترجمتها اليوم ، سنتحدث عن كيفية إنشاء شبكة طباعة لنظام التصميم باستخدام
وظائف عرض Vue .
هنا عرض تجريبي للمشروع الذي سنراجعه هنا.
يمكنك أن تجد رمزها هنا. يقول مؤلف هذه المادة إنه استخدم وظائف التجسيد نظرًا لحقيقة أنها تتيح تحكمًا أكثر دقة في عملية إنشاء تعليمات HTML البرمجية من قوالب Vue العادية. ومع ذلك ، لمفاجأته ، لم يستطع العثور على أمثلة عملية لتطبيقهم. لقد صادف كتيبات التعليمات فقط. إنه يأمل في أن تحدث هذه المادة فرقًا للأفضل بفضل المثال العملي لاستخدام وظائف تقديم Vue.
تقديم وظائف Vue
تبدو وظائف العرض دائمًا بالنسبة لي شيئًا غير معتاد بالنسبة لـ Vue. كل شيء في هذا الإطار يشدد على الرغبة في البساطة وفصل واجبات مختلف الكيانات. لكن وظائف التجسيد هي مزيج غريب من HTML و JavaScript ، وغالبًا ما يصعب قراءتها.
على سبيل المثال ، إليك علامة HTML:
<div class="container"> <p class="my-awesome-class">Some cool text</p> </div>
لتكوينها ، تحتاج إلى الوظيفة التالية:
render(createElement) { return createElement("div", { class: "container" }, [ createElement("p", { class: "my-awesome-class" }, "Some cool text") ]) }
أظن أن مثل هذه الإنشاءات ستجعل الكثيرين يتحولون على الفور عن وظائف العرض. بعد كل شيء ، سهولة الاستخدام هي بالضبط ما يجذب المطورين إلى Vue. إنه لأمر مؤسف إذا كان الكثير من الناس لا يرون مزاياهم الحقيقية وراء المظهر القبيح لوظائف العرض. الشيء هو أن تقديم وظائف والمكونات الوظيفية هي أدوات مثيرة للاهتمام وقوية. من أجل إظهار قدراتهم وقيمتهم الحقيقية ، سأتحدث عن كيف ساعدوني في حل المشكلة الحقيقية.
يرجى ملاحظة أنه سيكون من المفيد للغاية فتح
نسخة تجريبية من المشروع قيد النظر في علامة تبويب المتصفح المجاورة والوصول إليها أثناء قراءة مقال.
تحديد المعايير لنظام التصميم
لدينا نظام تصميم يعتمد على
VuePress . نحن بحاجة إلى تضمين صفحة جديدة فيه ، مما يدل على إمكانيات الطباعة المختلفة لتصميم النص. هكذا بدا التصميم الذي أعطاني المصمم شكله.
تخطيط الصفحةفيما يلي مثال لرمز CSS المطابق لهذه الصفحة:
h1, h2, h3, h4, h5, h6 { font-family: "balboa", sans-serif; font-weight: 300; margin: 0; } h4 { font-size: calc(1rem - 2px); } .body-text { font-family: "proxima-nova", sans-serif; } .body-text--lg { font-size: calc(1rem + 4px); } .body-text--md { font-size: 1rem; } .body-text--bold { font-weight: 700; } .body-text--semibold { font-weight: 600; }
يتم تنسيق الرؤوس بناءً على أسماء العلامات. لتنسيق العناصر الأخرى ، يتم استخدام أسماء الفئات. بالإضافة إلى ذلك ، هناك فئات منفصلة للثراء وأحجام الخطوط.
قبل أن أبدأ كتابة التعليمات البرمجية ، قمت بصياغة بعض القواعد:
خيارات لحل المشكلة
قبل بدء العمل ، فكرت في العديد من الخيارات لحل المهمة المحددة قبلي. هنا هو نظرة عامة.
code كتابة كود HTML يدويًا
أرغب في كتابة تعليمات HTML البرمجية يدويًا ، ولكن فقط عندما يسمح لنا بحل المشكلة الحالية بشكل مناسب. ومع ذلك ، في حالتي ، فإن كتابة الكود اليدوي تعني إدخال أجزاء مختلفة من الكود المتكرر التي توجد فيها بعض الاختلافات. لم يعجبني بالإضافة إلى ذلك ، قد يعني هذا أنه لا يمكن تخزين البيانات في ملف منفصل. ونتيجة لذلك ، رفضت هذا النهج.
إذا قمت بإنشاء الصفحة المعنية بهذا الشكل ، كنت سأحصل على شيء مثل التالي:
<div class="row"> <h1>Heading 1</h1> <p class="body-text body-text--md body-text--semibold">h1</p> <p class="body-text body-text--md body-text--semibold">Balboa Light, 30px</p> <p class="group body-text body-text--md body-text--semibold"> <span>Product title (once on a page)</span> <span>Illustration headline</span> </p> </div>
patterns باستخدام أنماط Vue التقليدية
في ظل الظروف العادية ، يتم استخدام هذا النهج في معظم الأحيان. ومع ذلك ، نلقي نظرة على
هذا المثال.
مثال على استخدام قوالب Vueفي العمود الأول يوجد ما يلي:
<h1>
، والتي يتم تقديمها في النموذج الذي يعرضه المستعرض.- تقوم
<p>
بتجميع عدة أطفال <span>
مع نص. يتم تعيين فئة لكل عنصر من هذه العناصر (ولكن لم يتم تعيين فئة خاصة للعلامة <p>
نفسها). <p>
التي لا تحتوي على عناصر <span>
متداخلة يتم تخصيص الفئة لها.
لتنفيذ كل هذا ، ستكون هناك حاجة إلى العديد من مثيلات
v-if
و
v-if-else
التوجيهية. وهذا ، كما أعرف ، سيؤدي إلى حقيقة أن الشفرة ستصبح مربكة للغاية قريبًا. أيضا ، أنا لا أحب استخدام كل هذا المنطق الشرطي في الترميز.
ender تقديم وظائف
نتيجة لذلك ، بعد تحليل البدائل الممكنة ، اخترت تقديم وظائف. في نفوسهم ، باستخدام JavaScript ، باستخدام بنيات شرطية ، يتم إنشاء العقد الفرعية للعقد الأخرى. عند إنشاء هذه العقد الفرعية ، يتم أخذ جميع المعايير اللازمة في الاعتبار. في هذه الحالة ، بدا هذا الحل مثالياً بالنسبة لي.
نموذج البيانات
كما قلت ، أردت تخزين بيانات الطباعة في ملف JSON منفصل. سيسمح ذلك ، إذا لزم الأمر ، بإجراء تغييرات عليها دون لمس العلامات.
هذه هي البيانات.
كل كائن JSON في الملف هو وصف لسطر منفصل:
{ "text": "Heading 1", "element": "h1", // . "properties": "Balboa Light, 30px", // . "usage": ["Product title (once on a page)", "Illustration headline"] // . - . }
إليك HTML الذي يأتي بعد معالجة هذا الكائن:
<div class="row"> <h1>Heading 1</h1> <p class="body-text body-text--md body-text--semibold">h1</p> <p class="body-text body-text--md body-text--semibold">Balboa Light, 30px</p> <p class="group body-text body-text--md body-text--semibold"> <span>Product title (once on a page)</span> <span>Illustration headline</span> </p> </div>
الآن النظر في مثال أكثر تعقيدا. تمثل المصفوفات مجموعات من الأطفال. يمكن لخصائص كائنات
classes
، والتي تعتبر كائنات في حد ذاتها ، تخزين أوصاف
classes
. تحتوي الخاصية
base
لكائن
classes
على وصف للفئات الشائعة لجميع العقد في الخلية. يتم تطبيق كل فئة موجودة في خاصية
variants
على عنصر واحد في المجموعة.
{ "text": "Body Text - Large", "element": "p", "classes": { "base": "body-text body-text--lg",
يتحول هذا الكائن إلى HTML التالي:
<div class="row"> <p class="group"> <span class="body-text body-text--lg body-text--bold">Body Text - Large</span> <span class="body-text body-text--lg body-text--regular">Body Text - Large</span> </p> <p class="group body-text body-text--md body-text--semibold"> <span>body-text body-text--lg body-text--bold</span> <span>body-text body-text--lg body-text--regular</span> </p> <p class="body-text body-text--md body-text--semibold">Proxima Nova Bold and Regular, 20px</p> <p class="group body-text body-text--md body-text--semibold"> <span>Large button title</span> <span>Form label</span> <span>Large modal text</span> </p> </div>
الهيكل الأساسي للمشروع
لدينا مكون الأصل ،
TypographyTable.vue
، والذي يحتوي على العلامات لتشكيل الجدول. لدينا أيضًا مكون
TypographyRow.vue
،
TypographyRow.vue
، وهو المسؤول عن إنشاء صف الجدول ويحتوي على وظيفة التجسيد الخاصة بنا.
عند تكوين صفوف الجدول ، يتم اجتياز صفيف به بيانات. يتم تمرير الكائنات التي تصف صفوف الجدول إلى مكون
TypographyRow
كخصائص.
<template> <section> <div class="row"> <p class="body-text body-text--lg-bold heading">Hierarchy</p> <p class="body-text body-text--lg-bold heading">Element/Class</p> <p class="body-text body-text--lg-bold heading">Properties</p> <p class="body-text body-text--lg-bold heading">Usage</p> </div> <typography-row v-for="(rowData, index) in $options.typographyData" :key="index" :row-data="rowData" /> </section> </template> <script> import TypographyData from "@/data/typography.json"; import TypographyRow from "./TypographyRow"; export default {
أود هنا أن أشير إلى تافه واحد ممتع: يمكن تمثيل البيانات المطبعية في مثيل Vue كخاصية. يمكنك الوصول إليهم باستخدام بنية
$options.typographyData
، نظرًا لأنها لا تتغير ويجب ألا تكون تفاعلية (بفضل
Anton Kosykh ).
خلق عنصر وظيفي
مكون
TypographyRow
الذي يعالج البيانات هو مكون وظيفي. المكونات الوظيفية هي الكيانات التي ليس لديها حالات ومثيلات. هذا يعني أنه ليس لديهم
this
، وأنهم لا يستطيعون الوصول إلى أساليب دورة حياة مكون Vue.
فيما يلي "الهيكل العظمي" لمكون مماثل سنبدأ به العمل على المكون الخاص بنا:
تأخذ طريقة مكون
render
وسيطة
context
لها خاصية
props
. تخضع هذه الخاصية للتدمير وتستخدم كوسيطة ثانية.
الوسيطة الأولى هي
createElement
. هذه وظيفة تخبر Vue عن العقدة التي يجب إنشاؤها. من أجل الإيجاز وتوحيد الكود ، يمكنني استخدام الاختصار
h
لـ
createElement
. يمكنك أن تقرأ عن سبب قيامي بهذا
هنا .
لذلك يأخذ
h
ثلاث حجج:
- علامة HTML (مثل
div
). - عنصر بيانات يحتوي على سمات القالب (على سبيل المثال ،
{ class: 'something'}
). - سلاسل نصية (إذا أضفنا فقط نصًا) أو عُقد فرعية تابعة باستخدام
h
.
إليك ما يبدو عليه:
render(h, { props }) { return h("div", { class: "example-class" }, "Here's my example text") }
لنلخص ما أنشأناه بالفعل. وهي لدينا الآن ما يلي:
- ملف به بيانات تم التخطيط لاستخدامه في تكوين الصفحة.
- مكون Vue منتظم يستورد ملف بيانات.
- إطار المكون الوظيفي المسؤول عن عرض صفوف الجدول.
لإنشاء صفوف الجدول ، يجب تمرير البيانات من تنسيق JSON كوسيطة إلى
h
. يمكنك نقل جميع هذه البيانات دفعة واحدة ، ولكن مع هذا النهج ، ستحتاج إلى قدر كبير من المنطق الشرطي ، مما يقلل من إمكانية قراءة الكود. بدلاً من ذلك ، قررت أن أفعل هذا:
- تحويل البيانات إلى تنسيق موحد.
- عرض البيانات المحولة.
تحويل البيانات
أرغب في تقديم بياناتي بتنسيق يطابق الوسائط التي يقبلها
h
. ولكن قبل تحويلها ، خططت للهيكل الذي يجب أن يكون لديهم في ملف JSON:
// { tag: "", // HTML- cellClass: "", // . - null text: "", // , children: [] // , . , . }
يمثل كل كائن خلية واحدة من الجدول. تشكل أربع خلايا كل صف من الجدول (يتم تجميعها في صفيف):
// [ { cell1 }, { cell2 }, { cell3 }, { cell4 } ]
قد تكون نقطة الإدخال وظيفة مثل ما يلي:
function createRow(data) {
دعنا ننظر إلى التصميم مرة أخرى.
تخطيط الصفحةيمكنك أن ترى أنه في العمود الأول ، يتم تصميم العناصر بطريقة مختلفة. وفي الأعمدة المتبقية ، يتم استخدام نفس التنسيق. لذلك دعونا نبدأ مع هذا.
اسمحوا لي أن أذكرك بأنني أود استخدام هيكل JSON التالي كنموذج لوصف كل خلية:
{ tag: "", cellClass: "", text: "", children: [] }
مع هذا النهج ، سيتم استخدام بنية تشبه شجرة لوصف كل خلية. هذا بالتحديد لأن بعض الخلايا تحتوي على مجموعات من الأطفال. نستخدم الدالتين التاليتين لإنشاء خلايا:
- تأخذ الدالة
createNode
كل الخصائص التي نهتم بها كوسيطة. - تلعب وظيفة
createCell
دور مجمّع حول createNode
، بمساعدتها نتحقق مما إذا كان text
الوسيطة text
صفيف. إذا كان الأمر كذلك ، فإننا نخلق مجموعة من الأطفال.
الآن يمكننا أن نفعل شيئا مثل هذا:
function createRow(data) { let { text, element, classes = null, properties, usage } = data; let row = []; row[0] = "" row[1] = createCellData("p", ?????)
عند تكوين العمودين الثالث والرابع ، نقوم بتمرير
properties
usage
نصية. ومع ذلك ، يختلف العمود الثاني عن الثالث والرابع. نعرض هنا أسماء الفئات التي يتم تخزينها في هذا النموذج في البيانات المصدر:
"classes": { "base": "body-text body-text--lg", "variants": ["body-text--bold", "body-text--regular"] },
بالإضافة إلى ذلك ، دعونا لا ننسى أنه عند التعامل مع الرؤوس ، لا يتم استخدام الفصول الدراسية. لذلك ، نحتاج إلى إنشاء أسماء علامات رأس للخطوط المقابلة (أي ،
h1
،
h2
، وما إلى ذلك).
نقوم بإنشاء وظائف مساعدة تسمح لنا بتحويل هذه البيانات إلى تنسيق يسهل استخدامها كوسيطة
text
.
الآن يمكننا القيام بما يلي:
function createRow(data) { let { text, element, classes = null, properties, usage } = data; let row = []; row[0] = "" row[1] = createCellData("p", displayClasses(element, classes))
تحويل البيانات المستخدمة لإظهار الأنماط
نحتاج إلى تحديد ما يجب فعله بالعمود الأول من الجدول ، مع عرض أمثلة لتطبيق الأنماط. هذا العمود يختلف عن الآخر. نحن هنا نطبق علامات وفئات جديدة على كل خلية بدلاً من استخدام مجموعة الفئات المستخدمة بواسطة الأعمدة المتبقية:
<p class="body-text body-text--md body-text--semibold">
بدلاً من محاولة تطبيق هذه الوظيفة في
createCellData
أو
createNodeData
، أقترح إنشاء وظيفة جديدة تستفيد من إمكانيات هذه الوظائف الأساسية التي تؤدي إلى تحويل البيانات. سوف تنفذ آلية جديدة لمعالجة البيانات:
function createDemoCellData(data) { let children; const classes = getClasses(data.classes);
الآن يتم تقليل بيانات السلسلة إلى تنسيق عادي ويمكن نقلها إلى وظيفة التجسيد:
function createRow(data) { let { text, element, classes = null, properties, usage } = data let row = [] row[0] = createDemoCellData(data) row[1] = createCellData("p", displayClasses(element, classes)) row[2] = createCellData("p", properties) row[3] = createCellData("p", usage) return row }
تقديم البيانات
إليك كيفية تقديم البيانات التي يتم عرضها على الصفحة:
الآن
كل شيء جاهز !
هنا ، مرة أخرى ، شفرة المصدر.
النتائج
تجدر الإشارة إلى أن النهج المتبع هنا هو وسيلة تجريبية لحل مشكلة تافهة إلى حد ما. أنا متأكد من أن الكثيرين سيقولون أن هذا الحل معقد بشكل غير معقول ومثقل بالأعمال الهندسية الزائدة. ربما أوافق على ذلك.
على الرغم من حقيقة أن تطوير هذا المشروع استغرق الكثير من الوقت ، فإن البيانات الآن منفصلة تمامًا عن العرض التقديمي. الآن ، إذا حضر مصممينا لإضافة بعض الصفوف إلى الجدول ، أو إزالة أي صفوف موجودة منه ، فلست مضطرًا إلى تشغيل كود HTML
المربك . من أجل القيام بذلك ، سيكون من المناسب بالنسبة لي تغيير العديد من الخصائص في ملف JSON.
هل النتيجة تستحق الجهد؟ أعتقد أنه من الضروري أن ننظر إلى الظروف. هذا ، ومع ذلك ، هو سمة جدا من البرمجة. أريد أن أقول أنه في رأسي ، في عملية العمل على هذا المشروع ، ظهرت الصورة التالية باستمرار.
ربما هذا هو الجواب على سؤالي حول ما إذا كان هذا المشروع يستحق الجهد المبذول في تطويره.
أعزائي القراء! ? ?
