المواد كما WebComponents

في الآونة الأخيرة ، كما أشرت في مقالة سابقة ، تقوم WebComponents of wrappers لإطارات العمل الشائعة التي تسمح باستخدامها من خلال واجهة برمجة التطبيقات للمستعرض بتطوير نفسها بنشاط. هذا يعني أنه إذا كنت تريد استخدام مكونات جاهزة تم إنشاؤها في إطار عمل معين ، فلن تحتاج إلى نشر المشروع وتجميعه. هذا يعني أيضًا أنه يمكنك استخدام التطوير على أطر عمل مختلفة عن طريق ربطها معًا من خلال التفاعل من خلال واجهة برمجة تطبيقات المتصفح.

منذ وقت ليس ببعيد ، كنت أحاول العثور على شبكة جيدة لمكونات الويب ، في ذلك الوقت كانت شبكة كاملة ، لكن في نفس الوقت لم أكن مضطرًا لاستخدام أي إطار عمل ، خاصة إذا كان شيءًا مثل Polymer لم يكن. في الماضي القريب ، كانت لدي تجربة ناجحة إلى حد ما مع المواد / cdk من قبل. بعد ذلك ، كان من السهل نسبيًا تخصيص الفلاتر والنداء للجدول بجدية ، لتوطين النصائح وكل هذا دون إعادة كتابة رمز المكتبة أو الخطافات القاتمة ، باستخدام آليات إعادة التعريف. في وقت المراجعة ، تبيّن أن المجلدات الخاصة بمكون الجدول لم يتم تنفيذها بعد ، لكن قبل أسبوعين لاحظت أن هناك شيئًا ما ظهر في المستودع الخاص بهذا الموضوع وقررت محاولة توصيله كمكونات ويب كجزء من التجربة.

من أجل البدء في استخدام مكونات المواد ، ما عليك سوى توصيل الحزمة مع الكود ومورد آخر بكل الأنماط ، مثل مراوح VueJS. على سبيل المثال ، يمكنك إنشاء حقل إدخال يتحكم فيه الزاوي / المادة كما يلي:

<link rel="stylesheet" href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css"> <script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script> <div class="mdc-text-field"> <input type="text" id="my-text-field" class="mdc-text-field__input"> <label class="mdc-floating-label" for="my-text-field">Label</label> <div class="mdc-line-ripple"></div> </div> <script> mdc.textField.MDCTextField.attachTo(document.querySelector('.mdc-text-field')); </script> 

ويمكننا توصيل جدول لعرض البيانات بنفس السهولة ، مباشرة من نموذج الوثائق على الرابط .

 <div class="mdc-text-field"> <input type="text" id="my-text-field" class="mdc-text-field__input"> <label class="mdc-floating-label" for="my-text-field">Label</label> <div class="mdc-line-ripple"></div> </div> <div class="mdc-data-table"> <table class="mdc-data-table__table" aria-label="Dessert calories"> <thead> <tr class="mdc-data-table__header-row"> <th class="mdc-data-table__header-cell" role="columnheader" scope="col">Dessert</th> <th class="mdc-data-table__header-cell" role="columnheader" scope="col">Carbs (g)</th> <th class="mdc-data-table__header-cell" role="columnheader" scope="col">Protein (g)</th> <th class="mdc-data-table__header-cell" role="columnheader" scope="col">Comments</th> </tr> </thead> <tbody class="mdc-data-table__content"> <tr class="mdc-data-table__row"> <td class="mdc-data-table__cell">Frozen yogurt</td> <td class="mdc-data-table__cell mdc-data-table__cell--numeric">24</td> <td class="mdc-data-table__cell mdc-data-table__cell--numeric">4.0</td> <td class="mdc-data-table__cell">Super tasty</td> </tr> <tr class="mdc-data-table__row"> <td class="mdc-data-table__cell">Ice cream sandwich</td> <td class="mdc-data-table__cell mdc-data-table__cell--numeric">37</td> <td class="mdc-data-table__cell mdc-data-table__cell--numeric">4.3</td> <td class="mdc-data-table__cell">I like ice cream more</td> </tr> <tr class="mdc-data-table__row"> <td class="mdc-data-table__cell">Eclair</td> <td class="mdc-data-table__cell mdc-data-table__cell--numeric">24</td> <td class="mdc-data-table__cell mdc-data-table__cell--numeric">6.0</td> <td class="mdc-data-table__cell">New filing flavor</td> </tr> </tbody> </table> </div> <script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script> <script type="module"> let filterField = mdc.textField.MDCTextField.attachTo(document.querySelector('.mdc-text-field')); let dataTable = new mdc.dataTable.MDCDataTable(document.querySelector('.mdc-data-table')); </script> 

عند الاتصال من حزم إلغاء كجم مع إلغاء تجميع التي قمنا بتجميعها بالفعل ، نحن للأسف لا نستخدم القدرات وحدات الأصلية لمتصفح WHATWG ، كما تربط هذه الحزم المكونات بمساحة الاسم العالمية وكائنها mdc ، بدلاً من تصديرها باستخدام المعيار المعياري ES6. لكن من المحتمل أن يكون مثل هذا الخيار أكثر دراية للمتخصصين ذوي الأفكار المحافظة ويمكن أن يعمل دون المترجمين في المتصفحات القديمة.



يمكن العثور على قائمة المكونات المنفذة في هذا المستودع .

لسوء الحظ ، في الوقت الحالي ، لا يتم عرض سوى نوع من التفاعل مع مربعات الاختيار ومحتوى السلسلة المقدمة بالفعل للجداول في واجهة برمجة تطبيقات يمكن الوصول إليها من خارج واجهة برمجة التطبيقات.

ومع ذلك ، تمكنت من google أحد الأمثلة التي تسمح لك بالوصول إلى واجهة برمجة التطبيقات (API) حتى الآن مخفية عنا ، من خلال الميراث. بالإضافة إلى ذلك ، يجب أن تكون مدركًا أنه بمساعدة مشروع Angular Elements ، يمكنك تطوير مكونات في البنية الأساسية للإطار وعرضها بشكل مستقل على واجهة برمجة تطبيقات المتصفح ونفس CustomElements.



أخذت المثال بأكمله ، حيث قمت ببعض التصحيحات ، "للعمل" على التصميم الأصلي وكان من الواضح أين أختار بعد قراءة المقال. هناك الكثير من التعليمات البرمجية والآن يتم طيها.

رمز الجدول
 <link rel="stylesheet" href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css"> <div class="mdc-text-field"> <input type="text" id="my-text-field" class="mdc-text-field__input"> <label class="mdc-floating-label" for="my-text-field">Label</label> <div class="mdc-line-ripple"></div> </div> <div class="mdc-data-table"> <table class="mdc-data-table__table" aria-label="Dessert calories"> <thead> <tr class="mdc-data-table__header-row"> <th class="mdc-data-table__header-cell" role="columnheader" scope="col">Dessert</th> <th class="mdc-data-table__header-cell" role="columnheader" scope="col">Carbs (g)</th> <th class="mdc-data-table__header-cell" role="columnheader" scope="col">Protein (g)</th> <th class="mdc-data-table__header-cell" role="columnheader" scope="col">Comments</th> </tr> </thead> <tbody class="mdc-data-table__content"> <tr class="mdc-data-table__row"> <td class="mdc-data-table__cell">Frozen yogurt</td> <td class="mdc-data-table__cell mdc-data-table__cell--numeric">24</td> <td class="mdc-data-table__cell mdc-data-table__cell--numeric">4.0</td> <td class="mdc-data-table__cell">Super tasty</td> </tr> <tr class="mdc-data-table__row"> <td class="mdc-data-table__cell">Ice cream sandwich</td> <td class="mdc-data-table__cell mdc-data-table__cell--numeric">37</td> <td class="mdc-data-table__cell mdc-data-table__cell--numeric">4.3</td> <td class="mdc-data-table__cell">I like ice cream more</td> </tr> <tr class="mdc-data-table__row"> <td class="mdc-data-table__cell">Eclair</td> <td class="mdc-data-table__cell mdc-data-table__cell--numeric">24</td> <td class="mdc-data-table__cell mdc-data-table__cell--numeric">6.0</td> <td class="mdc-data-table__cell">New filing flavor</td> </tr> </tbody> </table> </div> <script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.js"></script> <script type="module"> let filterField = mdc.textField.MDCTextField.attachTo(document.querySelector('.mdc-text-field')); const DATATABLE_COLUMNS_SELECTOR = `.mdc-data-table thead`, DATATABLE_DATA_SELECTOR = `tbody.mdc-data-table__content`, DATATABLE_SORTABLE_SELECTOR = `.mdc-data-table--sortable`, DATATABLE_COLUMNS_NUMERIC = `mdc-data-table--numeric`, DATATABLE_COLUMNS_SORTABLE = `mdc-data-table--sortable`, DATATABLE_COLUMNS_SORT_ASC = `mdc-data-table--sort-asc`, DATATABLE_COLUMNS_SORT_DESC = `mdc-data-table--sort-desc`; class MyDataTable extends mdc.dataTable.MDCDataTable { get data() { return this.foundation_.data; } set data(data) { if (Array.isArray(data)) { this.foundation_.setData(data); } else { throw new Error(`Expected an array`); } } layout() { if (this.foundation_.layout) { this.foundation_.layout(); } } getDefaultFoundation() { const getHeaderRow = () => { let thead = this.root_.querySelector(DATATABLE_COLUMNS_SELECTOR), row = thead.querySelector(`tr`); if (!row) { row = document.createElement(`tr`); row.setAttribute(`role`, `rowheader`); thead.appendChild(row); } return row; }, getHeaderColumns = () => { return getHeaderRow().querySelectorAll(`th`); }, emptyHeaderColumns = () => { getHeaderRow().remove(); }, getData = () => { return this.root_.querySelector(DATATABLE_DATA_SELECTOR); }, getDataRows = () => { return getData().querySelectorAll(`tr`); }, emptyData = () => { Array.prototype.map.call(getDataRows(), row => { row.remove(); }); }; return new MyDataTableFoundation({ registerSortClickHandler: (handler) => this.root_.addEventListener(`click`, handler), deregisterSortClickHandler: (handler) => this.root_.removeEventListener(`click`, handler), // Reads the columns list readColumns: () => { var cols = getHeaderColumns(); return Array.prototype.map.call(cols, col => { return { text: col.textContent, description: col.getAttribute(`aria-label`), numeric: col.classList.contains(DATATABLE_COLUMNS_NUMERIC), sortable: col.classList.contains(DATATABLE_COLUMNS_SORTABLE), sort: col.classList.contains(DATATABLE_COLUMNS_SORT_ASC) ? 1 : col.classList.contains(DATATABLE_COLUMNS_SORT_DESC) ? -1 : 0 }; }); }, // Edit the columns setColumns: (cols) => { emptyHeaderColumns(); let row = getHeaderRow(); cols.forEach(col => { let column = document.createElement(`th`); column.setAttribute(`role`, `columnheader`); // Add text column.textContent = col.text; column.setAttribute(`aria-label`, col.description); // Numeric if (col.numeric) { column.classList.add(DATATABLE_COLUMNS_NUMERIC); } // Sort if (col.sortable) { let ariaSort = `none`; column.classList.add(DATATABLE_COLUMNS_SORTABLE); if (col.sort === `asc` || col.sort === 1) { ariaSort = `ascending`; column.classList.add(DATATABLE_COLUMNS_SORT_ASC); } else if (col.sort === `desc` || col.sort === -1) { ariaSort = `descending`; column.classList.add(DATATABLE_COLUMNS_SORT_DESC); } column.setAttribute(`aria-sort`, ariaSort); } // Add to cols row.appendChild(column); }); }, // Read data readData: () => { var rows = getDataRows(); return Array.prototype.map.call(rows, row => { let cells = row.querySelectorAll(`td`); return Array.prototype.map.call(cells, cell => cell.textContent); }); }, // Edit the data setData: (data) => { emptyData(); let element = getData(); // Sorting data let column = this.columns.find(el => el.sort); if (column) { let index = this.columns.indexOf(column); if (column.sortable) { let f = (params => { if (params.sort === `desc` || params.sort === -1) { return params.numeric ? (a, b) => b[index] - a[index] : (a, b) => b[index].localeCompare(a[index]); } else { return params.numeric ? (a, b) => a[index] - b[index] : (a, b) => a[index].localeCompare(b[index]); } })(column); data.sort(f); } } // For each data data.forEach(d => { // Create a new row let row = document.createElement(`tr`); row.setAttribute(`role`, `row`); // For each values d.forEach((val, i) => { // Create a new cell let cell = document.createElement(`td`); cell.setAttribute(`role`, `gridcell`); // Add numeric if needed if (this.columns[i].numeric) { cell.classList.add(DATATABLE_COLUMNS_NUMERIC); } // Add content if (val instanceof Element) { cell.appendChild(val); } else { cell.textContent = val; } row.appendChild(cell); }); // Add to cols element.appendChild(row); }); }, // Redraw data table after edit redraw: () => { this.foundation_.adapter_.setColumns(this.columns); this.foundation_.adapter_.setData(this.data); } }); } } mdc.autoInit.register(`MDCDataTable`, MyDataTable); class MyDataTableFoundation extends mdc.base.MDCFoundation { static get defaultAdapter() { return { registerSortClickHandler: ( /* handler: EventListener */ ) => {}, deregisterSortClickHandler: ( /* handler: EventListener */ ) => {}, readColumns: () => {}, setColumns: () => {}, readData: () => {}, setData: () => {}, redraw: () => {} }; } constructor(adapter) { super(Object.assign(MyDataTableFoundation.defaultAdapter, adapter)); // Attributes this.columns = []; this.data = []; // Methods // On sort this.sortClickHandler_ = (e) => { let target = e.target.closest(DATATABLE_SORTABLE_SELECTOR); if (target) { let index = Array.prototype.indexOf.call(target.parentElement.children, target); this.columns.forEach((col, i) => { if (i !== index) { col.sort = 0; } else { if (col.sort === `asc` || col.sort === 1) { col.sort = `desc`; } else { col.sort = `asc`; } } }); this.adapter_.redraw(); } }; } init() { // Read columns this.columns = this.adapter_.readColumns(); // Read data this.data = this.adapter_.readData(); // Click this.adapter_.registerSortClickHandler(this.sortClickHandler_); } destroy() { // Click this.adapter_.deregisterSortClickHandler(this.sortClickHandler_); } setColumns(cols) { this.adapter_.setColumns(cols); } setData(data) { this.adapter_.setData(data); } } let dataTable = new MyDataTable(document.querySelector('.mdc-data-table')); </script> 


ينفذ هذا المثال حدًا أدنى معينًا لإعادة التعريف ويعرض طرق التفاعل مع api المفقودة في api. بفضل هذا ، يمكننا دمج مكون الجدول في أحشاء الإطار مع مكون آخر من حقل الإدخال ، بإضافة وظيفة التصفية الخاصة بنا.

 let filterField = mdc.textField.MDCTextField.attachTo(document.querySelector('.mdc-text-field')); filterField.input_.oninput = (event) => { dataTable.origData = dataTable.origData || dataTable.data.slice(); if (event.target.value == '') { dataTable.data = dataTable.origData.slice(); } else { let data = dataTable.origData.filter((row) => { let rowIsOk = false; for (let item of row) { if (item.indexOf(event.target.value) > 0) { rowIsOk = true; } } return rowIsOk; }) || []; dataTable.data = data; dataTable.getDefaultFoundation().redraw(); } }; 

ليس من الصحيح من الناحية النظرية تطبيق التصفية مباشرةً في معالج الأحداث ، ولهذا لدينا الآن فئة جدول وهياكل مؤسسة ومحول بيانات أقرب إلى المعنى ، ولكن مهمتنا اليوم هي التحقق من إمكانية تنظيم تفاعل المكونات. وتمكنا للتو من توصيل مكونين ليس لهما منطق تنفيذ مشترك بالكود في سياق تنفيذ المتصفح.


بعد إدخال البيانات في الحقل ، سيتم تصفية المحتوى


هذا المثال ، خاصة بعد وضع كل منطق جافا سكريبت في ملفات فصل منفصلة ، كما فعلنا في المقالة الأولى من السلسلة ، يمكن أن يكون نقطة انطلاق بالنسبة لك لإعادة استخدام مكونات cdk الزاوي / المادي أو مجموعة أدوات أخرى لتطويرك ، مع إعادة تعريف السلوك بحيث "المزارع الجماعية" كل شيء من الصفر أو عن طريق دمج الكود الجديد في البنية التحتية الحالية ، وتوقف لزيادة متراصة ، ل توفر مكونات الويب أفضل طريقة لتنظيم التطوير بشكل معياري.

Source: https://habr.com/ru/post/ar462695/


All Articles