Hello everyone, I’m Lin Sanxin, oh, we do Vue must be in touch with a lot of UI libraries, one of the most used must be ElementUI! After all this time, don’t you want to know how he pulled it off? Just like you get along with a girl for a long time, you like her, you will naturally want to know a lot of things about her, then you don’t take the initiative to ask, how can she tell you?? Take a look at the ElementUI source code. Hee hee!

download

Gayhub Download (Source version)

Clone by GayHub

Copy (release) directly in your own project’s node_module

Yeah, I copied it right here, ready made

Directory analysis

Since I mainly read the source code in the package directory, I can actually learn any version, which is the release VERSION I used

Element - UI ├─ lib// Directory of packaged files├ ─ ─ packages// Component source directory (main study)├ ─ ─ alert// Specific component source package├ ─ ─ the SRC// Vue component package├ ─ ─ index. Js// Import file├ ─ ─ the SRC// Source directory├ ─ ─ directive// Implement wheel optimization and mouse click optimization├ ─ ─ the locale// i18n internationalization├ ─ ─ mixins// Vue mixer├ ─ ─ the transition// Style transition effects├ ─ ─ utils// Utility class package├ ─ ─ index. Js// source code entry file├ ─ ─ types// typescript package├ ─ ─ package. Json// NPM package core file
Copy the code

ElementUI document view

Component analysis

El-row wraps el-Col to achieve the effect of “row” and “column”. All the guys used it. They all got it.

The parameters of the el – row

The parameters of the el – col

Rush!!!!!! Do it!!

Directory structures,

I used a scaffolding I built to learn ElementUI source code. You can choose to build your own scaffolding, or use Vuecli to learn directly. Nuggets have a lot of “scaffolding” articles, you can find it, style words can be directly source copy. We’re only talking about JavaScript here

El-row mimics source code analysis

// file row/SRC/row.js
export default {
  name: 'CRow'.props: {
    gutter: { // Grid spacing
      type: Number.default: 0,},type: String.// Layout mode, flex optional, available in modern browsers
    justify: { // Horizontal arrangement in flex layout
      type: String.default: 'start',},align: { // Vertical arrangement in flex layout
      type: String.default: 'top',},tag: { // Custom element tags (involving createElement in vue's render function)
      type: String.default: 'div'.// The default is the div tag}},created() {
    console.log(this.$slots, this.$slots.default.length, 'slots') // If you want to see what $slot looks like, you can ignore it
  },
  computed: {
    getRowGutterStyle() { // calculate left/right margin with gutter
      if (this.gutter === 0) return ' '
      const value = this.gutter / 2 + 'px'
      return {
        marginLeft: value,
        marginRight: value,
      }
    },
    getRowFlexClass() { // Calculate the class of the Flex layout
      return[{'c-row-flex': this.type === 'flex' },
        this.justify === 'start' ? ' ' : `is-justify-The ${this.justify}`.this.align === 'top' ? ' ' : `is-align-The ${this.align}`,]}},render: function (createElement) { // Render the DOM function
    return createElement(this.tag, { // Create dom with createElement
      class: [
        'c-row',
        { 'c-row-flex': this.type === 'flex' },
        this.justify === 'start' ? ' ' : `is-justify-The ${this.justify}`.this.align === 'top' ? ' ' : `is-align-The ${this.align}`,].style: this.getRowGutterStyle
    }, this.$slots.default)
  },
}

// file row/index.js
import CRow from './src/Row.js'

CRow.install = function (Vue) { // Why is there an install method
    Vue.component(CRow.name, CRow) // Globally register components
}

export default CRow
Copy the code

El-col mimics source code analysis

// file col/SRC/col.js
export default {
  name: 'CCol'.props: {
    span: { // The number of columns occupied by the grid
      type: Number.default: 24,},offset: { // The number of spacing cells to the left of the grid
      type: Number.default: 0,},// SCSS's for loop function + media query can achieve the following effects
    xs: [Number.Object].// <768px responsive raster number or raster attribute object
    sm: [Number.Object].// ≥768px responsive raster number or raster attribute object
    md: [Number.Object].// ≥992px responsive raster number or raster attribute object
    lg: [Number.Object].// ≥1200px responsive raster number or raster attribute object
    xl: [Number.Object].// ≥1920px responsive grid or raster attribute object
    tag: { // Custom element tags (involving createElement in vue's render function)
      type: String.default: 'div' // The default is the div tag}},computed: {
    getColGutterStyle() {
      const gutter = this.$parent.gutter // Since el-Row is wrapped in el-row, to calculate the gutter padding from the outer el-row to calculate the spacing between each grid
      if (this.gutter === 0) return ' '
      const value = gutter / 2 + 'px'
      return {
        paddingLeft: value,
        paddingRight: value,
      }
    },
    getColOffsetClass() { // Calculate the left spacing of each grid according to offset
      if (this.offset === 0) return ' '
      return 'c-col-offset-' + this.offset
    },
    getColMediaClass() { // Calculate the responsive class
      let sizeArr = [];
      ['xs'.'xm'.'md'.'lg'.'xl'].forEach((size) = > {
        if (typeof this[size] === 'number') { // Determine which responsive width is passed in and calculate the class name, which is stored in the array
          sizeArr.push(`c-col-${size}-The ${this[size]}`)}})return sizeArr
    },
  },
  render: function (createElement) { // The render function renders dom
    return createElement(this.tag, { The createElement function creates the DOM
      class: ['c-col'.'c-col-' + this.span, this.getColOffsetClass, ... this.getColMediaClass],// Dynamic class binding
      style: this.getColGutterStyle // Dynamic style binding
    }, this.$slots.default) // Default slot}},// file col/index.js
import CCol from './src/Col.js'

CCol.install = function (Vue) { // Why is there an install method
    Vue.component(CCol.name, CCol) // Globally register components
}

export default CCol
Copy the code
// style / row.scssFile // generate c-col-1To the c - col24
@for $i from 1 through 24 {
    .c-col-# {$i} {
        width: 100%/24* $i; }} // Generate c-col-offset-1To the c - col - offset -24
@for $i from 1 through 24 {
    .c-col-offset-# {$i} {
        margin-left: 100%/24* $i; }}.c-col {
    display: inline-block;
    box-sizing: border-box;
}

@media screen and (max-width: 767px) {
    @for $i from 1 through 24 {
        .c-col-xs-# {$i} {
            width: 100%/24* $i; }}}@media screen and (min-width: 768px) {
    @for $i from 1 through 24 {
        .c-col-sm-# {$i} {
            width: 100%/24* $i; }}}@media screen and (min-width: 992px) {
    @for $i from 1 through 24 {
        .c-col-md-# {$i} {
            width: 100%/24* $i; }}}@media screen and (min-width: 1200px) {
    @for $i from 1 through 24 {
        .c-col-lg-# {$i} {
            width: 100%/24* $i; }}}@media screen and (min-width: 1920px) {
    @for $i from 1 through 24 {
        .c-col-xl-# {$i} {
            width: 100%/24* $i; }}}Copy the code

Using the component

// import from main.js
import '.. /package/styles/index.scss' // Introduce the overall style
import { CButton, CButtonGroup, CRow, CCol, CContainer, 
    CHeader, CFooter, CAside, CMain, CBacktop, CCard } from '.. /package/index' // Destruct the introduction
Vue.use(CButton)
Vue.use(CButtonGroup)
Vue.use(CRow) // Is that why you export an install method
Vue.use(CCol) // Is that why you export an install method
Vue.use(CContainer)
Vue.use(CHeader)
Vue.use(CFooter)
Vue.use(CAside)
Vue.use(CMain)
Vue.use(CBacktop)
Vue.use(CCard)
Copy the code

Then it can be used globally

<template>
    <div class="demo-layout">
      <c-row :gutter="20">
        <c-col :span="24"
          ><div class="item">{{ doubleNum }}</div></c-col
        >
      </c-row>
      <c-row :gutter="20">
        <c-col :span="12"> <div class="item">hhh</div></c-col>
        <c-col :span="12"><div class="item">hhh</div></c-col>
      </c-row>
      <c-row :gutter="20">
        <c-col :span="8"><div class="item">hhh</div></c-col>
        <c-col :span="8"><div class="item">hhh</div></c-col>
        <c-col :span="8"><div class="item">hhh</div></c-col>
      </c-row>
      <c-row :gutter="20">
        <c-col :span="6"><div class="item">hhh</div></c-col>
        <c-col :span="6"><div class="item">hhh</div></c-col>
        <c-col :span="6"><div class="item">hhh</div></c-col>
        <c-col :span="6"><div class="item">hhh</div></c-col>
      </c-row>
      <c-row :gutter="20">
        <c-col :span="6"><div class="item">hhh</div></c-col>
        <c-col :span="6" :offset="12"><div class="item">hhh</div></c-col>
      </c-row>
      <c-row type="flex" justify="end">
        <c-col :span="6"><div class="item">hhh</div></c-col>
        <c-col :span="6"><div class="item">hhh</div></c-col>
      </c-row>
      <c-row type="flex" justify="space-around">
        <c-col :span="6"><div class="item">hhh</div></c-col>
        <c-col :span="6"><div class="item">hhh</div></c-col>
      </c-row>
      <c-row type="flex" justify="space-between">
        <c-col :span="6"><div class="item">hhh</div></c-col>
        <c-col :span="6"><div class="item">hhh</div></c-col>
      </c-row>
      <c-row :gutter="10">
        <c-col :xs="8" :sm="6" :md="1" :lg="6" :xl="1"><div class="item">hhh</div></c-col>
        <c-col :xs="4" :sm="6" :md="1" :lg="6" :xl="11"><div class="item">hhh</div></c-col>
        <c-col :xs="4" :sm="6" :md="12" :lg="11" :xl="11"><div class="item">hhh</div></c-col>
        <c-col :xs="8" :sm="6" :md="10" :lg="1" :xl="1"><div class="item">hhh</div></c-col>
      </c-row>
      <c-row :gutter="10" tag="header">
        <c-col tag="p" :xs="8" :sm="6" :md="1" :lg="6" :xl="1"><div class="item">hhh</div></c-col>
        <c-col :xs="4" :sm="6" :md="1" :lg="6" :xl="11"><div class="item">hhh</div></c-col>
        <c-col :xs="4" :sm="6" :md="12" :lg="11" :xl="11"><div class="item">hhh</div></c-col>
        <c-col :xs="8" :sm="6" :md="10" :lg="1" :xl="1"><div class="item">hhh</div></c-col>
      </c-row>
    </div>
</template>
Copy the code

Why export an install method, and what does it have to do with Vue’s use method

Vue. Use (options) : install (options); install (options) : install (options); You must make sure that the Options object you export contains the install method

Learn to summarize

The code is a knock, but can not knock so past bar, must learn something, otherwise you knock the code is useless! Here are some of the new things I learned (new to me) while mimicking ElementUI’s Layout component

  • scssIn the@forUse of methods
  • The child component retrieves data from the parent component usingthis.$parentTo obtain
  • Vue.use(options)Will performoptionstheinstallfunction
  • $slotsIs an object,keyforslot-name.valueIs the corresponding element (array), defaultkeyisdefault