preface

There are too many mature, good vuers for wheels, and over time you can feel like you only know how to run with wheels, so this article will look at how a good UI component can be implemented instead of the messy business requirements. Nowadays, mobile e-commerce development is very common, and Vant can meet most usage scenarios. Therefore, vUE + JSX + typescript + less are the technology stacks involved in this study.

Directory description

SRC/utils/ / utility class style/ // global style row/ // component code index.js index.lesstest// / test code demo/ // example col/.....test// / test class types/ //typescript declaration filesCopy the code

Preparation: create creates the class function

CreateNamespace receives the parameter name and returns createComponent, createBEM, createI18N. Comonent is a comonent instance, and CSS helper functions are called. And multilingual tools.

// utils/create/index.ts

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

Copy the code

(1) the createComponent

The createComponent function generates a VUE component object based on name, doing some presetting of the component in the process.


export function createComponent(name: string) {
  return function<Props = DefaultProps.Events = {}, Slots = {}> (
  // SFC: Single file Components, supporting object and functional components
    sfc: VantComponentOptions | FunctionComponent
  ): TsxComponent<Props, Events, Slots> {
  
    // Functional components are converted to object components
    if (typeof sfc === 'function') {
      sfc = transformFunctionComponent(sfc); 
    }
   
    if(! sfc.functional) { sfc.mixins = sfc.mixins || []; sfc.mixins.push(SlotsMixin);// Push a mixin compatible with a lower version of scopedSlots
    }

    sfc.name = name;
    sfc.install = install; // Install calls the Vue.component() method to register the component

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

Copy the code

The object component VantComponentOptions adds two properties to the Vue component: functional and install methods

export interface VantComponentOptions extends ComponentOptions<Vue> {
  functional? :boolean; // Used for functional component judgment aboveinstall? :(Vue: VueConstructor) = > void; // The install method for the plug-in
}
Copy the code

(2) createBEM

CreateBEM function createBEM is a method that generates a CSS class name based on name, separating the class’s ELEMENT and name with “__” and the class’s MODS with “–“, so that all style class names are prefixed as shown in the following example.

/** * 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' */
Copy the code

B () takes two arguments: EL and MOds

export function createBEM(name: string) {
  return function(el? : Mods, mods? : Mods) :Mods {
    // Only string el is processed, other formats are treated as MOds
    if (el && typeofel ! = ='string') {
      mods = el;
      el = ' ';
    }
    el = join(name, el, ELEMENT);

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

Copy the code

(3) the createI18N

Multilingual processing, I won’t go into that

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; }; }Copy the code

Van components — Row and Col

Call the creaeNamespace function first

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

The component’s configuration items are then passed to createComponent


export defaultcreateComponent({ props: { ... }, methods: { ... }, render() { ... ) ; }Copy the code

The specific props and Events can be referenced to the official API.

Here we focus on Row and Col render function, divided into component implementation, Html DOM writing, CSS writing three parts.

(1) Component implementation

Vant breaks the layout into 24 columns, using the SPAN attribute on Col to control the ratio, offset to control the offset, and gutter to control the spacing on the Row. In order to offset the excess padding, run the Col left and right padding 1/2 gutter on the Row for the margin-1/2 gutter, as shown in the figure below. , I don’t want to draw.)

Span and offset are the total width divided by 24*100%* specific values.

(2) Html DOM writing method

Many Vuers tend to use vue-template writing, which is more in line with traditional Html/ CSS/JS conventions, but Vue also provides render functions and JSX support, which is vant’s way of writing and gives it more control over DOM details.

    // Row.js
  render() {
    const { align, justify } = this;
    const flex = this.type === 'flex';
    const margin = `-${Number(this.gutter) / 2}px`; MarginLeft and maginRight const style = this.gutter? { marginLeft: margin, marginRight: margin } : {};returnClass ={bem({flex, [' align- '); class={bem({flex, [' align-)${align}`]: flex && align,
          [`justify-${justify}']: flex && justify})} // listen for the click event onClick={this.onclick} > {this.slots()} // place a slot so that Col is wrapped in Row and this can be used within Col.$parentGet the Row's data attribute </this.tag>); } // Col.js computed: {gutter() {
      return (this.$parent && Number(this.$parent.gutter)) || 0; $gutter = $gutter {$gutter = $gutter}, $gutter = $gutter}style() {
      const padding = `${this.gutter / 2}px`;
      returnthis.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>
    );
  }
Copy the code

(3) CSS writing method

Vant uses less for development, which in conjunction with the createBem method mentioned above greatly improves development efficiency. For example, class for Rol:

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

When the span = 1, offset = 2, namely

  class={bem({ 1: 1[`offset-2`] :2 })}
  // Convert the result
  class="van-col--1 van-col--offset-2"
Copy the code

Use less loops to dynamically generate CSS styles

.generate-col(24);
.generate-col(@n.@i: 1) when (@i= <@n) {
  .van-col--@{i} { width: @i * 100% / 24; } // 24 column grid
  .van-col--offset-@{i} { margin-left: @i * 100% / 24; }
  .generate-col(@n, (@i + 1));
}
Copy the code

summary

This article briefly introduces vant’s Utils class functions, namely Row and Col components, and then selects other components for analysis as appropriate. Only for personal learning to share the use, if there are mistakes, welcome to correct!