Навыки, полученные в исходном коде Element UI

внешний интерфейс внешний фреймворк
Навыки, полученные в исходном коде Element UI

Введение: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/index.jsа такжеpackages/{имя компонента}/index.js и пакеты/{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 выглядит следующим образом:

image.png

Файл ввода имеет три кода (компоненты импорта, экспорта и декларации), которые повторяются 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:

image.png

Логика компонента маршрутизации (Подробный код):

// 截取组件文档的路由代码片段
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

Далее я подробно поделюсь, как в документе достигается эффект демонстрации компонента:

image.png

Шаг 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'});}  

Результаты:

image.png

Извлеките содержимое аннотации в экземпляр реализации компонента.

Шаг 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 показан следующим образом:

image.png

Шаг 3: Пример отображения эффекта

  • Во-первых, компонент имеет только шаблон и никаких других атрибутов, так же как и описание слота контента, он может быть прозрачно передан прямо через слот;
  • Во-вторых, компонент имеет скриптовое содержимое, как с этим быть? Как показано ниже

image.png

Код компонента генерируется путем вызова модуля 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…

image.png

Решайте столько повторяющихся задач одновременно 😄

Совет 5: документируйте многоязычие

Документ многоязычный, используйте скрипт для генерации каждого языка и сгенерируйте шаблон vue отдельно, аналогично второму навыку, см.:build/bin/i18n.js