Колесо исследований, анализ исходного кода Ванта 1 — строка/столбец

Vue.js

предисловие

Сейчас слишком много зрелых и отличных навыков работы с колесами. Со временем возникнет ощущение, что «колеса используются только для бега, но не умеют строить», поэтому в этой статье мы отложим в сторону беспорядочные потребности бизнеса и взгляните на отличный компонент пользовательского интерфейса, как он достигается.
Развитие мобильной электронной коммерции сейчас очень распространено.vantОн также может соответствовать большинству сценариев использования, поэтому возьмите его в качестве объекта исследования, и задействованный технологический стек — это vue + jsx + typescript + less.

Введение

    src/
        utils/      //工具类
        style/      //全局样式
        row/        //组件代码
            index.js
            index.less
            test/       //测试代码
            demo/       //示例
        col/
        .....
    test/        //测试类
    types/       //typescript声明文件

Подготовка: создайте функцию создания класса

Каждый компонент ванта будет вызываться первымcreaeNamespaceфункция,createNamespaceФункция получает параметрыname,вернутьcreateComponent,createBEM,createI18NТри функции, а именно экземпляр comonent, функция вспомогательного класса css и многоязычный инструмент.

// utils/create/index.ts

export function createNamespace(name: string): CreateNamespaceReturn {
  name = 'van-' + name;
  return [createComponent(name), createBEM(name), createI18N(name)];
}

(1) создатькомпонент

createComponentфункционировать в соответствии сnameСгенерируйте объект компонента vue и сделайте некоторые пресеты для компонента в процессе.


export function createComponent(name: string) {
  return function<Props = DefaultProps, Events = {}, Slots = {}> (
  // 参数sfc:单文件组件(single file components),支持对象式组件和函数式组件
    sfc: VantComponentOptions | FunctionComponent
  ): TsxComponent<Props, Events, Slots> {
  
    // 函数式组件转化为对象式组件
    if (typeof sfc === 'function') {
      sfc = transformFunctionComponent(sfc); 
    }
   
    if (!sfc.functional) {
      sfc.mixins = sfc.mixins || [];
      sfc.mixins.push(SlotsMixin); // push了一个兼容低版本scopedSlots的mixin
    }

    sfc.name = name;
    sfc.install = install; // install中调用了Vue.component()方法注册组件

    return sfc as TsxComponent<Props, Events, Slots>;
  };
}

Объектно-ориентированные компонентыVantComponentOptionsВ компонент vue добавляются два свойства:functionalа такжеinstallметод

export interface VantComponentOptions extends ComponentOptions<Vue> {
  functional?: boolean; // 用于上文函数式组件判断
  install?: (Vue: VueConstructor) => void; // 插件的install方法
}

(2) createbem

createBEMname

/**
 * b() // 'button'
 * b('text') // 'button__text'
 * b({ disabled }) // 'button button--disabled'
 * b('text', { disabled }) // 'button__text button__text--disabled'
 * b(['disabled', 'primary']) // 'button button--disabled button--primary'
 */

b() принимает два параметра:elа такжеmods

export function createBEM(name: string) {
  return function(el?: Mods, mods?: Mods): Mods {
    //只有字符串格式的el会被处理,其他格式会当做mods处理
    if (el && typeof el !== 'string') {
      mods = el;
      el = '';
    }
    el = join(name, el, ELEMENT);

    return mods ? [el, prefix(el, mods)] : el;
  };
}

(3) createi18n

Многоязычная обработка, нечего сказать

export function createI18N(name: string) {
  const prefix = camelize(name) + '.';

  return function(path: string, ...args: any[]): string {
    const message = get(locale.messages(), prefix + path) || get(locale.messages(), path);
    return typeof message === 'function' ? message(...args) : message;
  };
}

Компоненты фургона - Ряд и Кол

сначала позвониcreaeNamespaceфункция

const [createComponent, bem, t] = createNamespace('row');

Затем передайте элементы конфигурации компонентаcreateComponent


export default createComponent({
  props: {
    ...
  },

  methods: {
    ...
  },

  render() {
    ...
    );
 }

Конкретные реквизиты и события могут быть переданы официальному лицу.api.

Здесь мы фокусируемся на строках и столбцах.renderфункции, разделенные наРеализация компонентов, написание HTML-дома, написание cssтри части.

(1) Реализация компонента

Вант делит макет на сетку из 24 столбцов, которая используется на ColspanСоотношение контроля атрибута,offsetСмещение управления, в строкеgutterКонтрольный интервал.
вgutterЛевое и правое заполнение через Col1/2 gutterДля достижения, чтобы компенсировать лишний интервал, сгенерированный от прокладки, поля слева и справа от ряда-1/2 gutternuggets.capable/post/684490…лень рисовать)

spanа такжеoffsetто есть总宽度/24*100%*具体数值.

Многие vuers, как правило, используют для разработки метод написания vue-template, который больше соответствует традиционным привычкам Html/css/js, но vue также предоставляет функцию рендеринга и поддерживает jsx.Vant использует этот метод написания, который может иметь более сильный DOM детали контроль способность.

    // Row.js
  render() {
    const { align, justify } = this;
    const flex = this.type === 'flex';
    const margin = `-${Number(this.gutter) / 2}px`;
    // 计算样式:marginLeft和maginRight
    const style = this.gutter ? { marginLeft: margin, marginRight: margin } : {};

    return (
    // 动态tag
      <this.tag 
        style={style}
        // 通过createBem将css类名统一在一个前缀下
        class={bem({
          flex,
          [`align-${align}`]: flex && align,
          [`justify-${justify}`]: flex && justify
        })}
        // 监听click事件
        onClick={this.onClick}
      >
        {this.slots()} // 放置一个slot,这样Col就被包裹在Row里,可以在Col中通过this.$parent获取Row的data属性
      </this.tag>
    );
  }
  
  // Col.js
 computed: {
    gutter() {
      return (this.$parent && Number(this.$parent.gutter)) || 0; // 获取父级gutter,仅支持一级父类
    },

    style() {
      const padding = `${this.gutter / 2}px`;
      return this.gutter ? { paddingLeft: padding, paddingRight: padding } : {};
    }
  },
  render() {
    const { span, offset } = this;
    return (
      <this.tag
        style={this.style}
        class={bem({ [span]: span, [`offset-${offset}`]: offset })}
        onClick={this.onClick}
      >
        {this.slots()}
      </this.tag>
    );
  }

(3) Написание CSS

вант усыновилlessРазвитие, с указанным вышеcreateBemМетод значительно повышает эффективность разработки. Возьмите класс Rol выше в качестве примера:

  class={bem({ [span]: span, [`offset-${offset}`]: offset })}

Когда span=1,offset=2 , т.е.

  class={bem({ 1: 1, [`offset-2`]: 2 })}
  // 转换结果
  class="van-col--1 van-col--offset-2"

используя меньшециклдля динамической генерации стилей css

.generate-col(24);
.generate-col(@n, @i: 1) when (@i =< @n) {
  .van-col--@{i} { width: @i * 100% / 24; } // 24列栅格
  .van-col--offset-@{i} { margin-left: @i * 100% / 24; }
  .generate-col(@n, (@i + 1));
}

резюме

В этом документе кратко представлена ​​функция класса VANT UTILS, два компонента Row и COL, которые затем выбирают другие компоненты по мере необходимости. Используйте только личное обучение, чтобы поделиться, если есть несчастье, добро пожаловать на исправление ^^!