Введение:Element UIЭто один из лучших UI-фреймворков в мире. Каковы преимущества этой превосходной структуры, из которых мы можем извлечь уроки? Эта статья поделится навыками, которые автор считает достойными ссылки при просмотре исходного кода этого репозитория фреймворка, и рекомендуется к сотрудничеству.elementИсходник лучше есть.
Совет 1: Компонентные леса
Применение строительных лесов при создании новых компонентов: Стандартизируйте каталог кода, уменьшите нагрузку на перемещение кирпичей и внедрите исходный код скаффолдинга:build/bin/new.js
# 执行命令,参数说明
# componentname 组件名 必填
# chineseName 组将中文名 选填 ,不填默认取值componentname
# node build/bin/new.js componentname [chineseName] 命令说明
# 在element项目下执行
node build/bin/new.js helloworld 示例
Результаты строительных лесов:
-
1. Обработка стиля компонента:
1.1 Создание пакетов стилей компонентов/theme-chalk/src/${componentname}.scss
1.2 Файл записи стиля packages/theme-chalk/src/index.scss импортирует и изменяет стиль компонента
-
2. Обработка кода компонента:
2.1 Создание файлов кода компонента: packages/{componentname}/src/main.vue
2.2 Импортируйте информацию о пути нового компонента в component.json , который представляет собой объект json, в котором хранится имя компонента и путь входа компонента.
-
3. Создайте документацию компонента:
3.1 Сгенерируйте examples/docs/{i18n}/component.md, где i18n=['en-US','es','fr-FR','zh-CN']
3.2 Добавьте заголовок и путь только что добавленного документа компонента в examples/nav.config.json, который является каталогом документа компонента пользовательского интерфейса Element и сохраняет заголовок и маршрут документа компонента.
-
4. Создайте модульные тесты:
4.1 Создайте файл модульного теста: test/unit/specs/component.spec.js
-
5. Создайте определение интерфейса компонента:
5.1 Создайте файл описания компонента: types/component.d.ts
5.2 Добавьте определения интерфейса для новых компонентов в types/element-ui.d.ts
Для отличного компонента, помимо написания кода компонента, есть еще юнит-тесты, документация и желательно определения интерфейса (у этого компилятора есть дружественные советы по использованию) все сделано 😄
Совет 2: Используйте код для генерации кода
Генерация файла ввода исходного кода: Element UI в настоящее время имеет в общей сложности компоненты 80. Если вы хотите экспортировать эти компоненты 80, код для импорта, экспорта и объявления компонентов Vue должен быть написан 240 раз, а файл ввода должен быть изменен для добавления или удаления компонентов. Чтобы уменьшить эту часть рабочей нагрузки, исходя изcomponents.jsonИмпорт и экспорт компонентов для создания входных файлов.
Содержимое component.json выглядит следующим образом:
Файл ввода имеет три кода (компоненты импорта, экспорта и декларации), которые повторяются 80 раз.Ниже приведен пример оператора кода импорта:
Представьте образцы кода:
/* Automatically generated by './build/bin/build-entry.js' */
import Pagination from '../packages/pagination/index.js';
import Dialog from '../packages/dialog/index.js';
import Autocomplete from '../packages/autocomplete/index.js';
import Dropdown from '../packages/dropdown/index.js';
import DropdownMenu from '../packages/dropdown-menu/index.js';
import DropdownItem from '../packages/dropdown-item/index.js';
import Menu from '../packages/menu/index.js';
/**省略 70多个组件导入**/
import CollapseTransition from 'element-ui/src/transitions/collapse-transition';
Сгенерируйте приведенный выше код, основная логика: прочитайте вcomponents.jsonПоскольку данные, а затем и шаблоны соединяются вместе, конкретная реализация выглядит следующим образом:
var Components = require('../../components.json');
var render = require('json-templater/string');
var uppercamelcase = require('uppercamelcase');
var endOfLine = require('os').EOL;
// import 语句语法模版
var IMPORT_TEMPLATE = 'import {{name}} from \'../packages/{{package}}/index.js\';';
var ComponentNames = Object.keys(Components);
var includeComponentTemplate = [];
ComponentNames.forEach(name => {
var componentName = uppercamelcase(name);
includeComponentTemplate.push(
// 单条import生成语句
render(IMPORT_TEMPLATE, {
name: componentName,
package: name
})
);
});
console.info(includeComponentTemplate.join(endOfLine))
Реализация сгенерированного кода:build/bin/build-entry.js
Расположение кода:src/index.js
Совет 3: Используйте md для написания документации и примеров компонентов
Очень элегантная документация и написание примеров: Документы и примеры записываются в файлы markdown единообразно.Написав md-loader,сначала конвертировать их в html файлы,потом конвертировать в vue компоненты,а потом рендерить.Мне кажется такой подход слишком интересным.
Давайте сначала посмотрим на структуру страницы документации Element UI:
Логика компонента маршрутизации (Подробный код):
// 截取组件文档的路由代码片段
const LOAD_DOCS_MAP = {
'zh-CN': path => {
return r => require.ensure([], () =>
r(require(`./docs/zh-CN${path}.md`)),
'zh-CN');
},
'en-US': path => {
return r => require.ensure([], () =>
r(require(`./docs/en-US${path}.md`)),
'en-US');
},
'es': path => {
return r => require.ensure([], () =>
r(require(`./docs/es${path}.md`)),
'es');
},
'fr-FR': path => {
return r => require.ensure([], () =>
r(require(`./docs/fr-FR${path}.md`)),
'fr-FR');
}
};
Обратите внимание, что компонент, загруженный маршрутом, является не компонентом vue, а файлом уценки. Этот процесс достигается за счет настройки загрузчика в процессе упаковки веб-пакета: уценка преобразуется в vue для достижения.
Подробная реализация:build/md-loader/index.js
Далее я подробно поделюсь, как в документе достигается эффект демонстрации компонента:
Шаг 1: Расширьте формат контейнера уценки: демонстрация
:::demo ${content}:::
Код реализации:
const md = require('markdown-it')();
const fs = require('fs');
const path = require('path');
const mdContainer = require('markdown-it-container');
module.exports = md => {
md.use(mdContainer, 'demo', {
validate(params) {
return params.trim().match(/^demo\s*(.*)$/);
},
render(tokens, idx) {
const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/);
if (tokens[idx].nesting === 1) {
const description = m && m.length > 1 ? m[1] : '';
const content = tokens[idx + 1].type === 'fence' ? tokens[idx + 1].content : '';
return `<demo-block>
${description ? `<div>${md.render(description)}</div>` : ''}
<!--element-demo: ${content}:element-demo-->
`;
}
return '</demo-block>';
}
});
md.use(mdContainer, 'tip');
md.use(mdContainer, 'warning');
};
const inputPath = path.resolve(__dirname, './alert.md');
const outputPath = path.resolve(__dirname, './alert.html');
const input = fs.readFileSync(inputPath, {encoding: 'utf8'});
const ounput = md.render(input);
fs.writeFileSync(outputPath, ounput, {encoding: 'utf8'});}
Результаты:
Извлеките содержимое аннотации в экземпляр реализации компонента.
Шаг 2. Конвертируйте html в ComponentDoc.vue
<template>
<section class="content element-doc">
<h2>Alert 警告</h2>
<p>用于页面中展示重要的提示信息。</p>
<h3>自定义关闭按钮</h3>
<p>自定义关闭按钮为文字或其他符号。</p>
<!--示例展示 这个步是最关键-->
<demo-block>
<template name="source">
<element-demo0 />
</template>
<template name="default"></template>
<slot name="highlight"></slot>
</demo-block>
</section>
</template>
Компонент: , расположение исходного кода:examples/components/demo-block.vue
Эффект DemoBlockComponent показан следующим образом:
Шаг 3: Пример отображения эффекта
- Во-первых, компонент имеет только шаблон и никаких других атрибутов, так же как и описание слота контента, он может быть прозрачно передан прямо через слот;
- Во-вторых, компонент имеет скриптовое содержимое, как с этим быть? Как показано ниже
Код компонента генерируется путем вызова модуля Vue-Template-Compiler, см.:build/md-loader/util.js:L30
Совет 4: Пример компонента значка
Пользовательский интерфейс Element содержит значки 280. Ручное перемещение кирпичей и написание документов требует много сверхурочной работы. Для программистов, у которых есть занятия, конечно, у них должны быть идеи. Навыки обработки: используйте модуль postcss для анализа файлов стилей иконок, извлечения className из el-icon-XXX, сборки classNames всех иконок в массив и сохранения его вexamples/icon.json
Имя значка извлекается через класс стиля, а код реализован следующим образом:
'use strict';
var postcss = require('postcss');
var fs = require('fs');
var path = require('path');
var fontFile = fs.readFileSync(path.resolve(__dirname, '../../packages/theme-chalk/src/icon.scss'), 'utf8');
// 借助postcss解析css文件
var nodes = postcss.parse(fontFile).nodes;
var classList = [];
// 通过正则获取icon的name
nodes.forEach((node) => {
var selector = node.selector || '';
var reg = new RegExp(/\.el-icon-([^:]+):before/);
var arr = selector.match(reg);
if (arr && arr[1]) {
classList.push(arr[1]);
}});
classList.reverse();
// 希望按 css 文件顺序倒序排列
console.info(classList.length);
fs.writeFile(
path.resolve(__dirname, '../../examples/icon.json'),
JSON.stringify(classList)
);
Эти три метода — это компонент ComponentDoc.vue, сгенерированный icons.md значков.Если вы не можете написать код для передачи в массив значков, вставьте его напрямую. В цепочке прототипов в Vue
// 文档入口引入
import Vue from 'vue'
import icon from './icon.json';
Vue.prototype.$icon = icon;
значок документ написание
图标集合
<ul class="icon-list">
<!--直接从原型链获取全部icon名字-->
<li v-for="name in $icon" :key="name">
<span>
<i :class="'el-icon-' + name"></i>
<span class="icon-name">{{'el-icon-' + name}}</span>
</span>
</li>
</ul>
Эффект:элемент. Вы голодны? IO/#/this-cn/com…
Решайте столько повторяющихся задач одновременно 😄
Совет 5: документируйте многоязычие
Документ многоязычный, используйте скрипт для генерации каждого языка и сгенерируйте шаблон vue отдельно, аналогично второму навыку, см.:build/bin/i18n.js